diff --git a/Corona-Warn-App/schemas/de.rki.coronawarnapp.submission.data.tekhistory.internal.TEKHistoryDatabase/1.json b/Corona-Warn-App/schemas/de.rki.coronawarnapp.submission.data.tekhistory.internal.TEKHistoryDatabase/1.json new file mode 100644 index 0000000000000000000000000000000000000000..885c44dfb880c4ec73741c3aa6d94a3a6730f37d --- /dev/null +++ b/Corona-Warn-App/schemas/de.rki.coronawarnapp.submission.data.tekhistory.internal.TEKHistoryDatabase/1.json @@ -0,0 +1,82 @@ +{ + "formatVersion": 1, + "database": { + "version": 1, + "identityHash": "47e1148ca2a3e750269b5b921bc36d7a", + "entities": [ + { + "tableName": "tek_history", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `batchId` TEXT NOT NULL, `obtainedAt` TEXT NOT NULL, `keyData` BLOB NOT NULL, `rollingStartIntervalNumber` INTEGER NOT NULL, `transmissionRiskLevel` INTEGER NOT NULL, `rollingPeriod` INTEGER NOT NULL, `reportType` INTEGER NOT NULL, `daysSinceOnsetOfSymptoms` INTEGER NOT NULL, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "batchId", + "columnName": "batchId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "obtainedAt", + "columnName": "obtainedAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "persistedTEK.keyData", + "columnName": "keyData", + "affinity": "BLOB", + "notNull": true + }, + { + "fieldPath": "persistedTEK.rollingStartIntervalNumber", + "columnName": "rollingStartIntervalNumber", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "persistedTEK.transmissionRiskLevel", + "columnName": "transmissionRiskLevel", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "persistedTEK.rollingPeriod", + "columnName": "rollingPeriod", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "persistedTEK.reportType", + "columnName": "reportType", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "persistedTEK.daysSinceOnsetOfSymptoms", + "columnName": "daysSinceOnsetOfSymptoms", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '47e1148ca2a3e750269b5b921bc36d7a')" + ] + } +} \ No newline at end of file diff --git a/Corona-Warn-App/schemas/de.rki.coronawarnapp.submission.tekhistory.storage.internal.TEKHistoryDatabase/1.json b/Corona-Warn-App/schemas/de.rki.coronawarnapp.submission.tekhistory.storage.internal.TEKHistoryDatabase/1.json new file mode 100644 index 0000000000000000000000000000000000000000..b4a40ea2dd7eeecf5f59ed9b011f230924664640 --- /dev/null +++ b/Corona-Warn-App/schemas/de.rki.coronawarnapp.submission.tekhistory.storage.internal.TEKHistoryDatabase/1.json @@ -0,0 +1,82 @@ +{ + "formatVersion": 1, + "database": { + "version": 1, + "identityHash": "d63edaaa672685ab593a15e9deb02210", + "entities": [ + { + "tableName": "tek_history", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `batchId` TEXT NOT NULL, `obtainedAt` TEXT NOT NULL, `keyData` BLOB NOT NULL, `rollingStartIntervalNumber` INTEGER NOT NULL, `transmissionRiskLevel` INTEGER NOT NULL, `rollingPeriod` INTEGER NOT NULL, `reportType` INTEGER NOT NULL, `daysSinceOnsetOfSymptoms` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "batchId", + "columnName": "batchId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "obtainedAt", + "columnName": "obtainedAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "persistedTEK.keyData", + "columnName": "keyData", + "affinity": "BLOB", + "notNull": true + }, + { + "fieldPath": "persistedTEK.rollingStartIntervalNumber", + "columnName": "rollingStartIntervalNumber", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "persistedTEK.transmissionRiskLevel", + "columnName": "transmissionRiskLevel", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "persistedTEK.rollingPeriod", + "columnName": "rollingPeriod", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "persistedTEK.reportType", + "columnName": "reportType", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "persistedTEK.daysSinceOnsetOfSymptoms", + "columnName": "daysSinceOnsetOfSymptoms", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'd63edaaa672685ab593a15e9deb02210')" + ] + } +} \ No newline at end of file diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/nearby/InternalExposureNotificationPermissionHelperTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/nearby/InternalExposureNotificationPermissionHelperTest.kt deleted file mode 100644 index a096f1c4b62e31b5fb21e8a0d2a9b728e2c37a1b..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/nearby/InternalExposureNotificationPermissionHelperTest.kt +++ /dev/null @@ -1,161 +0,0 @@ -package de.rki.coronawarnapp.nearby - -import androidx.fragment.app.Fragment -import androidx.fragment.app.testing.FragmentScenario -import androidx.fragment.app.testing.launchFragmentInContainer -import androidx.localbroadcastmanager.content.LocalBroadcastManager -import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.google.android.gms.common.api.ApiException -import com.google.android.gms.common.api.Status -import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey -import de.rki.coronawarnapp.CoronaWarnApplication -import de.rki.coronawarnapp.TestFragment -import io.mockk.coEvery -import io.mockk.every -import io.mockk.mockk -import io.mockk.mockkObject -import io.mockk.unmockkAll -import org.hamcrest.CoreMatchers.`is` -import org.hamcrest.MatcherAssert.assertThat -import org.junit.After -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith - -/** - * InternalExposureNotificationPermissionHelper test. - */ -@RunWith(AndroidJUnit4::class) -class InternalExposureNotificationPermissionHelperTest { - private lateinit var scenario: FragmentScenario<TestFragment> - private var fail = false - private var startSuccess = false - private var sharingSuccess = false - private val callback = object : InternalExposureNotificationPermissionHelper.Callback { - override fun onFailure(exception: Exception?) { - fail = true - } - - override fun onStartPermissionGranted() { - startSuccess = true - } - - override fun onKeySharePermissionGranted(keys: List<TemporaryExposureKey>) { - sharingSuccess = true - } - } - - /** - * Launch test fragment, required for view lifecycle owner. - * - * @see [InternalExposureNotificationPermissionHelper] - * @see [Fragment.getViewLifecycleOwner] - */ - @Before - fun setUp() { - fail = false - startSuccess = false - sharingSuccess = false - mockkObject(InternalExposureNotificationClient) - scenario = launchFragmentInContainer<TestFragment>() - } - - /** - * Test tracing permission request assuming EN Client is enabled. - */ - @Test - fun testRequestPermissionToStartTracingENIsEnabled() { - coEvery { InternalExposureNotificationClient.asyncIsEnabled() } returns true - scenario.onFragment { - val helper = InternalExposureNotificationPermissionHelper(it, callback) - helper.requestPermissionToStartTracing() - } - assertThat(fail, `is`(false)) - assertThat(startSuccess, `is`(true)) - } - - /** - * Test tracing permission request assuming EN Client is disabled. - */ - @Test - fun testRequestPermissionToStartTracingENIsNotEnabled() { - coEvery { InternalExposureNotificationClient.asyncIsEnabled() } returns false - // not every device/emulator has access to exposure notifications Google API: - coEvery { InternalExposureNotificationClient.asyncStart() } returns mockk() - - scenario.onFragment { - val helper = InternalExposureNotificationPermissionHelper(it, callback) - helper.requestPermissionToStartTracing() - } - assertThat(fail, `is`(false)) - assertThat(startSuccess, `is`(true)) - } - - /** - * Test tracing permission request exception handling. - */ - @Test - fun testRequestPermissionToStartTracingExceptionHandling() { - coEvery { InternalExposureNotificationClient.asyncIsEnabled() } returns false - - // not every device/emulator has access to exposure notifications Google API: - coEvery { InternalExposureNotificationClient.asyncStart() } throws mockApiException(Status.RESULT_CANCELED) - - scenario.onFragment { - val helper = InternalExposureNotificationPermissionHelper(it, callback) - helper.requestPermissionToStartTracing() - } - assertThat(fail, `is`(true)) - assertThat(startSuccess, `is`(false)) - } - - /** - * Test keys sharing permission request. - */ - @Test - fun testRequestPermissionToShareKeys() { - // not every device/emulator has access to exposure notifications Google API: - coEvery { InternalExposureNotificationClient.asyncGetTemporaryExposureKeyHistory() } returns mockk() - - scenario.onFragment { - val helper = InternalExposureNotificationPermissionHelper(it, callback) - helper.requestPermissionToShareKeys() - } - assertThat(fail, `is`(false)) - assertThat(sharingSuccess, `is`(true)) - } - - /** - * Test keys sharing permission request exception handling. - */ - @Test - fun testRequestPermissionToShareKeysException() { - // not every device/emulator has access to exposure notifications Google API: - coEvery { - InternalExposureNotificationClient.asyncGetTemporaryExposureKeyHistory() - } throws mockApiException(Status.RESULT_CANCELED) - - scenario.onFragment { - val helper = InternalExposureNotificationPermissionHelper(it, callback) - helper.requestPermissionToShareKeys() - } - assertThat(fail, `is`(true)) - assertThat(sharingSuccess, `is`(false)) - } - - private fun mockApiException(status: Status): ApiException { - mockkObject(LocalBroadcastManager.getInstance(CoronaWarnApplication.getAppContext())) - val exception = ApiException(status) - // don't need a dialog for exception - every { - LocalBroadcastManager.getInstance(CoronaWarnApplication.getAppContext()) - .sendBroadcast(any()) - } returns true - return exception - } - - @After - fun cleanUp() { - unmockkAll() - } -} diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/submission/SubmissionSettingsTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/submission/SubmissionSettingsTest.kt deleted file mode 100644 index fa26c51fb8bd4e0b5341722e53909388e8155a11..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/submission/SubmissionSettingsTest.kt +++ /dev/null @@ -1,24 +0,0 @@ -package de.rki.coronawarnapp.ui.submission - -import android.content.Context -import androidx.test.core.app.ApplicationProvider -import de.rki.coronawarnapp.submission.SubmissionSettings -import io.kotest.matchers.shouldBe -import org.junit.Test -import org.junit.runner.RunWith -import org.junit.runners.JUnit4 - -@RunWith(JUnit4::class) -class SubmissionSettingsTest { - - private val appContext: Context - get() = ApplicationProvider.getApplicationContext() - - @Test - fun consentIsPersisted() { - val settings = SubmissionSettings(appContext) - settings.hasGivenConsent.value shouldBe false - settings.hasGivenConsent.update { true } - settings.hasGivenConsent.value shouldBe true - } -} diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/worker/DiagnosisKeyRetrievalOneTimeWorkerTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/worker/DiagnosisKeyRetrievalOneTimeWorkerTest.kt deleted file mode 100644 index 92c26746805454187a1ec0cca583ff671e301753..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/worker/DiagnosisKeyRetrievalOneTimeWorkerTest.kt +++ /dev/null @@ -1,71 +0,0 @@ -package de.rki.coronawarnapp.worker - -import android.content.Context -import androidx.test.core.app.ApplicationProvider -import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.work.ListenableWorker - -import androidx.work.testing.TestListenableWorkerBuilder -import de.rki.coronawarnapp.transaction.RetrieveDiagnosisKeysTransaction -import io.mockk.Runs -import io.mockk.coEvery -import io.mockk.just -import io.mockk.mockkObject -import org.hamcrest.CoreMatchers.`is` -import org.hamcrest.MatcherAssert.assertThat -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith - -/** - * DiagnosisKeyRetrievalOneTimeWorker test. - */ -@RunWith(AndroidJUnit4::class) -class DiagnosisKeyRetrievalOneTimeWorkerTest { - private lateinit var context: Context - private lateinit var worker: ListenableWorker - - @Before - fun setUp() { - context = ApplicationProvider.getApplicationContext() - mockkObject(RetrieveDiagnosisKeysTransaction) - } - - /** - * Test worker result = [ListenableWorker.Result.success] - */ - @Test - fun testDiagnosisKeyRetrievalOneTimeWorkerSuccess() { - worker = - TestListenableWorkerBuilder<DiagnosisKeyRetrievalOneTimeWorker>(context).build() - coEvery { RetrieveDiagnosisKeysTransaction.start() } just Runs - val result = worker.startWork().get() - assertThat(result, `is`(ListenableWorker.Result.success())) - } - - /** - * Test worker result = [ListenableWorker.Result.retry] - */ - @Test - fun testDiagnosisKeyRetrievalOneTimeWorkerRetry() { - worker = - TestListenableWorkerBuilder<DiagnosisKeyRetrievalOneTimeWorker>(context).build() - coEvery { RetrieveDiagnosisKeysTransaction.start() } throws Exception("test exception") - val result = worker.startWork().get() - assertThat(result, `is`(ListenableWorker.Result.retry())) - } - - /** - * Test worker result = [ListenableWorker.Result.failure] - * Check [BackgroundConstants.WORKER_RETRY_COUNT_THRESHOLD] for proper attempt count. - * - * @see [BackgroundConstants.WORKER_RETRY_COUNT_THRESHOLD] - */ - @Test - fun testDiagnosisKeyRetrievalOneTimeWorkerFailed() { - worker = - TestListenableWorkerBuilder<DiagnosisKeyRetrievalOneTimeWorker>(context).setRunAttemptCount(5).build() - val result = worker.startWork().get() - assertThat(result, `is`(ListenableWorker.Result.failure())) - } -} diff --git a/Corona-Warn-App/src/androidTest/java/testhelpers/FragmentTestModuleRegistrar.kt b/Corona-Warn-App/src/androidTest/java/testhelpers/FragmentTestModuleRegistrar.kt index 46b897285c2413ecb3d8d3ab422dabfb5f3e12a3..2e7625e1fc676f8106f7e15034a670ff387547e9 100644 --- a/Corona-Warn-App/src/androidTest/java/testhelpers/FragmentTestModuleRegistrar.kt +++ b/Corona-Warn-App/src/androidTest/java/testhelpers/FragmentTestModuleRegistrar.kt @@ -41,7 +41,7 @@ import de.rki.coronawarnapp.ui.submission.SubmissionTestResultTestModule SubmissionSymptomCalendarFragmentTestModule::class, SubmissionContactTestModule::class, SubmissionDoneTestModule::class, - SubmissionQRScanFragmentModule::class, + SubmissionQRScanFragmentModule::class ] ) class FragmentTestModuleRegistrar diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/api/ui/TestForAPIFragment.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/api/ui/TestForAPIFragment.kt index ec7778acfa0c13c4117156c77776a7c9c6f7d7c0..c8063ec9aa534c0ec732621561cbfdbb5ab68779 100644 --- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/api/ui/TestForAPIFragment.kt +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/api/ui/TestForAPIFragment.kt @@ -17,7 +17,6 @@ import androidx.recyclerview.widget.RecyclerView import androidx.viewpager2.widget.ViewPager2 import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey -import com.google.android.material.snackbar.Snackbar import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.google.protobuf.ByteString @@ -33,7 +32,6 @@ import de.rki.coronawarnapp.exception.ExceptionCategory.INTERNAL import de.rki.coronawarnapp.exception.TransactionException import de.rki.coronawarnapp.exception.reporting.report import de.rki.coronawarnapp.nearby.ENFClient -import de.rki.coronawarnapp.nearby.InternalExposureNotificationPermissionHelper import de.rki.coronawarnapp.receiver.ExposureStateUpdateReceiver import de.rki.coronawarnapp.risk.TimeVariables import de.rki.coronawarnapp.risk.storage.RiskLevelStorage @@ -41,6 +39,7 @@ import de.rki.coronawarnapp.server.protocols.AppleLegacyKeyExchange import de.rki.coronawarnapp.sharing.ExposureSharingService import de.rki.coronawarnapp.storage.AppDatabase import de.rki.coronawarnapp.storage.tracing.TracingIntervalRepository +import de.rki.coronawarnapp.submission.data.tekhistory.TEKHistoryUpdater import de.rki.coronawarnapp.test.menu.ui.TestMenuItem import de.rki.coronawarnapp.util.KeyFileHelper import de.rki.coronawarnapp.util.di.AutoInject @@ -61,11 +60,11 @@ import java.util.UUID import javax.inject.Inject @SuppressWarnings("TooManyFunctions", "LongMethod") -class TestForAPIFragment : Fragment(R.layout.fragment_test_for_a_p_i), - InternalExposureNotificationPermissionHelper.Callback, AutoInject { +class TestForAPIFragment : Fragment(R.layout.fragment_test_for_a_p_i), AutoInject { @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory @Inject lateinit var enfClient: ENFClient + @Inject lateinit var tekHistoryUpdater: TEKHistoryUpdater // TODO: This is ugly, remove when refactoring the fragment @Inject lateinit var appConfigProvider: AppConfigProvider @@ -94,8 +93,6 @@ class TestForAPIFragment : Fragment(R.layout.fragment_test_for_a_p_i), private var otherExposureKey: AppleLegacyKeyExchange.Key? = null private var otherExposureKeyList = mutableListOf<AppleLegacyKeyExchange.Key>() - private lateinit var internalExposureNotificationPermissionHelper: InternalExposureNotificationPermissionHelper - private lateinit var qrPager: ViewPager2 private lateinit var qrPagerAdapter: RecyclerView.Adapter<QRPagerAdapter.QRViewHolder> @@ -106,9 +103,6 @@ class TestForAPIFragment : Fragment(R.layout.fragment_test_for_a_p_i), override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - internalExposureNotificationPermissionHelper = - InternalExposureNotificationPermissionHelper(this, this) - qrPager = binding.qrCodeViewpager qrPagerAdapter = QRPagerAdapter() qrPager.adapter = qrPagerAdapter @@ -119,9 +113,15 @@ class TestForAPIFragment : Fragment(R.layout.fragment_test_for_a_p_i), "Google Play Services version: ${state.version}" } + vm.infoEvent.observe2(this) { showToast(it) } + vm.errorEvents.observe2(this) { showToast(it.toString()) } + vm.permissionRequiredEvent.observe2(this) { permissionRequest -> + permissionRequest.invoke(requireActivity()) + } + // Test action card binding.apply { - buttonApiTestStart.setOnClickListener { start() } + buttonApiTestStart.setOnClickListener { vm.requestTracingPermission() } buttonApiGetExposureKeys.setOnClickListener { getExposureKeys() } buttonApiScanQrCode.setOnClickListener { @@ -137,7 +137,29 @@ class TestForAPIFragment : Fragment(R.layout.fragment_test_for_a_p_i), buttonApiSubmitKeys.setOnClickListener { vm.launch { try { - internalExposureNotificationPermissionHelper.requestPermissionToShareKeys() + tekHistoryUpdater.callback = object : TEKHistoryUpdater.Callback { + override fun onTEKAvailable(teks: List<TemporaryExposureKey>) { + launch(context = Dispatchers.Main) { + myExposureKeysJSON = keysToJson(teks) + myExposureKeys = teks + qrPagerAdapter.notifyDataSetChanged() + } + } + + override fun onPermissionDeclined() { + launch(context = Dispatchers.Main) { + showToast("Permission declined") + } + } + + override fun onError(error: Throwable) { + launch(context = Dispatchers.Main) { + showToast(error.toString()) + } + } + } + + updateKeysDisplay() // SubmitDiagnosisKeysTransaction.start("123") withContext(Dispatchers.Main) { @@ -221,13 +243,9 @@ class TestForAPIFragment : Fragment(R.layout.fragment_test_for_a_p_i), } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - this.internalExposureNotificationPermissionHelper.onResolutionComplete( - requestCode, - resultCode - ) + vm.handleActivityResult(requestCode, resultCode, data) - val result: IntentResult? = - IntentIntegrator.parseActivityResult(requestCode, resultCode, data) + val result: IntentResult? = IntentIntegrator.parseActivityResult(requestCode, resultCode, data) if (result != null) { if (result.contents == null) { showToast("Cancelled") @@ -239,12 +257,10 @@ class TestForAPIFragment : Fragment(R.layout.fragment_test_for_a_p_i), } } - private fun start() { - this.internalExposureNotificationPermissionHelper.requestPermissionToStartTracing() - } - private fun getExposureKeys() { - this.internalExposureNotificationPermissionHelper.requestPermissionToShareKeys() + tekHistoryUpdater.updateTEKHistoryOrRequestPermission { permissionRequest -> + permissionRequest(requireActivity()) + } } private fun shareMyKeys() { @@ -337,26 +353,6 @@ class TestForAPIFragment : Fragment(R.layout.fragment_test_for_a_p_i), Toast.makeText(context, message, Toast.LENGTH_LONG).show() } - private fun showSnackBar(message: String) { - Snackbar.make(requireView(), message, Snackbar.LENGTH_LONG).show() - } - - override fun onFailure(exception: Exception?) { - showToast(exception?.localizedMessage ?: "Error during EN start") - } - - override fun onStartPermissionGranted() { - showToast("Started EN Tracing") - } - - override fun onKeySharePermissionGranted(keys: List<TemporaryExposureKey>) { - myExposureKeysJSON = keysToJson(keys) - myExposureKeys = keys - qrPagerAdapter.notifyDataSetChanged() - - updateKeysDisplay() - } - private inner class QRPagerAdapter : RecyclerView.Adapter<QRPagerAdapter.QRViewHolder>() { diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/api/ui/TestForApiFragmentViewModel.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/api/ui/TestForApiFragmentViewModel.kt index d277c9b961d19aa3ab2eba3c8eb262c0fe71fe51..87ab9e8d040733ba9d4bbabbac3f448bb7884b60 100644 --- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/api/ui/TestForApiFragmentViewModel.kt +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/api/ui/TestForApiFragmentViewModel.kt @@ -1,26 +1,57 @@ package de.rki.coronawarnapp.test.api.ui +import android.app.Activity import android.content.Context +import android.content.Intent import androidx.core.content.pm.PackageInfoCompat import com.google.android.gms.common.GoogleApiAvailability import com.squareup.inject.assisted.AssistedInject +import de.rki.coronawarnapp.nearby.TracingPermissionHelper import de.rki.coronawarnapp.risk.RiskLevelTask import de.rki.coronawarnapp.task.TaskController import de.rki.coronawarnapp.task.common.DefaultTaskRequest import de.rki.coronawarnapp.util.di.AppContext +import de.rki.coronawarnapp.util.ui.SingleLiveEvent import de.rki.coronawarnapp.util.ui.smartLiveData import de.rki.coronawarnapp.util.viewmodel.CWAViewModel import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory class TestForApiFragmentViewModel @AssistedInject constructor( @AppContext private val context: Context, - private val taskController: TaskController + private val taskController: TaskController, + private val tracingPermissionHelper: TracingPermissionHelper ) : CWAViewModel() { + val errorEvents = SingleLiveEvent<Throwable>() + val infoEvent = SingleLiveEvent<String>() + val permissionRequiredEvent = SingleLiveEvent<(Activity) -> Unit>() + + init { + tracingPermissionHelper.callback = object : TracingPermissionHelper.Callback { + override fun onUpdateTracingStatus(isTracingEnabled: Boolean) { + infoEvent.postValue("isTracingEnabled: $isTracingEnabled") + } + + override fun onError(error: Throwable) { + errorEvents.postValue(error) + } + } + } + fun calculateRiskLevelClicked() { taskController.submit(DefaultTaskRequest(RiskLevelTask::class, originTag = "TestForApiFragmentViewModel")) } + fun handleActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + tracingPermissionHelper.handleActivityResult(requestCode, resultCode, data) + } + + fun requestTracingPermission() { + tracingPermissionHelper.startTracing { permissionRequest -> + permissionRequiredEvent.postValue(permissionRequest) + } + } + val gmsState by smartLiveData { GoogleServicesState( version = PackageInfoCompat.getLongVersionCode( diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/submission/ui/SubmissionTestFragment.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/submission/ui/SubmissionTestFragment.kt index e758be589d545f339e9700bdabdea8d6934a3749..0b47a57d582dbc37f79e344811f28c9f9c39eabf 100644 --- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/submission/ui/SubmissionTestFragment.kt +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/submission/ui/SubmissionTestFragment.kt @@ -1,13 +1,16 @@ package de.rki.coronawarnapp.test.submission.ui import android.annotation.SuppressLint +import android.content.Intent import android.os.Bundle import android.view.View import androidx.fragment.app.Fragment +import androidx.recyclerview.widget.LinearLayoutManager import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentTestSubmissionBinding import de.rki.coronawarnapp.test.menu.ui.TestMenuItem import de.rki.coronawarnapp.util.di.AutoInject +import de.rki.coronawarnapp.util.lists.diffutil.update import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.viewBindingLazy import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider @@ -32,6 +35,26 @@ class SubmissionTestFragment : Fragment(R.layout.fragment_test_submission), Auto deleteTokenAction.setOnClickListener { vm.deleteRegistrationToken() } scrambleTokenAction.setOnClickListener { vm.scrambleRegistrationToken() } } + + val tekHistoryAdapter = TEKHistoryAdapter() + binding.tekHistoryList.apply { + adapter = tekHistoryAdapter + layoutManager = LinearLayoutManager(requireContext()) + } + vm.tekHistory.observe2(this) { teks -> + tekHistoryAdapter.update(teks) + } + + binding.apply { + tekStorageUpdate.setOnClickListener { vm.updateStorage(requireActivity()) } + tekStorageClear.setOnClickListener { vm.clearStorage() } + } + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + if (!vm.onActivityResult(requestCode, resultCode, data)) { + super.onActivityResult(requestCode, resultCode, data) + } } companion object { diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/submission/ui/SubmissionTestFragmentViewModel.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/submission/ui/SubmissionTestFragmentViewModel.kt index c5d678dedff0cc54c1c97663f696f15303b27288..758d6d0910620c51aef1f4e3ac5bc3765ccc14c6 100644 --- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/submission/ui/SubmissionTestFragmentViewModel.kt +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/submission/ui/SubmissionTestFragmentViewModel.kt @@ -1,21 +1,64 @@ package de.rki.coronawarnapp.test.submission.ui +import android.app.Activity +import android.content.Intent +import androidx.lifecycle.LiveData import androidx.lifecycle.asLiveData +import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey import com.squareup.inject.assisted.AssistedInject import de.rki.coronawarnapp.storage.LocalData +import de.rki.coronawarnapp.submission.data.tekhistory.TEKHistoryStorage +import de.rki.coronawarnapp.submission.data.tekhistory.TEKHistoryUpdater +import de.rki.coronawarnapp.submission.data.tekhistory.TEKHistoryUpdater.UpdateResult import de.rki.coronawarnapp.util.coroutine.DispatcherProvider +import de.rki.coronawarnapp.util.ui.SingleLiveEvent import de.rki.coronawarnapp.util.viewmodel.CWAViewModel import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.map +import timber.log.Timber import java.util.UUID class SubmissionTestFragmentViewModel @AssistedInject constructor( - dispatcherProvider: DispatcherProvider + dispatcherProvider: DispatcherProvider, + private val tekHistoryStorage: TEKHistoryStorage, + private val tekHistoryUpdater: TEKHistoryUpdater ) : CWAViewModel(dispatcherProvider = dispatcherProvider) { + val errorEvents = SingleLiveEvent<Throwable>() private val internalToken = MutableStateFlow(LocalData.registrationToken()) val currentTestId = internalToken.asLiveData() + val tekHistory: LiveData<List<TEKHistoryItem>> = tekHistoryStorage.tekData.map { items -> + items.flatMap { batch -> + batch.keys + .map { key -> + TEKHistoryItem( + obtainedAt = batch.obtainedAt, + batchId = batch.batchId, + key = key + ) + } + .sortedBy { it.key.rollingStartIntervalNumber } + } + }.asLiveData(context = dispatcherProvider.Default) + + init { + tekHistoryUpdater.callback = object : TEKHistoryUpdater.Callback { + override fun onTEKAvailable(teks: List<TemporaryExposureKey>) { + Timber.d("TEKs are available: %s", teks) + } + + override fun onPermissionDeclined() { + Timber.d("Permission were declined.") + } + + override fun onError(error: Throwable) { + errorEvents.postValue(error) + } + } + } + fun scrambleRegistrationToken() { LocalData.registrationToken(UUID.randomUUID().toString()) internalToken.value = LocalData.registrationToken() @@ -26,6 +69,36 @@ class SubmissionTestFragmentViewModel @AssistedInject constructor( internalToken.value = LocalData.registrationToken() } + fun updateStorage(activity: Activity) { + tekHistoryUpdater.updateTEKHistoryOrRequestPermission { permissionRequest -> + permissionRequest.invoke(activity) + } + } + + fun clearStorage() { + launch { + tekHistoryStorage.clear() + } + } + + fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?): Boolean { + val result = tekHistoryUpdater.handleActivityResult(requestCode, resultCode, data) + Timber.d("tekHistoryUpdater.handleActivityResult(): %s", result) + + if (result == UpdateResult.PERMISSION_AVAILABLE) { + launch { + try { + tekHistoryUpdater.updateHistoryOrThrow() + } catch (e: Exception) { + Timber.e(e, "updateHistoryOrThrow() threw :O") + errorEvents.postValue(e) + } + } + } + + return result != UpdateResult.UNKNOWN_RESULT + } + @AssistedInject.Factory interface Factory : SimpleCWAViewModelFactory<SubmissionTestFragmentViewModel> } diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/submission/ui/TEKHistoryAdapter.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/submission/ui/TEKHistoryAdapter.kt new file mode 100644 index 0000000000000000000000000000000000000000..759f52916867432a540abb78b5093998bcb77c3a --- /dev/null +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/submission/ui/TEKHistoryAdapter.kt @@ -0,0 +1,49 @@ +package de.rki.coronawarnapp.test.submission.ui + +import android.view.ViewGroup +import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.databinding.FragmentTestSubmissionTekhistoryLineBinding +import de.rki.coronawarnapp.ui.lists.BaseAdapter +import de.rki.coronawarnapp.util.lists.BindableVH +import de.rki.coronawarnapp.util.lists.diffutil.AsyncDiffUtilAdapter +import de.rki.coronawarnapp.util.lists.diffutil.AsyncDiffer +import okio.ByteString.Companion.toByteString + +class TEKHistoryAdapter : BaseAdapter<TEKHistoryAdapter.VH>(), AsyncDiffUtilAdapter<TEKHistoryItem> { + + init { + setHasStableIds(true) + } + + override val asyncDiffer: AsyncDiffer<TEKHistoryItem> = AsyncDiffer(this) + + override fun getItemCount(): Int = data.size + + override fun getItemId(position: Int): Long = data[position].stableId + + override fun onCreateBaseVH(parent: ViewGroup, viewType: Int): VH = VH(parent) + + override fun onBindBaseVH(holder: VH, position: Int) { + val item = data[position] + holder.bind(item) + } + + class VH( + val parent: ViewGroup + ) : BaseAdapter.VH( + R.layout.fragment_test_submission_tekhistory_line, parent + ), BindableVH<TEKHistoryItem, FragmentTestSubmissionTekhistoryLineBinding> { + + override val viewBinding = lazy { FragmentTestSubmissionTekhistoryLineBinding.bind(itemView) } + + override val onBindData: FragmentTestSubmissionTekhistoryLineBinding.(key: TEKHistoryItem) -> Unit = { item -> + val key = item.key + primary.text = """ + rollingStartIntervalNumber=${key.rollingStartIntervalNumber} rollingPeriod=${key.rollingPeriod} + transmissionRiskLevel=${key.transmissionRiskLevel} reportType=${key.reportType} + daysSinceOnsetOfSymptoms=${key.daysSinceOnsetOfSymptoms} + """.trimIndent() + secondary.text = "keyData=${key.keyData.toByteString().base64()}" + } + } +} diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/submission/ui/TEKHistoryItem.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/submission/ui/TEKHistoryItem.kt new file mode 100644 index 0000000000000000000000000000000000000000..99dc8859631ee5f2d7d23cb81cdf627482a184a1 --- /dev/null +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/submission/ui/TEKHistoryItem.kt @@ -0,0 +1,14 @@ +package de.rki.coronawarnapp.test.submission.ui + +import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey +import de.rki.coronawarnapp.util.lists.HasStableId +import org.joda.time.Instant + +data class TEKHistoryItem( + val obtainedAt: Instant, + val batchId: String, + val key: TemporaryExposureKey +) : HasStableId { + + override val stableId: Long = key.keyData.hashCode().toLong() +} diff --git a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_submission.xml b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_submission.xml index ac69680e903cf5df93ecff2f503a2a65dcee8fe5..89613811ce5e5076a182402f2bf0fa96f2724031 100644 --- a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_submission.xml +++ b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_submission.xml @@ -64,5 +64,51 @@ </androidx.constraintlayout.widget.ConstraintLayout> + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/tek_history" + style="@style/card" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="@dimen/spacing_tiny" + android:layout_marginStart="8dp" + android:layout_marginEnd="8dp"> + + <TextView + android:id="@+id/tek_history_title" + style="@style/body1" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="Stored TEK History" + app:layout_constraintTop_toTopOf="parent" /> + + <Button + android:id="@+id/tek_storage_update" + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_marginTop="@dimen/spacing_tiny" + android:text="Update storage" + app:layout_constraintEnd_toStartOf="@+id/tek_storage_clear" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/tek_history_title" /> + + <Button + android:id="@+id/tek_storage_clear" + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_marginTop="@dimen/spacing_tiny" + android:text="Clear storage" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toEndOf="@+id/tek_storage_update" + app:layout_constraintTop_toBottomOf="@id/tek_history_title" /> + + <androidx.recyclerview.widget.RecyclerView + android:id="@+id/tek_history_list" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_tiny" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintTop_toBottomOf="@id/tek_storage_clear" /> + </androidx.constraintlayout.widget.ConstraintLayout> + </LinearLayout> </androidx.core.widget.NestedScrollView> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/ENPermissionException.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/ENPermissionException.kt deleted file mode 100644 index 86ed68b893e8d8a32e0394ec3e117e0f4e09f841..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/ENPermissionException.kt +++ /dev/null @@ -1,10 +0,0 @@ -package de.rki.coronawarnapp.exception - -import de.rki.coronawarnapp.exception.reporting.ErrorCodes -import de.rki.coronawarnapp.exception.reporting.ReportedException - -class ENPermissionException : - ReportedException( - ErrorCodes.EN_PERMISSION_PROBLEM.code, - "user did not grant the exposure notification permission" - ) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/reporting/ExceptionReporter.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/reporting/ExceptionReporter.kt index 5f177f2920d7e8bc8bf9738df7e19189f9aa6f0b..11eee98a8a05d095c46e2f8bbf21674f7a17c4b9 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/reporting/ExceptionReporter.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/reporting/ExceptionReporter.kt @@ -24,7 +24,7 @@ fun Throwable.report(exceptionCategory: ExceptionCategory) { fun Throwable.report( exceptionCategory: ExceptionCategory, prefix: String?, - suffix: String? + suffix: String? = null ) { if (CWADebug.isAUnitTest) return diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ENFClient.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ENFClient.kt index 4838e9ceeac1340f3a7bd07671e84e8b6dd712bc..c99f4c9ef4ae8dcab13a8f37eff1bf1b49fe7cf4 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ENFClient.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ENFClient.kt @@ -10,6 +10,7 @@ import de.rki.coronawarnapp.nearby.modules.detectiontracker.TrackedExposureDetec import de.rki.coronawarnapp.nearby.modules.diagnosiskeyprovider.DiagnosisKeyProvider import de.rki.coronawarnapp.nearby.modules.exposurewindow.ExposureWindowProvider import de.rki.coronawarnapp.nearby.modules.locationless.ScanningSupport +import de.rki.coronawarnapp.nearby.modules.tekhistory.TEKHistoryProvider import de.rki.coronawarnapp.nearby.modules.tracing.TracingStatus import de.rki.coronawarnapp.nearby.modules.version.ENFVersion import kotlinx.coroutines.flow.Flow @@ -29,8 +30,14 @@ class ENFClient @Inject constructor( private val scanningSupport: ScanningSupport, private val exposureWindowProvider: ExposureWindowProvider, private val exposureDetectionTracker: ExposureDetectionTracker, - private val enfVersion: ENFVersion -) : DiagnosisKeyProvider, TracingStatus, ScanningSupport, ExposureWindowProvider, ENFVersion by enfVersion { + private val enfVersion: ENFVersion, + private val tekHistoryProvider: TEKHistoryProvider +) : DiagnosisKeyProvider, + TracingStatus by tracingStatus, + ScanningSupport, + ExposureWindowProvider, + ENFVersion by enfVersion, + TEKHistoryProvider by tekHistoryProvider { // TODO Remove this once we no longer need direct access to the ENF Client, // i.e. in **[InternalExposureNotificationClient]** @@ -56,9 +63,6 @@ class ENFClient @Inject constructor( override val isLocationLessScanningSupported: Flow<Boolean> get() = scanningSupport.isLocationLessScanningSupported - override val isTracingEnabled: Flow<Boolean> - get() = tracingStatus.isTracingEnabled - fun isPerformingExposureDetection(): Flow<Boolean> = exposureDetectionTracker.calculations .map { it.values } .map { values -> diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ENFModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ENFModule.kt index cbf0c96de676d53d0f59d28aad11c4ea4ee121e5..ccbe5c6956fd5ff52581c9aacf0d4d079aef6c31 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ENFModule.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ENFModule.kt @@ -15,6 +15,8 @@ import de.rki.coronawarnapp.nearby.modules.exposurewindow.DefaultExposureWindowP import de.rki.coronawarnapp.nearby.modules.exposurewindow.ExposureWindowProvider import de.rki.coronawarnapp.nearby.modules.locationless.DefaultScanningSupport import de.rki.coronawarnapp.nearby.modules.locationless.ScanningSupport +import de.rki.coronawarnapp.nearby.modules.tekhistory.DefaultTEKHistoryProvider +import de.rki.coronawarnapp.nearby.modules.tekhistory.TEKHistoryProvider import de.rki.coronawarnapp.nearby.modules.tracing.DefaultTracingStatus import de.rki.coronawarnapp.nearby.modules.tracing.TracingStatus import de.rki.coronawarnapp.nearby.modules.version.DefaultENFVersion @@ -63,4 +65,8 @@ class ENFModule { @Singleton @Provides fun enfClientVersion(enfVersion: DefaultENFVersion): ENFVersion = enfVersion + + @Singleton + @Provides + fun tekHistory(tekHistory: DefaultTEKHistoryProvider): TEKHistoryProvider = tekHistory } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/InternalExposureNotificationClient.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/InternalExposureNotificationClient.kt index 3ded662b655f7aa9dc7b87cdada9cbd6425031a6..7229fda0a8ad3809edf317bfa0eaaf3f401daf06 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/InternalExposureNotificationClient.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/InternalExposureNotificationClient.kt @@ -1,13 +1,8 @@ package de.rki.coronawarnapp.nearby -import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey -import de.rki.coronawarnapp.CoronaWarnApplication -import de.rki.coronawarnapp.risk.TimeVariables -import de.rki.coronawarnapp.storage.LocalData -import de.rki.coronawarnapp.storage.tracing.TracingIntervalRepository -import de.rki.coronawarnapp.util.TimeAndDateExtensions.millisecondsToSeconds import de.rki.coronawarnapp.util.di.AppInjector -import java.util.Date +import kotlinx.coroutines.flow.first +import timber.log.Timber import kotlin.coroutines.resume import kotlin.coroutines.resumeWithException import kotlin.coroutines.suspendCoroutine @@ -19,41 +14,8 @@ import kotlin.coroutines.suspendCoroutine object InternalExposureNotificationClient { // reference to the client from the Google framework with the given application context - private val exposureNotificationClient by lazy { - AppInjector.component.enfClient.internalClient - } - - /**************************************************** - * COROUTINE FUNCTIONS - ****************************************************/ - /** - * Tells Google Play services to start the broadcasting and scanning process. The first time - * that this method is called after installation of the app, it prompts Google Play services to - * display a dialog box, where the user is asked to give permission to broadcast and scan. - * - * @return - */ - suspend fun asyncStart() = suspendCoroutine<Void> { cont -> - exposureNotificationClient.start() - .addOnSuccessListener { - cont.resume(it) - }.addOnFailureListener { - cont.resumeWithException(it) - } - }.also { - LocalData.lastNonActiveTracingTimestamp()?.let { ts -> - TracingIntervalRepository.getDateRepository(CoronaWarnApplication.getAppContext()) - .createInterval(ts, System.currentTimeMillis()) - val difference = Date().time.minus(ts).millisecondsToSeconds() - if (difference >= TimeVariables.getDeactivationTracingMeasureThresholdTimeRange()) { - LocalData.totalNonActiveTracing( - LocalData.totalNonActiveTracing().plus(difference) - ) - } - } - LocalData.lastNonActiveTracingTimestamp(null) - LocalData.initialTracingActivationTimestamp() - ?: LocalData.initialTracingActivationTimestamp(System.currentTimeMillis()) + private val enfClient by lazy { + AppInjector.component.enfClient } /** @@ -63,15 +25,13 @@ object InternalExposureNotificationClient { * * @return */ - suspend fun asyncStop() = suspendCoroutine<Void> { cont -> - exposureNotificationClient.stop() - .addOnSuccessListener { - cont.resume(it) - }.addOnFailureListener { - cont.resumeWithException(it) - } - }.also { - LocalData.lastNonActiveTracingTimestamp(System.currentTimeMillis()) + suspend fun asyncStop() = suspendCoroutine<Unit> { cont -> + enfClient.setTracing( + false, + onSuccess = { cont.resume(Unit) }, + onError = { cont.resumeWithException(it) }, + onPermissionRequired = { Timber.e("Permission was required to disable tracing?") } + ) } /** @@ -79,33 +39,5 @@ object InternalExposureNotificationClient { * * @return */ - suspend fun asyncIsEnabled(): Boolean = suspendCoroutine { cont -> - exposureNotificationClient.isEnabled - .addOnSuccessListener { - cont.resume(it) - }.addOnFailureListener { - cont.resumeWithException(it) - } - } - - /** - * Retrieves key history from the data store on the device for uploading to your - * internet-accessible server. Calling this method prompts Google Play services to display - * a dialog, requesting permission from the user to gather and upload their exposure keys. - * The keys returned include the past 14 days, but not the current day’s key. - * - * The permission granted by the user lasts for 24 hours, so the permission dialog appears - * only once for each 24-hour period, regardless of how many times the method is called - * - * @return - */ - suspend fun asyncGetTemporaryExposureKeyHistory(): List<TemporaryExposureKey> = - suspendCoroutine { cont -> - exposureNotificationClient.temporaryExposureKeyHistory - .addOnSuccessListener { - cont.resume(it) - }.addOnFailureListener { - cont.resumeWithException(it) - } - } + suspend fun asyncIsEnabled(): Boolean = enfClient.isTracingEnabled.first() } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/InternalExposureNotificationPermissionHelper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/InternalExposureNotificationPermissionHelper.kt deleted file mode 100644 index 8bba58f42a35db70e0a5497d739d8588eabda020..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/InternalExposureNotificationPermissionHelper.kt +++ /dev/null @@ -1,169 +0,0 @@ -package de.rki.coronawarnapp.nearby - -import android.app.Activity -import android.content.IntentSender -import androidx.fragment.app.Fragment -import androidx.lifecycle.lifecycleScope -import com.google.android.gms.common.api.ApiException -import com.google.android.gms.nearby.exposurenotification.ExposureNotificationStatusCodes -import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey -import de.rki.coronawarnapp.exception.ENPermissionException -import de.rki.coronawarnapp.exception.ExceptionCategory -import de.rki.coronawarnapp.exception.reporting.report -import kotlinx.coroutines.launch - -/** - * Permission Helper for Exposure Notification permissions needed by the API - * - * In the current v1.3 of the Exposure Notification the user is asked for permission for the following - * actions: - * - * getTemporaryExposureKeyHistory - * start - * - * The permission in the current state is implemented with a specific exception. If the Exposure Notification functions - * needs a specific permission to proceed an ApiException with a certain status will be raised. - * This needs to be handled accordingly in order to display the permission dialog to the user. - * @see handleException - * - * @property host - * @property callback - */ - -class InternalExposureNotificationPermissionHelper( - private val host: Fragment, - private val callback: Callback -) { - - interface Callback { - fun onFailure(exception: Exception?) - fun onStartPermissionGranted() {} - fun onKeySharePermissionGranted(keys: List<TemporaryExposureKey>) {} - } - - companion object { - private val TAG: String? = InternalExposureNotificationPermissionHelper::class.simpleName - } - - private var permissionResolutionInProgress = false - - /** - * Function to request the permission to start tracing - * - * @see InternalExposureNotificationClient.asyncStart - * - */ - fun requestPermissionToStartTracing() { - // Call start only if isEnabled() is false - host.viewLifecycleOwner.lifecycleScope.launch { - try { - val isEnabled = - InternalExposureNotificationClient.asyncIsEnabled() - if (!isEnabled) { - InternalExposureNotificationClient.asyncStart() - } - callback.onStartPermissionGranted() - } catch (apiException: ApiException) { - handleException( - apiException, - ResolutionRequestCodes.REQUEST_CODE_START_EXPOSURE_NOTIFICATION.code - ) - } catch (exception: Exception) { - returnError(exception) - } - } - } - - /** - * Function to request the permission get and ultimately share their own Temporary Exposure Keys - * - * @see InternalExposureNotificationClient.asyncGetExposureSummary - * - */ - fun requestPermissionToShareKeys() { - host.viewLifecycleOwner.lifecycleScope.launch { - try { - val keys = InternalExposureNotificationClient.asyncGetTemporaryExposureKeyHistory() - callback.onKeySharePermissionGranted(keys) - } catch (apiException: ApiException) { - handleException( - apiException, - ResolutionRequestCodes.REQUEST_CODE_GET_TEMP_EXPOSURE_KEY_HISTORY.code - ) - } catch (exception: Exception) { - returnError(exception) - } - } - } - - /** - * Will evaluate if the exception was raised because of a missing permission - * If that is the case the permission dialog will be shown to the user - * - * @param apiException - * @param resolutionRequestCode request code for the specific task the user has to give permission - */ - private fun handleException(apiException: ApiException, resolutionRequestCode: Int) { - if (permissionResolutionInProgress) { - returnError(apiException) - return - } - - if (apiException.statusCode == ExposureNotificationStatusCodes.RESOLUTION_REQUIRED) { - try { - permissionResolutionInProgress = true - apiException.status.startResolutionForResult( - host.activity, - resolutionRequestCode - ) - } catch (e: IntentSender.SendIntentException) { - returnError(e) - } - } else { - returnError(apiException) - } - } - - /** - * Returns the error to the callback - * - * @param exception - */ - private fun returnError(exception: Exception) { - exception.report( - ExceptionCategory.EXPOSURENOTIFICATION, - TAG, - null - ) - permissionResolutionInProgress = false - callback.onFailure(exception) - } - - /** - * Function which can be invoked on the onActivityResult event to get the users decision if the permission was - * given or not. - * - * Depending on the requested permission the corresponding function will be executed again to check if the permission - * is now there and to execute the action immediately - * - * @param requestCode code of the requested permission - * @param resultCode code of the user decision - */ - fun onResolutionComplete( - requestCode: Int, - resultCode: Int - ) { - permissionResolutionInProgress = false - - if (resultCode == Activity.RESULT_OK) { - when (requestCode) { - ResolutionRequestCodes.REQUEST_CODE_START_EXPOSURE_NOTIFICATION.code - -> requestPermissionToStartTracing() - ResolutionRequestCodes.REQUEST_CODE_GET_TEMP_EXPOSURE_KEY_HISTORY.code - -> requestPermissionToShareKeys() - } - } else { - callback.onFailure(ENPermissionException()) - } - } -} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ResolutionRequestCodeConstants.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ResolutionRequestCodeConstants.kt deleted file mode 100644 index 0adb9de284eda7cbe93974ba51abaf551186b195..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ResolutionRequestCodeConstants.kt +++ /dev/null @@ -1,6 +0,0 @@ -package de.rki.coronawarnapp.nearby - -object ResolutionRequestCodeConstants { - const val REQUEST_CODE_START_EXPOSURE_NOTIFICATION_CODE = 1111 - const val REQUEST_CODE_GET_TEMP_EXPOSURE_KEY_HISTORY_CODE = 2222 -} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ResolutionRequestCodes.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ResolutionRequestCodes.kt deleted file mode 100644 index 7104ec1512307904c6168b732bf2363b74c63789..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ResolutionRequestCodes.kt +++ /dev/null @@ -1,16 +0,0 @@ -package de.rki.coronawarnapp.nearby - -/** - * Enum class to reflect the request codes of the different - * permissions for the Exposure Notification API - * - * @property code - */ -enum class ResolutionRequestCodes(val code: Int) { - REQUEST_CODE_START_EXPOSURE_NOTIFICATION( - ResolutionRequestCodeConstants.REQUEST_CODE_START_EXPOSURE_NOTIFICATION_CODE - ), - REQUEST_CODE_GET_TEMP_EXPOSURE_KEY_HISTORY( - ResolutionRequestCodeConstants.REQUEST_CODE_GET_TEMP_EXPOSURE_KEY_HISTORY_CODE - ) -} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/TracingPermissionHelper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/TracingPermissionHelper.kt new file mode 100644 index 0000000000000000000000000000000000000000..96d331d90f6714cc1b25dd58aa45e785b352a9e0 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/TracingPermissionHelper.kt @@ -0,0 +1,92 @@ +package de.rki.coronawarnapp.nearby + +import android.app.Activity +import android.content.Intent +import de.rki.coronawarnapp.util.coroutine.AppScope +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.launch +import timber.log.Timber +import javax.inject.Inject + +class TracingPermissionHelper @Inject constructor( + private val enfClient: ENFClient, + @AppScope private val scope: CoroutineScope +) { + + var callback: Callback? = null + + fun startTracing( + onUserPermissionRequired: (permissionRequest: (Activity) -> Unit) -> Unit + ) { + scope.launch { + if (enfClient.isTracingEnabled.first()) { + callback?.onUpdateTracingStatus(true) + } else { + enableTracing(onUserPermissionRequired) + } + } + } + + private fun enableTracing( + onUserPermissionRequired: ((permissionRequest: (Activity) -> Unit) -> Unit)? + ) { + enfClient.setTracing( + true, + onSuccess = { callback?.onUpdateTracingStatus(true) }, + onError = { callback?.onError(it) }, + onPermissionRequired = { status -> + if (onUserPermissionRequired != null) { + val permissionRequestTrigger: (Activity) -> Unit = { + status.startResolutionForResult(it, TRACING_PERMISSION_REQUESTCODE) + } + onUserPermissionRequired(permissionRequestTrigger) + } else { + callback?.onError( + IllegalStateException("Permission were granted but we are still not allowed to enable tracing.") + ) + } + } + ) + } + + fun handleActivityResult(requestCode: Int, resultCode: Int, data: Intent?): UpdateResult { + Timber.v( + "handleActivityResult(requesutCode=%d, resultCode=%d, data=%s)", + requestCode, resultCode, data + ) + if (requestCode != TRACING_PERMISSION_REQUESTCODE) { + Timber.tag(TAG).w("Not our request code ($requestCode): %s", data) + return UpdateResult.UNKNOWN_RESULT + } + + return if (resultCode == Activity.RESULT_OK) { + Timber.tag(TAG).w("User granted permission (== RESULT_OK): %s", data) + + enableTracing(null) + UpdateResult.PERMISSION_AVAILABLE + } else { + Timber.tag(TAG).w("User declined permission (!= RESULT_OK): %s", data) + + callback?.onUpdateTracingStatus(false) + UpdateResult.PERMISSION_DECLINED + } + } + + enum class UpdateResult { + PERMISSION_AVAILABLE, + PERMISSION_DECLINED, + UNKNOWN_RESULT + } + + interface Callback { + fun onUpdateTracingStatus(isTracingEnabled: Boolean) + + fun onError(error: Throwable) + } + + companion object { + private const val TAG = "TracingPermissionHelper" + const val TRACING_PERMISSION_REQUESTCODE = 3010 + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/tekhistory/DefaultTEKHistoryProvider.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/tekhistory/DefaultTEKHistoryProvider.kt new file mode 100644 index 0000000000000000000000000000000000000000..537d70cf4127e31899ad72fd5b72ec99d9d404ea --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/tekhistory/DefaultTEKHistoryProvider.kt @@ -0,0 +1,67 @@ +package de.rki.coronawarnapp.nearby.modules.tekhistory + +import android.content.IntentSender +import com.google.android.gms.common.api.ApiException +import com.google.android.gms.common.api.Status +import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient +import com.google.android.gms.nearby.exposurenotification.ExposureNotificationStatusCodes +import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey +import timber.log.Timber +import javax.inject.Inject +import javax.inject.Singleton +import kotlin.coroutines.resume +import kotlin.coroutines.resumeWithException +import kotlin.coroutines.suspendCoroutine + +@Singleton +class DefaultTEKHistoryProvider @Inject constructor( + private val client: ExposureNotificationClient +) : TEKHistoryProvider { + + override suspend fun isTEKAccessPermissionGranted(): Boolean { + return try { + getTEKHistory() + true + } catch (e: ApiException) { + if (e.statusCode == ExposureNotificationStatusCodes.RESOLUTION_REQUIRED) { + false + } else { + throw e + } + } + } + + override suspend fun getTEKHistoryOrRequestPermission( + onTEKHistoryAvailable: (List<TemporaryExposureKey>) -> Unit, + onPermissionRequired: (Status) -> Unit + ) { + try { + onTEKHistoryAvailable(getTEKHistory()) + } catch (apiException: ApiException) { + if (apiException.statusCode != ExposureNotificationStatusCodes.RESOLUTION_REQUIRED) { + throw apiException + } + if (!apiException.status.hasResolution()) { + throw apiException + } + try { + onPermissionRequired(apiException.status) + } catch (e: IntentSender.SendIntentException) { + throw e + } + } + } + + override suspend fun getTEKHistory(): List<TemporaryExposureKey> = suspendCoroutine { cont -> + Timber.i("Retrieving temporary exposure keys.") + client.temporaryExposureKeyHistory + .addOnSuccessListener { + Timber.i("Temporary exposure keys were retrieved: %s", it.joinToString("\n")) + cont.resume(it) + } + .addOnFailureListener { + Timber.e(it, "Failed to retrieve temporary exposure keys.") + cont.resumeWithException(it) + } + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/tekhistory/TEKHistoryProvider.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/tekhistory/TEKHistoryProvider.kt new file mode 100644 index 0000000000000000000000000000000000000000..264571ca22f883d1629273acf083ffa5c1dca5cf --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/tekhistory/TEKHistoryProvider.kt @@ -0,0 +1,25 @@ +package de.rki.coronawarnapp.nearby.modules.tekhistory + +import com.google.android.gms.common.api.Status +import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey + +interface TEKHistoryProvider { + + /** + * Retrieves key history from the data store on the device for uploading to your + * internet-accessible server. Calling this method prompts Google Play services to display + * a dialog, requesting permission from the user to gather and upload their exposure keys. + * The keys returned include the past 14 days, but not the current day’s key. + * + * The permission granted by the user lasts for 24 hours, so the permission dialog appears + * only once for each 24-hour period, regardless of how many times the method is called + */ + suspend fun getTEKHistory(): List<TemporaryExposureKey> + + suspend fun isTEKAccessPermissionGranted(): Boolean + + suspend fun getTEKHistoryOrRequestPermission( + onTEKHistoryAvailable: (List<TemporaryExposureKey>) -> Unit, + onPermissionRequired: (Status) -> Unit + ) +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/tracing/DefaultTracingStatus.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/tracing/DefaultTracingStatus.kt index d8ef3330e9fda35f2935660f6ce4ffef0094f8c3..a34f35c65762487bf05abbf4a7079699f566ed9a 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/tracing/DefaultTracingStatus.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/tracing/DefaultTracingStatus.kt @@ -1,8 +1,16 @@ package de.rki.coronawarnapp.nearby.modules.tracing +import com.google.android.gms.common.api.ApiException +import com.google.android.gms.common.api.Status import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient +import com.google.android.gms.nearby.exposurenotification.ExposureNotificationStatusCodes +import de.rki.coronawarnapp.CoronaWarnApplication import de.rki.coronawarnapp.exception.ExceptionCategory import de.rki.coronawarnapp.exception.reporting.report +import de.rki.coronawarnapp.risk.TimeVariables +import de.rki.coronawarnapp.storage.LocalData +import de.rki.coronawarnapp.storage.tracing.TracingIntervalRepository +import de.rki.coronawarnapp.util.TimeAndDateExtensions.millisecondsToSeconds import de.rki.coronawarnapp.util.coroutine.AppScope import de.rki.coronawarnapp.util.flow.shareLatest import kotlinx.coroutines.CancellationException @@ -15,7 +23,9 @@ import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.onCompletion import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onStart +import kotlinx.coroutines.launch import timber.log.Timber +import java.util.Date import javax.inject.Inject import javax.inject.Singleton import kotlin.coroutines.resume @@ -28,10 +38,73 @@ class DefaultTracingStatus @Inject constructor( @AppScope val scope: CoroutineScope ) : TracingStatus { + override fun setTracing( + enable: Boolean, + onSuccess: (Boolean) -> Unit, + onError: (Throwable) -> Unit, + onPermissionRequired: (Status) -> Unit + ) { + scope.launch { + try { + if (enable) { + if (isEnabled()) { + onSuccess(true) + } else { + asyncStart() + onSuccess(true) + } + } else { + if (!isEnabled()) { + onSuccess(false) + } else { + asyncStop() + onSuccess(false) + } + } + } catch (e: Exception) { + if (e is ApiException && e.statusCode == ExposureNotificationStatusCodes.RESOLUTION_REQUIRED) { + Timber.tag(TAG).i(e, "Permission needs to be granted by user.") + onPermissionRequired(e.status) + } else { + Timber.tag(TAG).e(e, "Failed to change tracing state.") + onError(e) + } + } + } + } + + private suspend fun asyncStart() = suspendCoroutine<Void> { cont -> + client.start() + .addOnSuccessListener { cont.resume(it) } + .addOnFailureListener { cont.resumeWithException(it) } + }.also { + LocalData.lastNonActiveTracingTimestamp()?.let { ts -> + TracingIntervalRepository.getDateRepository(CoronaWarnApplication.getAppContext()) + .createInterval(ts, System.currentTimeMillis()) + val difference = Date().time.minus(ts).millisecondsToSeconds() + if (difference >= TimeVariables.getDeactivationTracingMeasureThresholdTimeRange()) { + LocalData.totalNonActiveTracing( + LocalData.totalNonActiveTracing().plus(difference) + ) + } + } + LocalData.lastNonActiveTracingTimestamp(null) + LocalData.initialTracingActivationTimestamp() + ?: LocalData.initialTracingActivationTimestamp(System.currentTimeMillis()) + } + + private suspend fun asyncStop() = suspendCoroutine<Void> { cont -> + client.stop() + .addOnSuccessListener { cont.resume(it) } + .addOnFailureListener { cont.resumeWithException(it) } + }.also { + LocalData.lastNonActiveTracingTimestamp(System.currentTimeMillis()) + } + override val isTracingEnabled: Flow<Boolean> = flow { while (true) { try { - emit(pollIsEnabled()) + emit(isEnabled()) delay(POLLING_DELAY_MS) } catch (e: CancellationException) { Timber.d("isBackgroundRestricted was cancelled") @@ -53,7 +126,7 @@ class DefaultTracingStatus @Inject constructor( scope = scope ) - private suspend fun pollIsEnabled(): Boolean = suspendCoroutine { cont -> + private suspend fun isEnabled(): Boolean = suspendCoroutine { cont -> client.isEnabled .addOnSuccessListener { cont.resume(it) } .addOnFailureListener { cont.resumeWithException(it) } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/tracing/TracingStatus.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/tracing/TracingStatus.kt index d2d64ee3d980e7e2d489cee2a7170406d932df96..d98223148d89af4d909c2a6723c820a7d7713e54 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/tracing/TracingStatus.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/tracing/TracingStatus.kt @@ -1,7 +1,15 @@ package de.rki.coronawarnapp.nearby.modules.tracing +import com.google.android.gms.common.api.Status import kotlinx.coroutines.flow.Flow interface TracingStatus { val isTracingEnabled: Flow<Boolean> + + fun setTracing( + enable: Boolean, + onSuccess: (Boolean) -> Unit, + onError: (Throwable) -> Unit, + onPermissionRequired: (Status) -> Unit + ) } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/notification/TestResultNotificationService.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/notification/TestResultNotificationService.kt index b435c2ff87d82e4c5eac5125ab2ab86d4d57be0f..ecfeb8f79dc592c5476c5c503bfb577376bf2298 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/notification/TestResultNotificationService.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/notification/TestResultNotificationService.kt @@ -39,7 +39,7 @@ class TestResultNotificationService @Inject constructor( val pendingIntent = NavDeepLinkBuilder(context) .setGraph(R.navigation.nav_graph) .setComponentName(MainActivity::class.java) - .setDestination(R.id.submissionResultFragment) + .setDestination(R.id.submissionTestResultAvailableFragment) .createPendingIntent() NotificationHelper.sendNotification( diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/sharing/ExposureSharingService.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/sharing/ExposureSharingService.kt index 6b07ea1084bc3d8e0cd260f4108d9bee48a8c815..c1df9fb4678fd7ba334e9f27c8a87948716fccf9 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/sharing/ExposureSharingService.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/sharing/ExposureSharingService.kt @@ -10,8 +10,8 @@ import com.google.zxing.qrcode.QRCodeWriter import de.rki.coronawarnapp.exception.ExceptionCategory.EXPOSURENOTIFICATION import de.rki.coronawarnapp.exception.ExceptionCategory.INTERNAL import de.rki.coronawarnapp.exception.reporting.report -import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient import de.rki.coronawarnapp.server.protocols.AppleLegacyKeyExchange +import de.rki.coronawarnapp.util.di.AppInjector import timber.log.Timber object ExposureSharingService { @@ -24,10 +24,9 @@ object ExposureSharingService { callback: (Bitmap?) -> Unit? ) { try { - val tempExpKeys = InternalExposureNotificationClient - .asyncGetTemporaryExposureKeyHistory() + val tempExpKeys = AppInjector.component.enfClient.getTEKHistory() - val latest = tempExpKeys.maxBy { it.rollingStartIntervalNumber } + val latest = tempExpKeys.maxByOrNull { it.rollingStartIntervalNumber } val key = AppleLegacyKeyExchange.Key.newBuilder() .setKeyData(ByteString.copyFrom(latest!!.keyData)) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/SubmissionRepository.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/SubmissionRepository.kt index 9fa27a5ef59fa1b7d671376196553a5986027741..fdde1fdc34c29291e61ae094587845cd3586ce37 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/SubmissionRepository.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/SubmissionRepository.kt @@ -8,6 +8,12 @@ import de.rki.coronawarnapp.exception.reporting.report import de.rki.coronawarnapp.playbook.BackgroundNoise import de.rki.coronawarnapp.service.submission.SubmissionService import de.rki.coronawarnapp.submission.SubmissionSettings +import de.rki.coronawarnapp.submission.SubmissionTask +import de.rki.coronawarnapp.submission.data.tekhistory.TEKHistoryStorage +import de.rki.coronawarnapp.task.TaskController +import de.rki.coronawarnapp.task.TaskInfo +import de.rki.coronawarnapp.task.common.DefaultTaskRequest +import de.rki.coronawarnapp.task.submitBlocking import de.rki.coronawarnapp.util.DeviceUIState import de.rki.coronawarnapp.util.NetworkRequestWrapper import de.rki.coronawarnapp.util.NetworkRequestWrapper.Companion.withSuccess @@ -18,6 +24,7 @@ import de.rki.coronawarnapp.worker.BackgroundWorkScheduler import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import timber.log.Timber import java.util.Date @@ -29,14 +36,12 @@ class SubmissionRepository @Inject constructor( private val submissionSettings: SubmissionSettings, private val submissionService: SubmissionService, @AppScope private val scope: CoroutineScope, - private val timeStamper: TimeStamper + private val timeStamper: TimeStamper, + private val taskController: TaskController, + private val tekHistoryStorage: TEKHistoryStorage ) { companion object { - fun submissionSuccessful() { - BackgroundWorkScheduler.stopWorkScheduler() - LocalData.numberOfSuccessfulSubmissions(1) - } fun deleteRegistrationToken() { LocalData.registrationToken(null) LocalData.devicePairingSuccessfulTimestamp(0L) @@ -52,9 +57,25 @@ class SubmissionRepository @Inject constructor( // to be used by new submission flow screens val hasGivenConsentToSubmission = submissionSettings.hasGivenConsent.flow + val currentSymptoms = submissionSettings.symptoms + + private fun List<TaskInfo>.isSubmissionTaskRunning() = any { + it.taskState.isActive && it.taskState.request.type == SubmissionTask::class + } + + val isSubmissionRunning = taskController.tasks.map { it.isSubmissionTaskRunning() } private val testResultFlow = MutableStateFlow<TestResult?>(null) + suspend fun startSubmission() { + Timber.i("Starting submission.") + val result = taskController.submitBlocking(DefaultTaskRequest(type = SubmissionTask::class)) + result.error?.let { + Timber.e(it, "Submission failed.") + it.report(ExceptionCategory.HTTP, prefix = "Submission failed.") + } + } + fun setTeletan(teletan: String) { LocalData.teletan(teletan) } @@ -103,7 +124,7 @@ class SubmissionRepository @Inject constructor( } // TODO this should be more UI agnostic - suspend fun refreshUIState(refreshTestResult: Boolean): NetworkRequestWrapper<DeviceUIState, Throwable> { + private suspend fun refreshUIState(refreshTestResult: Boolean): NetworkRequestWrapper<DeviceUIState, Throwable> { var uiState = DeviceUIState.UNPAIRED if (LocalData.submissionWasSuccessful()) { @@ -144,9 +165,10 @@ class SubmissionRepository @Inject constructor( return registrationData.testResult } - fun reset() { + suspend fun reset() { deviceUIStateFlowInternal.value = NetworkRequestWrapper.RequestIdle - revokeConsentToSubmission() + tekHistoryStorage.clear() + submissionSettings.clear() } @VisibleForTesting diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/SubmissionSettings.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/SubmissionSettings.kt index 8fb7276180cde94a2d30417c55726f85a5224565..c6990e4bf3a08fdad00609d864a93b0668994c3c 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/SubmissionSettings.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/SubmissionSettings.kt @@ -1,16 +1,35 @@ package de.rki.coronawarnapp.submission import android.content.Context +import com.google.gson.Gson import de.rki.coronawarnapp.util.di.AppContext +import de.rki.coronawarnapp.util.preferences.FlowPreference +import de.rki.coronawarnapp.util.preferences.clearAndNotify import de.rki.coronawarnapp.util.preferences.createFlowPreference +import de.rki.coronawarnapp.util.serialization.BaseGson +import de.rki.coronawarnapp.util.serialization.adapter.RuntimeTypeAdapterFactory import javax.inject.Inject import javax.inject.Singleton @Singleton class SubmissionSettings @Inject constructor( - @AppContext val context: Context + @AppContext val context: Context, + @BaseGson val baseGson: Gson ) { + private val gson by lazy { + baseGson.newBuilder().apply { + val rta = RuntimeTypeAdapterFactory.of(Symptoms.StartOf::class.java) + .registerSubtype(Symptoms.StartOf.NoInformation::class.java) + .registerSubtype(Symptoms.StartOf.LastSevenDays::class.java) + .registerSubtype(Symptoms.StartOf.MoreThanTwoWeeks::class.java) + .registerSubtype(Symptoms.StartOf.OneToTwoWeeksAgo::class.java) + .registerSubtype(Symptoms.StartOf.Date::class.java) + + registerTypeAdapterFactory(rta) + }.create() + } + private val prefs by lazy { context.getSharedPreferences("submission_localdata", Context.MODE_PRIVATE) } @@ -19,4 +38,15 @@ class SubmissionSettings @Inject constructor( key = "key_submission_consent", defaultValue = false ) + + val symptoms: FlowPreference<Symptoms?> = FlowPreference( + prefs, + key = "submission.symptoms.latest", + reader = FlowPreference.gsonReader<Symptoms?>(gson, null), + writer = FlowPreference.gsonWriter(gson) + ) + + fun clear() { + prefs.clearAndNotify() + } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/SubmissionTask.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/SubmissionTask.kt index 9f7350a10e581ecee86ec451748e8cb517738763..1511a337ea20b57b3c9d09fd67349d4e80e95c7b 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/SubmissionTask.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/SubmissionTask.kt @@ -2,16 +2,20 @@ package de.rki.coronawarnapp.submission import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey import de.rki.coronawarnapp.appconfig.AppConfigProvider +import de.rki.coronawarnapp.exception.NoRegistrationTokenSetException +import de.rki.coronawarnapp.notification.TestResultNotificationService import de.rki.coronawarnapp.playbook.Playbook -import de.rki.coronawarnapp.server.protocols.external.exposurenotification.TemporaryExposureKeyExportOuterClass -import de.rki.coronawarnapp.storage.SubmissionRepository +import de.rki.coronawarnapp.storage.LocalData +import de.rki.coronawarnapp.submission.data.tekhistory.TEKHistoryStorage import de.rki.coronawarnapp.task.Task import de.rki.coronawarnapp.task.TaskCancellationException import de.rki.coronawarnapp.task.TaskFactory import de.rki.coronawarnapp.task.common.DefaultProgress +import de.rki.coronawarnapp.worker.BackgroundWorkScheduler import kotlinx.coroutines.channels.ConflatedBroadcastChannel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.asFlow +import kotlinx.coroutines.flow.first import org.joda.time.Duration import timber.log.Timber import javax.inject.Inject @@ -20,7 +24,10 @@ import javax.inject.Provider class SubmissionTask @Inject constructor( private val playbook: Playbook, private val appConfigProvider: AppConfigProvider, - private val exposureKeyHistoryCalculations: ExposureKeyHistoryCalculations + private val tekHistoryCalculations: ExposureKeyHistoryCalculations, + private val tekHistoryStorage: TEKHistoryStorage, + private val submissionSettings: SubmissionSettings, + private val testResultNotificationService: TestResultNotificationService ) : Task<DefaultProgress, Task.Result> { private val internalProgress = ConflatedBroadcastChannel<DefaultProgress>() @@ -29,19 +36,41 @@ class SubmissionTask @Inject constructor( private var isCanceled = false override suspend fun run(arguments: Task.Arguments) = try { - Timber.d("Running with arguments=%s", arguments) - arguments as Arguments + Timber.tag(TAG).d("Running with arguments=%s", arguments) - Playbook.SubmissionData( - arguments.registrationToken, - arguments.getHistory(), + val registrationToken = LocalData.registrationToken() ?: throw NoRegistrationTokenSetException() + Timber.tag(TAG).d("Using registrationToken=$registrationToken") + + val keys: List<TemporaryExposureKey> = tekHistoryStorage.tekData.first().flatMap { it.keys } + val symptoms: Symptoms = submissionSettings.symptoms.value ?: Symptoms.NO_INFO_GIVEN + + val transformedKeys = tekHistoryCalculations.transformToKeyHistoryInExternalFormat( + keys, + symptoms + ) + Timber.tag(TAG).d("Transformed keys with symptoms %s from %s to %s", symptoms, keys, transformedKeys) + + val submissionData = Playbook.SubmissionData( + registrationToken, + transformedKeys, true, getSupportedCountries() ) - .also { checkCancel() } - .let { playbook.submit(it) } - SubmissionRepository.submissionSuccessful() + checkCancel() + + Timber.tag(TAG).d("Submitting %s", submissionData) + playbook.submit(submissionData) + + Timber.tag(TAG).d("Submission successful, deleting submission data.") + tekHistoryStorage.clear() + submissionSettings.symptoms.update { null } + + // TODO re-evaluate the necessity of this behavior + BackgroundWorkScheduler.stopWorkScheduler() + LocalData.numberOfSuccessfulSubmissions(1) + + testResultNotificationService.cancelPositiveTestResultNotification() object : Task.Result {} } catch (error: Exception) { @@ -52,12 +81,6 @@ class SubmissionTask @Inject constructor( internalProgress.close() } - private fun Arguments.getHistory(): List<TemporaryExposureKeyExportOuterClass.TemporaryExposureKey> = - exposureKeyHistoryCalculations.transformToKeyHistoryInExternalFormat( - keys, - symptoms - ) - private suspend fun getSupportedCountries(): List<String> { val countries = appConfigProvider.getAppConfig().supportedCountries return when { @@ -78,12 +101,6 @@ class SubmissionTask @Inject constructor( isCanceled = true } - class Arguments( - val registrationToken: String, - val keys: List<TemporaryExposureKey>, - val symptoms: Symptoms - ) : Task.Arguments - data class Config( override val executionTimeout: Duration = Duration.standardMinutes(8), // TODO unit-test that not > 9 min diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/Symptoms.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/Symptoms.kt index 0743eb1aaa05b52dccde5cde3b2f29e057bded17..db2daf4f590d4753998ebdaaa1e33bf0b015f816 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/Symptoms.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/Symptoms.kt @@ -1,6 +1,7 @@ package de.rki.coronawarnapp.submission import android.os.Parcelable +import com.google.gson.annotations.SerializedName import kotlinx.android.parcel.Parcelize import org.joda.time.LocalDate @@ -18,22 +19,43 @@ data class Symptoms( data class Date(val date: LocalDate) : StartOf() @Parcelize - object LastSevenDays : StartOf() + object LastSevenDays : StartOf() { + override fun equals(other: Any?): Boolean = other is LastSevenDays + + override fun hashCode(): Int = System.identityHashCode(this) + } @Parcelize - object OneToTwoWeeksAgo : StartOf() + object OneToTwoWeeksAgo : StartOf() { + override fun equals(other: Any?): Boolean = other is OneToTwoWeeksAgo + + override fun hashCode(): Int = System.identityHashCode(this) + } @Parcelize - object MoreThanTwoWeeks : StartOf() + object MoreThanTwoWeeks : StartOf() { + override fun equals(other: Any?): Boolean = other is MoreThanTwoWeeks + + override fun hashCode(): Int = System.identityHashCode(this) + } @Parcelize - object NoInformation : StartOf() + object NoInformation : StartOf() { + override fun equals(other: Any?): Boolean = other is NoInformation + + override fun hashCode(): Int = System.identityHashCode(this) + } } @Parcelize enum class Indication : Parcelable { + @SerializedName("POSITIVE") POSITIVE, + + @SerializedName("NEGATIVE") NEGATIVE, + + @SerializedName("NO_INFORMATION") NO_INFORMATION } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/data/tekhistory/TEKHistoryStorage.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/data/tekhistory/TEKHistoryStorage.kt new file mode 100644 index 0000000000000000000000000000000000000000..9559e76051fe03a07c6709a46c6d205cb843a123 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/data/tekhistory/TEKHistoryStorage.kt @@ -0,0 +1,73 @@ +package de.rki.coronawarnapp.submission.data.tekhistory + +import android.database.sqlite.SQLiteConstraintException +import androidx.room.withTransaction +import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey +import de.rki.coronawarnapp.submission.data.tekhistory.internal.TEKEntryDao +import de.rki.coronawarnapp.submission.data.tekhistory.internal.TEKHistoryDatabase +import de.rki.coronawarnapp.submission.data.tekhistory.internal.toPersistedTEK +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import okio.ByteString.Companion.toByteString +import org.joda.time.Instant +import timber.log.Timber +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class TEKHistoryStorage @Inject constructor( + private val tekHistoryDatabaseFactory: TEKHistoryDatabase.Factory +) { + + private val database by lazy { tekHistoryDatabaseFactory.create() } + private val tekHistoryTables by lazy { database.tekHistory() } + + suspend fun storeTEKData(data: TEKBatch) = database.withTransaction { + data.keys.forEach { + val id = it.keyData.toByteString().base64() + val newEntry = TEKEntryDao( + id = id, + batchId = data.batchId, + obtainedAt = data.obtainedAt, + persistedTEK = it.toPersistedTEK() + ) + Timber.tag(TAG).v("Inserting TEK: %s", newEntry) + try { + tekHistoryTables.insertEntry(newEntry) + } catch (e: SQLiteConstraintException) { + Timber.i(e, "TEK is already stored: %s", id) + } + } + } + + val tekData: Flow<List<TEKBatch>> by lazy { + tekHistoryTables.allEntries().map { tekDaos -> + val batches = mutableMapOf<String, List<TEKEntryDao>>() + tekDaos.forEach { tekDao -> + batches[tekDao.batchId] = batches.getOrPut(tekDao.batchId) { emptyList() }.plus(tekDao) + } + batches.values.map { batchTEKs -> + TEKBatch( + batchId = batchTEKs.first().batchId, + obtainedAt = batchTEKs.first().obtainedAt, + keys = batchTEKs.map { it.persistedTEK.toTemporaryExposureKey() } + ) + }.toList() + } + } + + suspend fun clear() { + Timber.w("clear() - Clearing all stored temporary exposure keys.") + database.clearAllTables() + } + + data class TEKBatch( + val obtainedAt: Instant, + val batchId: String, + val keys: List<TemporaryExposureKey> + ) + + companion object { + private const val TAG = "TEKHistoryStorage" + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/data/tekhistory/TEKHistoryUpdater.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/data/tekhistory/TEKHistoryUpdater.kt new file mode 100644 index 0000000000000000000000000000000000000000..2810ba4d6b7c14abea6c96af342cd539f7601c9d --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/data/tekhistory/TEKHistoryUpdater.kt @@ -0,0 +1,116 @@ +package de.rki.coronawarnapp.submission.data.tekhistory + +import android.app.Activity +import android.content.Intent +import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey +import de.rki.coronawarnapp.exception.ExceptionCategory +import de.rki.coronawarnapp.exception.reporting.report +import de.rki.coronawarnapp.nearby.ENFClient +import de.rki.coronawarnapp.util.TimeStamper +import de.rki.coronawarnapp.util.coroutine.AppScope +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.async +import kotlinx.coroutines.launch +import timber.log.Timber +import java.util.UUID +import javax.inject.Inject + +class TEKHistoryUpdater @Inject constructor( + private val tekHistoryStorage: TEKHistoryStorage, + private val timeStamper: TimeStamper, + private val enfClient: ENFClient, + @AppScope private val scope: CoroutineScope +) { + + var callback: Callback? = null + + fun updateTEKHistoryOrRequestPermission( + onUserPermissionRequired: (permissionRequest: (Activity) -> Unit) -> Unit + ) { + scope.launch { + enfClient.getTEKHistoryOrRequestPermission( + onTEKHistoryAvailable = { + updateHistoryAndTriggerCallback() + }, + onPermissionRequired = { status -> + val permissionRequestTrigger: (Activity) -> Unit = { + status.startResolutionForResult(it, TEK_PERMISSION_REQUESTCODE) + } + onUserPermissionRequired(permissionRequestTrigger) + } + ) + } + } + + suspend fun updateHistoryOrThrow(): List<TemporaryExposureKey> { + return updateTEKHistory() + } + + fun handleActivityResult(requestCode: Int, resultCode: Int, data: Intent?): UpdateResult { + if (requestCode != TEK_PERMISSION_REQUESTCODE) { + Timber.tag(TAG).w("Not our request code ($requestCode): %s", data) + return UpdateResult.UNKNOWN_RESULT + } + return if (resultCode == Activity.RESULT_OK) { + Timber.tag(TAG).w("Permission granted (== RESULT_OK): %s", data) + updateHistoryAndTriggerCallback() + UpdateResult.PERMISSION_AVAILABLE + } else { + Timber.tag(TAG).w("Permission declined (!= RESULT_OK): %s", data) + callback?.onPermissionDeclined() + UpdateResult.PERMISSION_UNAVAILABLE + } + } + + private fun updateHistoryAndTriggerCallback() { + scope.launch { + try { + val result = updateTEKHistory() + callback?.onTEKAvailable(result) + } catch (e: Exception) { + callback?.onError(e) + } + } + } + + private suspend fun updateTEKHistory(): List<TemporaryExposureKey> { + val deferred = scope.async { + val teks = enfClient.getTEKHistory() + Timber.i("Permission are available, storing TEK history.") + + tekHistoryStorage.storeTEKData( + TEKHistoryStorage.TEKBatch( + batchId = UUID.randomUUID().toString(), + obtainedAt = timeStamper.nowUTC, + keys = teks + ) + ) + + teks + } + return try { + deferred.await() + } catch (e: Exception) { + Timber.tag(TAG).e(e, "Positive permission result but failed to update history?") + e.report(ExceptionCategory.EXPOSURENOTIFICATION, TAG, null) + throw e + } + } + + enum class UpdateResult { + PERMISSION_AVAILABLE, + PERMISSION_UNAVAILABLE, + UNKNOWN_RESULT + } + + companion object { + private const val TAG = "TEKHistoryUpdater" + const val TEK_PERMISSION_REQUESTCODE = 3011 + } + + interface Callback { + fun onTEKAvailable(teks: List<TemporaryExposureKey>) + fun onPermissionDeclined() + fun onError(error: Throwable) + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/data/tekhistory/internal/TEKEntryDao.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/data/tekhistory/internal/TEKEntryDao.kt new file mode 100644 index 0000000000000000000000000000000000000000..8593f4b585c98065ef88554dd6045e903d609846 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/data/tekhistory/internal/TEKEntryDao.kt @@ -0,0 +1,73 @@ +package de.rki.coronawarnapp.submission.data.tekhistory.internal + +import androidx.room.ColumnInfo +import androidx.room.Embedded +import androidx.room.Entity +import androidx.room.PrimaryKey +import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey +import org.joda.time.Instant + +@Entity(tableName = "tek_history") +data class TEKEntryDao( + @PrimaryKey @ColumnInfo(name = "id") val id: String, + @ColumnInfo(name = "batchId") val batchId: String, + @ColumnInfo(name = "obtainedAt") val obtainedAt: Instant, + @Embedded val persistedTEK: PersistedTEK +) { + + data class PersistedTEK( + @ColumnInfo(name = "keyData") val keyData: ByteArray, + @ColumnInfo(name = "rollingStartIntervalNumber") val rollingStartIntervalNumber: Int, + @ColumnInfo(name = "transmissionRiskLevel") val transmissionRiskLevel: Int, + @ColumnInfo(name = "rollingPeriod") val rollingPeriod: Int, + @ColumnInfo(name = "reportType") val reportType: Int, + @ColumnInfo(name = "daysSinceOnsetOfSymptoms") val daysSinceOnsetOfSymptoms: Int + ) { + + fun toTemporaryExposureKey(): TemporaryExposureKey = TemporaryExposureKey.TemporaryExposureKeyBuilder().apply { + setKeyData(keyData) + setRollingStartIntervalNumber(rollingStartIntervalNumber) + setTransmissionRiskLevel(transmissionRiskLevel) + setRollingPeriod(rollingPeriod) + setReportType(reportType) + if (daysSinceOnsetOfSymptoms != TemporaryExposureKey.DAYS_SINCE_ONSET_OF_SYMPTOMS_UNKNOWN) { + setDaysSinceOnsetOfSymptoms(daysSinceOnsetOfSymptoms) + } + }.build() + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as PersistedTEK + + if (!keyData.contentEquals(other.keyData)) return false + if (rollingStartIntervalNumber != other.rollingStartIntervalNumber) return false + if (transmissionRiskLevel != other.transmissionRiskLevel) return false + if (rollingPeriod != other.rollingPeriod) return false + if (reportType != other.reportType) return false + if (daysSinceOnsetOfSymptoms != other.daysSinceOnsetOfSymptoms) return false + + return true + } + + override fun hashCode(): Int { + var result = keyData.contentHashCode() + result = 31 * result + rollingStartIntervalNumber + result = 31 * result + transmissionRiskLevel + result = 31 * result + rollingPeriod + result = 31 * result + reportType + result = 31 * result + daysSinceOnsetOfSymptoms + return result + } + } +} + +fun TemporaryExposureKey.toPersistedTEK() = TEKEntryDao.PersistedTEK( + keyData = this.keyData, + rollingStartIntervalNumber = this.rollingStartIntervalNumber, + transmissionRiskLevel = this.transmissionRiskLevel, + rollingPeriod = this.rollingPeriod, + reportType = this.reportType, + daysSinceOnsetOfSymptoms = this.daysSinceOnsetOfSymptoms +) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/data/tekhistory/internal/TEKHistoryDatabase.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/data/tekhistory/internal/TEKHistoryDatabase.kt new file mode 100644 index 0000000000000000000000000000000000000000..931714c0c771d6f863bbdbfbde950c85d780e0da --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/data/tekhistory/internal/TEKHistoryDatabase.kt @@ -0,0 +1,58 @@ +package de.rki.coronawarnapp.submission.data.tekhistory.internal + +import android.content.Context +import androidx.room.Dao +import androidx.room.Database +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import androidx.room.Room +import androidx.room.RoomDatabase +import androidx.room.Transaction +import androidx.room.TypeConverters +import de.rki.coronawarnapp.util.database.CommonConverters +import de.rki.coronawarnapp.util.di.AppContext +import kotlinx.coroutines.flow.Flow +import timber.log.Timber +import javax.inject.Inject + +@Suppress("MaxLineLength") +@Database( + entities = [ + TEKEntryDao::class + ], + version = 1, + exportSchema = true +) +@TypeConverters( + CommonConverters::class +) +abstract class TEKHistoryDatabase : RoomDatabase() { + + abstract fun tekHistory(): TEKHistoryDao + + @Dao + interface TEKHistoryDao { + @Transaction + @Query("SELECT * FROM tek_history") + fun allEntries(): Flow<List<TEKEntryDao>> + + @Insert(onConflict = OnConflictStrategy.ABORT) + suspend fun insertEntry(riskResultDao: TEKEntryDao) + } + + class Factory @Inject constructor(@AppContext private val context: Context) { + + fun create(): TEKHistoryDatabase { + Timber.d("Instantiating temporary exposure key history database.") + return Room + .databaseBuilder(context, TEKHistoryDatabase::class.java, DATABASE_NAME) + .fallbackToDestructiveMigrationFrom() + .build() + } + } + + companion object { + private const val DATABASE_NAME = "temporary_exposure_keys.db" + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/task/TaskController.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/task/TaskController.kt index 6db01b71292562462a2db3d0cd7202e68f772f29..eb6c8aab8c7527e6c9dc8d1e6250c98fa16ec7d8 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/task/TaskController.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/task/TaskController.kt @@ -205,11 +205,16 @@ class TaskController @Inject constructor( // Handle collision behavior for tasks of same type when { + !arePreconditionsMet -> { + Timber.tag(TAG).d("Preconditions are not met, skipping: %s", state) + workMap[state.id] = state.toSkippedState() + } siblingTasks.isEmpty() -> { + Timber.tag(TAG).d("No siblings exists, running: %s", state) workMap[state.id] = state.toRunningState() } - !arePreconditionsMet || - state.config.collisionBehavior == CollisionBehavior.SKIP_IF_SIBLING_RUNNING -> { + state.config.collisionBehavior == CollisionBehavior.SKIP_IF_SIBLING_RUNNING -> { + Timber.tag(TAG).d("Siblings exists, skipping according to collision behavior: %s", state) workMap[state.id] = state.toSkippedState() } state.config.collisionBehavior == CollisionBehavior.ENQUEUE -> { diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragment.kt index 18bffeac946353d8c4779d4b3f9405c5a7ebea94..887906299d153167153daa3dc00515840f5a77f8 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragment.kt @@ -11,7 +11,6 @@ import de.rki.coronawarnapp.util.DialogHelper import de.rki.coronawarnapp.util.ExternalActionHelper import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.errors.RecoveryByResetDialogFactory -import de.rki.coronawarnapp.util.network.NetworkStateProvider import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.viewBindingLazy @@ -36,7 +35,6 @@ class HomeFragment : Fragment(R.layout.fragment_home), AutoInject { @Inject lateinit var homeMenu: HomeMenu @Inject lateinit var tracingExplanationDialog: TracingExplanationDialog - @Inject lateinit var networkStateProvider: NetworkStateProvider override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -140,9 +138,7 @@ class HomeFragment : Fragment(R.layout.fragment_home), AutoInject { private fun setupTestResultCard() { binding.apply { - val toSubmissionResult = { - doNavigate(HomeFragmentDirections.actionMainFragmentToSubmissionResultFragment()) - } + mainTestUnregistered.apply { val toSubmissionDispatcher = { doNavigate(HomeFragmentDirections.actionMainFragmentToSubmissionDispatcher()) @@ -151,17 +147,24 @@ class HomeFragment : Fragment(R.layout.fragment_home), AutoInject { submissionStatusCardUnregisteredButton.setOnClickListener { toSubmissionDispatcher() } } - mainTestDone.submissionStatusCardDone.setOnClickListener { - doNavigate(HomeFragmentDirections.actionMainFragmentToSubmissionDoneFragment()) - } + // Test is negative mainTestResult.apply { + val toSubmissionResult = { + doNavigate(HomeFragmentDirections.actionMainFragmentToSubmissionResultFragment()) + } submissionStatusCardContent.setOnClickListener { toSubmissionResult() } submissionStatusCardContentButton.setOnClickListener { toSubmissionResult() } } - + // Test is positive mainTestPositive.apply { - submissionStatusCardPositive.setOnClickListener { toSubmissionResult() } - submissionStatusCardPositiveButton.setOnClickListener { toSubmissionResult() } + val toConsentScreen = { + doNavigate( + HomeFragmentDirections + .actionMainFragmentToSubmissionResultPositiveOtherWarningNoConsentFragment() + ) + } + submissionStatusCardPositive.setOnClickListener { toConsentScreen() } + submissionStatusCardPositiveButton.setOnClickListener { toConsentScreen() } } mainTestFailed.apply { diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingTracingFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingTracingFragment.kt index 3967ad69621fc9230467a0d3503ee62bc3987fc3..813163ef4a9fb5ff246c4f780e9e9e3ffd288929 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingTracingFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingTracingFragment.kt @@ -4,16 +4,13 @@ import android.content.Intent import android.os.Bundle import android.view.View import android.view.accessibility.AccessibilityEvent -import androidx.appcompat.app.AlertDialog import androidx.fragment.app.Fragment import androidx.navigation.fragment.findNavController import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentOnboardingTracingBinding -import de.rki.coronawarnapp.nearby.InternalExposureNotificationPermissionHelper import de.rki.coronawarnapp.ui.doNavigate import de.rki.coronawarnapp.util.DialogHelper import de.rki.coronawarnapp.util.di.AutoInject -import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.viewBindingLazy import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider @@ -22,32 +19,14 @@ import javax.inject.Inject /** * This fragment ask the user if he wants to enable tracing. - * - * @see InternalExposureNotificationPermissionHelper - * @see AlertDialog */ -class OnboardingTracingFragment : Fragment(R.layout.fragment_onboarding_tracing), - InternalExposureNotificationPermissionHelper.Callback, AutoInject { +class OnboardingTracingFragment : Fragment(R.layout.fragment_onboarding_tracing), AutoInject { - private lateinit var internalExposureNotificationPermissionHelper: InternalExposureNotificationPermissionHelper private val binding: FragmentOnboardingTracingBinding by viewBindingLazy() @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val vm: OnboardingTracingFragmentViewModel by cwaViewModels { viewModelFactory } - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - internalExposureNotificationPermissionHelper.onResolutionComplete( - requestCode, - resultCode - ) - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - internalExposureNotificationPermissionHelper = - InternalExposureNotificationPermissionHelper(this, this) - } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) vm.countryList.observe2(this) { @@ -55,23 +34,22 @@ class OnboardingTracingFragment : Fragment(R.layout.fragment_onboarding_tracing) } vm.saveInteroperabilityUsed() binding.apply { - onboardingButtonNext.setOnClickListener { vm.onNextButtonClick() } + onboardingButtonNext.setOnClickListener { vm.onActivateTracingClicked() } onboardingButtonDisable.setOnClickListener { vm.showCancelDialog() } onboardingButtonBack.buttonIcon.setOnClickListener { vm.onBackButtonPress() } } vm.routeToScreen.observe2(this) { when (it) { - is OnboardingNavigationEvents.NavigateToOnboardingTest -> - internalExposureNotificationPermissionHelper.requestPermissionToStartTracing() + is OnboardingNavigationEvents.NavigateToOnboardingTest -> navigateToOnboardingTestFragment() is OnboardingNavigationEvents.ShowCancelDialog -> DialogHelper.showDialog(DialogHelper.DialogInstance( - requireActivity(), - R.string.onboarding_tracing_dialog_headline, - R.string.onboarding_tracing_dialog_body, - R.string.onboarding_tracing_dialog_button_positive, - R.string.onboarding_tracing_dialog_button_negative, - true, - { + context = requireActivity(), + title = R.string.onboarding_tracing_dialog_headline, + message = R.string.onboarding_tracing_dialog_body, + positiveButton = R.string.onboarding_tracing_dialog_button_positive, + negativeButton = R.string.onboarding_tracing_dialog_button_negative, + cancelable = true, + positiveButtonFunction = { navigateToOnboardingTestFragment() } )) @@ -79,6 +57,9 @@ class OnboardingTracingFragment : Fragment(R.layout.fragment_onboarding_tracing) (requireActivity() as OnboardingActivity).goBack() } } + vm.permissionRequestEvent.observe2(this) { permissionRequest -> + permissionRequest.invoke(requireActivity()) + } } override fun onResume() { @@ -87,12 +68,8 @@ class OnboardingTracingFragment : Fragment(R.layout.fragment_onboarding_tracing) vm.resetTracing() } - override fun onStartPermissionGranted() { - navigateToOnboardingTestFragment() - } - - override fun onFailure(exception: Exception?) { - // dialog closed, user has to explicitly allow or deny the tracing permission + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + vm.handleActivityResult(requestCode, resultCode, data) } private fun navigateToOnboardingTestFragment() { diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingTracingFragmentViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingTracingFragmentViewModel.kt index a710675c0b0b106baf0222a0ccc1355063e5c3ec..ad4d8e2808078116ea7f8be6538055d29e176fb4 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingTracingFragmentViewModel.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingTracingFragmentViewModel.kt @@ -1,21 +1,42 @@ package de.rki.coronawarnapp.ui.onboarding +import android.app.Activity +import android.content.Intent +import androidx.lifecycle.asLiveData import com.squareup.inject.assisted.AssistedInject import de.rki.coronawarnapp.exception.ExceptionCategory import de.rki.coronawarnapp.exception.reporting.report import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient +import de.rki.coronawarnapp.nearby.TracingPermissionHelper import de.rki.coronawarnapp.storage.LocalData import de.rki.coronawarnapp.storage.interoperability.InteroperabilityRepository import de.rki.coronawarnapp.ui.SingleLiveEvent import de.rki.coronawarnapp.util.viewmodel.CWAViewModel import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory +import timber.log.Timber class OnboardingTracingFragmentViewModel @AssistedInject constructor( - private val interoperabilityRepository: InteroperabilityRepository + private val interoperabilityRepository: InteroperabilityRepository, + private val tracingPermissionHelper: TracingPermissionHelper ) : CWAViewModel() { - val countryList = interoperabilityRepository.countryList + val countryList = interoperabilityRepository.countryListFlow.asLiveData() val routeToScreen: SingleLiveEvent<OnboardingNavigationEvents> = SingleLiveEvent() + val permissionRequestEvent = SingleLiveEvent<(Activity) -> Unit>() + + init { + tracingPermissionHelper.callback = object : TracingPermissionHelper.Callback { + override fun onUpdateTracingStatus(isTracingEnabled: Boolean) { + if (isTracingEnabled) { + routeToScreen.postValue(OnboardingNavigationEvents.NavigateToOnboardingTest) + } + } + + override fun onError(error: Throwable) { + Timber.e(error, "Failed to activate tracing during onboarding.") + } + } + } fun saveInteroperabilityUsed() { interoperabilityRepository.saveInteroperabilityUsed() @@ -40,8 +61,10 @@ class OnboardingTracingFragmentViewModel @AssistedInject constructor( } } - fun onNextButtonClick() { - routeToScreen.postValue(OnboardingNavigationEvents.NavigateToOnboardingTest) + fun onActivateTracingClicked() { + tracingPermissionHelper.startTracing { permissionRequest -> + permissionRequestEvent.postValue(permissionRequest) + } } fun showCancelDialog() { @@ -52,6 +75,10 @@ class OnboardingTracingFragmentViewModel @AssistedInject constructor( routeToScreen.postValue(OnboardingNavigationEvents.NavigateToOnboardingPrivacy) } + fun handleActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + tracingPermissionHelper.handleActivityResult(requestCode, resultCode, data) + } + @AssistedInject.Factory interface Factory : SimpleCWAViewModelFactory<OnboardingTracingFragmentViewModel> diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionBlockingDialog.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionBlockingDialog.kt new file mode 100644 index 0000000000000000000000000000000000000000..7fe93abaae4e577d300d7b1d3f2d07764c8a416d --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionBlockingDialog.kt @@ -0,0 +1,25 @@ +package de.rki.coronawarnapp.ui.submission + +import android.content.Context +import androidx.appcompat.app.AlertDialog +import de.rki.coronawarnapp.R + +class SubmissionBlockingDialog( + val context: Context +) { + + private val dialog by lazy { + AlertDialog.Builder(context).apply { + setCancelable(false) + setView(R.layout.submission_blocking_dialog_view) + }.create() + } + + fun setState(show: Boolean) { + if (show && !dialog.isShowing) { + dialog.show() + } else if (!show && dialog.isShowing) { + dialog.dismiss() + } + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionCancelDialog.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionCancelDialog.kt new file mode 100644 index 0000000000000000000000000000000000000000..b1bce78678fe53bc31b5b6c6ab2c588af97f2340 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionCancelDialog.kt @@ -0,0 +1,22 @@ +package de.rki.coronawarnapp.ui.submission + +import android.content.Context +import androidx.appcompat.app.AlertDialog +import de.rki.coronawarnapp.R + +class SubmissionCancelDialog( + val context: Context +) { + fun show(onUserDidCancel: () -> Unit) { + AlertDialog.Builder(context).apply { + setTitle(R.string.submission_error_dialog_confirm_cancellation_title) + setMessage(R.string.submission_error_dialog_confirm_cancellation_body) + setPositiveButton(R.string.submission_error_dialog_confirm_cancellation_button_positive) { _, _ -> + onUserDidCancel() + } + setNegativeButton(R.string.submission_error_dialog_confirm_cancellation_button_negative) { _, _ -> + // NOOP + } + }.show() + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/fragment/SubmissionDoneFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/fragment/SubmissionDoneFragment.kt deleted file mode 100644 index b209cef7275df15d89b92e9ef09a36a168c8192c..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/fragment/SubmissionDoneFragment.kt +++ /dev/null @@ -1,55 +0,0 @@ -package de.rki.coronawarnapp.ui.submission.fragment - -import android.os.Bundle -import android.view.View -import android.view.accessibility.AccessibilityEvent -import androidx.fragment.app.Fragment -import de.rki.coronawarnapp.R -import de.rki.coronawarnapp.databinding.FragmentSubmissionDoneBinding -import de.rki.coronawarnapp.ui.submission.viewmodel.SubmissionDoneViewModel -import de.rki.coronawarnapp.ui.submission.viewmodel.SubmissionNavigationEvents -import de.rki.coronawarnapp.util.di.AutoInject -import de.rki.coronawarnapp.util.ui.doNavigate -import de.rki.coronawarnapp.util.ui.observe2 -import de.rki.coronawarnapp.util.ui.viewBindingLazy -import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider -import de.rki.coronawarnapp.util.viewmodel.cwaViewModels -import javax.inject.Inject - -/** - * The [SubmissionDoneFragment] displays information to a user that submitted his exposure keys - */ -class SubmissionDoneFragment : Fragment(R.layout.fragment_submission_done), AutoInject { - - @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory - private val viewModel: SubmissionDoneViewModel by cwaViewModels { viewModelFactory } - private val binding: FragmentSubmissionDoneBinding by viewBindingLazy() - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - setButtonOnClickListener() - - viewModel.routeToScreen.observe2(this) { - when (it) { - is SubmissionNavigationEvents.NavigateToMainActivity -> - doNavigate( - SubmissionDoneFragmentDirections.actionSubmissionDoneFragmentToMainFragment() - ) - } - } - } - - override fun onResume() { - super.onResume() - binding.submissionDoneContainer.sendAccessibilityEvent(AccessibilityEvent.TYPE_ANNOUNCEMENT) - } - - private fun setButtonOnClickListener() { - binding.submissionDoneHeader.headerButtonBack.buttonIcon.setOnClickListener { - viewModel.onBackPressed() - } - binding.submissionDoneButtonDone.setOnClickListener { - viewModel.onDonePressed() - } - } -} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/qrcode/scan/SubmissionQRCodeScanFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/qrcode/scan/SubmissionQRCodeScanFragment.kt index 28b89d5b7b97d2bf0a12862e26d4f187743b4413..5f502109501b9d6f36177d5faad92f8457a11213 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/qrcode/scan/SubmissionQRCodeScanFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/qrcode/scan/SubmissionQRCodeScanFragment.kt @@ -21,6 +21,7 @@ import de.rki.coronawarnapp.ui.submission.viewmodel.SubmissionNavigationEvents import de.rki.coronawarnapp.util.CameraPermissionHelper import de.rki.coronawarnapp.util.DialogHelper import de.rki.coronawarnapp.util.di.AutoInject +import de.rki.coronawarnapp.util.formatter.TestResult import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.viewBindingLazy @@ -76,16 +77,23 @@ class SubmissionQRCodeScanFragment : Fragment(R.layout.fragment_submission_qr_co goBack() } - viewModel.registrationState.observe2(this) { - binding.submissionQrCodeScanSpinner.visibility = when (it) { + viewModel.registrationState.observe2(this) { state -> + binding.submissionQrCodeScanSpinner.visibility = when (state.apiRequestState) { ApiRequestState.STARTED -> View.VISIBLE else -> View.GONE } - if (ApiRequestState.SUCCESS == it) { - doNavigate( - SubmissionQRCodeScanFragmentDirections - .actionSubmissionQRCodeScanFragmentToSubmissionResultFragment() - ) + if (ApiRequestState.SUCCESS == state.apiRequestState) { + if (state.testResult == TestResult.POSITIVE) { + doNavigate( + SubmissionQRCodeScanFragmentDirections + .actionSubmissionQRCodeScanFragmentToSubmissionTestResultAvailableFragment() + ) + } else { + doNavigate( + SubmissionQRCodeScanFragmentDirections + .actionSubmissionQRCodeScanFragmentToSubmissionResultFragment() + ) + } } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/qrcode/scan/SubmissionQRCodeScanViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/qrcode/scan/SubmissionQRCodeScanViewModel.kt index 0a282b83e5b17559986880e23ab8875b30d042c1..3ab5e07acd497640c9539227c2d1a476abb00507 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/qrcode/scan/SubmissionQRCodeScanViewModel.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/qrcode/scan/SubmissionQRCodeScanViewModel.kt @@ -22,7 +22,7 @@ class SubmissionQRCodeScanViewModel @AssistedInject constructor( private val submissionRepository: SubmissionRepository ) : CWAViewModel() { - val routeToScreen: SingleLiveEvent<SubmissionNavigationEvents> = SingleLiveEvent() + val routeToScreen = SingleLiveEvent<SubmissionNavigationEvents>() val showRedeemedTokenWarning = SingleLiveEvent<Unit>() val scanStatusValue = SingleLiveEvent<ScanStatus>() @@ -38,16 +38,22 @@ class SubmissionQRCodeScanViewModel @AssistedInject constructor( } } - val registrationState = MutableLiveData(ApiRequestState.IDLE) + val registrationState = MutableLiveData(RegistrationState(ApiRequestState.IDLE)) val registrationError = SingleLiveEvent<CwaWebException>() + data class RegistrationState( + val apiRequestState: ApiRequestState, + val testResult: TestResult? = null + ) + private fun doDeviceRegistration(scanResult: QRScanResult) = launch { try { - registrationState.postValue(ApiRequestState.STARTED) - checkTestResult(submissionRepository.asyncRegisterDeviceViaGUID(scanResult.guid!!)) - registrationState.postValue(ApiRequestState.SUCCESS) + registrationState.postValue(RegistrationState(ApiRequestState.STARTED)) + val testResult = submissionRepository.asyncRegisterDeviceViaGUID(scanResult.guid!!) + checkTestResult(testResult) + registrationState.postValue(RegistrationState(ApiRequestState.SUCCESS, testResult)) } catch (err: CwaWebException) { - registrationState.postValue(ApiRequestState.FAILED) + registrationState.postValue(RegistrationState(ApiRequestState.FAILED)) registrationError.postValue(err) } catch (err: TransactionException) { if (err.cause is CwaWebException) { @@ -55,13 +61,13 @@ class SubmissionQRCodeScanViewModel @AssistedInject constructor( } else { err.report(ExceptionCategory.INTERNAL) } - registrationState.postValue(ApiRequestState.FAILED) + registrationState.postValue(RegistrationState(ApiRequestState.FAILED)) } catch (err: InvalidQRCodeException) { - registrationState.postValue(ApiRequestState.FAILED) + registrationState.postValue(RegistrationState(ApiRequestState.FAILED)) deregisterTestFromDevice() showRedeemedTokenWarning.postValue(Unit) } catch (err: Exception) { - registrationState.postValue(ApiRequestState.FAILED) + registrationState.postValue(RegistrationState(ApiRequestState.FAILED)) err.report(ExceptionCategory.INTERNAL) } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultavailable/SubmissionTestResultAvailableEvents.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultavailable/SubmissionTestResultAvailableEvents.kt index 53c5cf329657e7756a1f1a15c1853ead2dca11e0..ad61e5426a4a561847660e539a9aff9cda90cd74 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultavailable/SubmissionTestResultAvailableEvents.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultavailable/SubmissionTestResultAvailableEvents.kt @@ -3,5 +3,5 @@ package de.rki.coronawarnapp.ui.submission.resultavailable sealed class SubmissionTestResultAvailableEvents { object GoBack : SubmissionTestResultAvailableEvents() object GoConsent : SubmissionTestResultAvailableEvents() - object Proceed : SubmissionTestResultAvailableEvents() + object GoToTestResult : SubmissionTestResultAvailableEvents() } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultavailable/SubmissionTestResultAvailableFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultavailable/SubmissionTestResultAvailableFragment.kt index 7e755156787faf3c70c1c309fca31f26b31cb728..5c4575484805518b84bffd947c99964dc1fdf741 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultavailable/SubmissionTestResultAvailableFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultavailable/SubmissionTestResultAvailableFragment.kt @@ -1,13 +1,16 @@ package de.rki.coronawarnapp.ui.submission.resultavailable +import android.content.Intent import android.os.Bundle import android.view.View import android.view.accessibility.AccessibilityEvent +import androidx.activity.OnBackPressedCallback import androidx.fragment.app.Fragment import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentSubmissionTestResultAvailableBinding import de.rki.coronawarnapp.util.DialogHelper import de.rki.coronawarnapp.util.di.AutoInject +import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.viewBindingLazy import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider @@ -23,31 +26,46 @@ class SubmissionTestResultAvailableFragment : Fragment(R.layout.fragment_submiss override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + val backCallback = object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() = vm.goBack() + } + requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, backCallback) + vm.consent.observe2(this) { if (it) { binding.submissionTestResultAvailableText.setText( - R.string.submission_test_result_available_text_consent_given) + R.string.submission_test_result_available_text_consent_given + ) } else { binding.submissionTestResultAvailableText.setText( - R.string.submission_test_result_available_text_consent_not_given) + R.string.submission_test_result_available_text_consent_not_given + ) } binding.submissionTestResultAvailableConsentStatus.consent = it } binding.apply { submissionTestResultAvailableProceedButton.setOnClickListener { vm.proceed() } - submissionTestResultAvailableHeader.headerButtonBack.buttonIcon.setOnClickListener { vm.goBack() } submissionTestResultAvailableConsentStatus.setOnClickListener { vm.goConsent() } + submissionTestResultAvailableHeader.headerButtonBack.buttonIcon.setOnClickListener { vm.goBack() } } - vm.clickEvent.observe2(this) { - when (it) { - is SubmissionTestResultAvailableEvents.GoBack -> showCloseDialog() - // TODO: Add navigation - // is SubmissionTestResultAvailableEvents.GoConsent -> doNavigate(TestResultAvailableFragmentDirections.actionTestResultAvailableToSubmissionYourConsent()) - is SubmissionTestResultAvailableEvents.Proceed -> showProceedPopUp() - } + vm.showCloseDialog.observe2(this) { + showCloseDialog() } + + vm.routeToScreen.observe2(this) { + doNavigate(it) + } + + vm.showPermissionRequest.observe2(this) { permissionRequest -> + permissionRequest.invoke(requireActivity()) + } + } + + override fun onResume() { + super.onResume() + binding.submissionTestResultAvailableContainer.sendAccessibilityEvent(AccessibilityEvent.TYPE_ANNOUNCEMENT) } private fun showCloseDialog() { @@ -60,27 +78,19 @@ class SubmissionTestResultAvailableFragment : Fragment(R.layout.fragment_submiss } val closeDialogInstance = DialogHelper.DialogInstance( - requireActivity(), - dialogTitle, - dialogBody, - R.string.submission_test_result_available_close_dialog_continue_button, - R.string.submission_test_result_available_close_dialog_cancel_button, - true, { - // TODO: Add navigation - // doNavigate(TestResultAvailableFragmentDirections.actionTestResultAvailableToMainFragment()) - }, { - // Do nothing - } + context = requireActivity(), + title = dialogTitle, + message = dialogBody, + positiveButton = R.string.submission_test_result_available_close_dialog_continue_button, + negativeButton = R.string.submission_test_result_available_close_dialog_cancel_button, + cancelable = true, + positiveButtonFunction = { vm.onCancelConfirmed() }, + negativeButtonFunction = { } ) DialogHelper.showDialog(closeDialogInstance) } - private fun showProceedPopUp() { - // TODO: Show proceed pop up with further navigation - } - - override fun onResume() { - super.onResume() - binding.submissionTestResultAvailableContainer.sendAccessibilityEvent(AccessibilityEvent.TYPE_ANNOUNCEMENT) + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + vm.handleActivityResult(requestCode, resultCode, data) } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultavailable/SubmissionTestResultAvailableViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultavailable/SubmissionTestResultAvailableViewModel.kt index d7776d82d1733775fc6ec9dd81795dab269edc55..4a43adf71c50153e7eb75364f5e6e03040fd52b9 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultavailable/SubmissionTestResultAvailableViewModel.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultavailable/SubmissionTestResultAvailableViewModel.kt @@ -1,32 +1,98 @@ package de.rki.coronawarnapp.ui.submission.resultavailable +import android.app.Activity +import android.content.Intent import androidx.lifecycle.asLiveData +import androidx.navigation.NavDirections +import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey import com.squareup.inject.assisted.AssistedInject +import de.rki.coronawarnapp.exception.ExceptionCategory +import de.rki.coronawarnapp.exception.reporting.report import de.rki.coronawarnapp.storage.SubmissionRepository +import de.rki.coronawarnapp.submission.data.tekhistory.TEKHistoryUpdater import de.rki.coronawarnapp.ui.SingleLiveEvent import de.rki.coronawarnapp.util.coroutine.DispatcherProvider import de.rki.coronawarnapp.util.viewmodel.CWAViewModel import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory +import kotlinx.coroutines.flow.first +import timber.log.Timber class SubmissionTestResultAvailableViewModel @AssistedInject constructor( dispatcherProvider: DispatcherProvider, - submissionRepository: SubmissionRepository + private val tekHistoryUpdater: TEKHistoryUpdater, + private val submissionRepository: SubmissionRepository ) : CWAViewModel(dispatcherProvider = dispatcherProvider) { - val clickEvent: SingleLiveEvent<SubmissionTestResultAvailableEvents> = SingleLiveEvent() + val routeToScreen = SingleLiveEvent<NavDirections>() - val consent = submissionRepository.hasGivenConsentToSubmission.asLiveData(dispatcherProvider.Default) + val consentFlow = submissionRepository.hasGivenConsentToSubmission + val consent = consentFlow.asLiveData(dispatcherProvider.Default) + val showPermissionRequest = SingleLiveEvent<(Activity) -> Unit>() + val showCloseDialog = SingleLiveEvent<Unit>() + + init { + submissionRepository.refreshDeviceUIState(refreshTestResult = false) + + tekHistoryUpdater.callback = object : TEKHistoryUpdater.Callback { + override fun onTEKAvailable(teks: List<TemporaryExposureKey>) { + routeToScreen.postValue( + SubmissionTestResultAvailableFragmentDirections + .actionSubmissionTestResultAvailableFragmentToSubmissionTestResultConsentGivenFragment() + ) + } + + override fun onPermissionDeclined() { + routeToScreen.postValue( + SubmissionTestResultAvailableFragmentDirections + .actionSubmissionTestResultAvailableFragmentToSubmissionTestResultNoConsentFragment() + ) + } + + override fun onError(error: Throwable) { + Timber.e(error, "Failed to update TEKs.") + error.report( + exceptionCategory = ExceptionCategory.EXPOSURENOTIFICATION, + prefix = "SubmissionTestResultAvailableViewModel" + ) + } + } + } fun goBack() { - clickEvent.postValue(SubmissionTestResultAvailableEvents.GoBack) + showCloseDialog.postValue(Unit) + } + + fun onCancelConfirmed() { + routeToScreen.postValue( + SubmissionTestResultAvailableFragmentDirections + .actionSubmissionTestResultAvailableFragmentToMainFragment() + ) } fun goConsent() { - clickEvent.postValue(SubmissionTestResultAvailableEvents.GoConsent) + routeToScreen.postValue( + SubmissionTestResultAvailableFragmentDirections + .actionSubmissionTestResultAvailableFragmentToSubmissionYourConsentFragment() + ) } fun proceed() { - clickEvent.postValue(SubmissionTestResultAvailableEvents.Proceed) + launch { + if (consentFlow.first()) { + tekHistoryUpdater.updateTEKHistoryOrRequestPermission { permissionRequest -> + showPermissionRequest.postValue(permissionRequest) + } + } else { + routeToScreen.postValue( + SubmissionTestResultAvailableFragmentDirections + .actionSubmissionTestResultAvailableFragmentToSubmissionTestResultNoConsentFragment() + ) + } + } + } + + fun handleActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + tekHistoryUpdater.handleActivityResult(requestCode, resultCode, data) } @AssistedInject.Factory diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultready/SubmissionResultReadyFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultready/SubmissionResultReadyFragment.kt new file mode 100644 index 0000000000000000000000000000000000000000..690593a7b7875b1fea5fec93e052d720ec355185 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultready/SubmissionResultReadyFragment.kt @@ -0,0 +1,84 @@ +package de.rki.coronawarnapp.ui.submission.resultready + +import android.os.Bundle +import android.view.View +import android.view.accessibility.AccessibilityEvent +import androidx.activity.OnBackPressedCallback +import androidx.fragment.app.Fragment +import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.databinding.FragmentSubmissionResultReadyBinding +import de.rki.coronawarnapp.ui.submission.SubmissionBlockingDialog +import de.rki.coronawarnapp.ui.submission.SubmissionCancelDialog +import de.rki.coronawarnapp.ui.submission.viewmodel.SubmissionNavigationEvents +import de.rki.coronawarnapp.util.di.AutoInject +import de.rki.coronawarnapp.util.ui.doNavigate +import de.rki.coronawarnapp.util.ui.observe2 +import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider +import de.rki.coronawarnapp.util.viewmodel.cwaViewModels +import javax.inject.Inject + +/** + * The [SubmissionResultReadyFragment] displays information to a user if no consent is given + */ +class SubmissionResultReadyFragment : Fragment(R.layout.fragment_submission_result_ready), AutoInject { + + @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory + private val viewModel: SubmissionResultReadyViewModel by cwaViewModels { viewModelFactory } + private val binding: FragmentSubmissionResultReadyBinding by viewBindingLazy() + + private lateinit var uploadDialog: SubmissionBlockingDialog + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + uploadDialog = SubmissionBlockingDialog(requireContext()) + + val backCallback = object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + onConfirmSkipSymptomsInput() + } + } + requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, backCallback) + + setButtonOnClickListener() + + viewModel.routeToScreen.observe2(this) { + when (it) { + is SubmissionNavigationEvents.NavigateToMainActivity -> doNavigate( + SubmissionResultReadyFragmentDirections.actionSubmissionResultReadyFragmentToMainFragment() + ) + + is SubmissionNavigationEvents.NavigateToSymptomIntroduction -> doNavigate( + SubmissionResultReadyFragmentDirections + .actionSubmissionResultReadyFragmentToSubmissionSymptomIntroductionFragment() + ) + } + } + viewModel.showUploadDialog.observe2(this) { + uploadDialog.setState(show = it) + } + } + + override fun onResume() { + super.onResume() + binding.submissionDoneNoConsentContainer.sendAccessibilityEvent(AccessibilityEvent.TYPE_ANNOUNCEMENT) + } + + private fun setButtonOnClickListener() { + binding.submissionDoneNoConsentHeader.headerButtonBack.buttonIcon.setOnClickListener { + onConfirmSkipSymptomsInput() + } + binding.submissionDoneButtonContinueWithSymptomRecording.setOnClickListener { + viewModel.onContinueWithSymptomRecordingPressed() + } + binding.submissionDoneContactButtonFinishFlow.setOnClickListener { + onConfirmSkipSymptomsInput() + } + } + + private fun onConfirmSkipSymptomsInput() { + SubmissionCancelDialog(requireContext()).show { + viewModel.onSkipSymptomInput() + } + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/viewmodel/SubmissionDoneModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultready/SubmissionResultReadyModule.kt similarity index 55% rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/viewmodel/SubmissionDoneModule.kt rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultready/SubmissionResultReadyModule.kt index ab1e39b1676f50d81c93774d1cef5971c9af84dc..c815a3f2385fd4bdfdace2315ac1dfdcd6796639 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/viewmodel/SubmissionDoneModule.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultready/SubmissionResultReadyModule.kt @@ -1,4 +1,4 @@ -package de.rki.coronawarnapp.ui.submission.viewmodel +package de.rki.coronawarnapp.ui.submission.resultready import dagger.Binds import dagger.Module @@ -8,11 +8,11 @@ import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory import de.rki.coronawarnapp.util.viewmodel.CWAViewModelKey @Module -abstract class SubmissionDoneModule { +abstract class SubmissionResultReadyModule { @Binds @IntoMap - @CWAViewModelKey(SubmissionDoneViewModel::class) - abstract fun submissionDoneFragment( - factory: SubmissionDoneViewModel.Factory + @CWAViewModelKey(SubmissionResultReadyViewModel::class) + abstract fun submissionDoneNoConsentFragment( + factory: SubmissionResultReadyViewModel.Factory ): CWAViewModelFactory<out CWAViewModel> } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultready/SubmissionResultReadyViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultready/SubmissionResultReadyViewModel.kt new file mode 100644 index 0000000000000000000000000000000000000000..0e335b5f5f68881f6dfff04c8611d9a2a931dfbb --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultready/SubmissionResultReadyViewModel.kt @@ -0,0 +1,41 @@ +package de.rki.coronawarnapp.ui.submission.resultready + +import androidx.lifecycle.asLiveData +import com.squareup.inject.assisted.AssistedInject +import de.rki.coronawarnapp.storage.SubmissionRepository +import de.rki.coronawarnapp.ui.submission.viewmodel.SubmissionNavigationEvents +import de.rki.coronawarnapp.util.coroutine.DispatcherProvider +import de.rki.coronawarnapp.util.ui.SingleLiveEvent +import de.rki.coronawarnapp.util.viewmodel.CWAViewModel +import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory +import timber.log.Timber + +class SubmissionResultReadyViewModel @AssistedInject constructor( + private val submissionRepository: SubmissionRepository, + dispatcherProvider: DispatcherProvider +) : CWAViewModel(dispatcherProvider = dispatcherProvider) { + + val showUploadDialog = submissionRepository.isSubmissionRunning + .asLiveData(context = dispatcherProvider.Default) + val routeToScreen: SingleLiveEvent<SubmissionNavigationEvents> = SingleLiveEvent() + + fun onContinueWithSymptomRecordingPressed() { + routeToScreen.postValue(SubmissionNavigationEvents.NavigateToSymptomIntroduction) + } + + fun onSkipSymptomInput() { + Timber.d("Symptom submission was cancelled.") + launch { + try { + submissionRepository.startSubmission() + } catch (e: Exception) { + Timber.e(e, "onCancelConfirmed() failed.") + } finally { + routeToScreen.postValue(SubmissionNavigationEvents.NavigateToMainActivity) + } + } + } + + @AssistedInject.Factory + interface Factory : SimpleCWAViewModelFactory<SubmissionResultReadyViewModel> +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/symptoms/calendar/SubmissionSymptomCalendarFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/symptoms/calendar/SubmissionSymptomCalendarFragment.kt index ceb33fc3aa71426f3895efb6119877192b704760..3b394c05e35f1ad74e65e03c85f55fab822b7c48 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/symptoms/calendar/SubmissionSymptomCalendarFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/symptoms/calendar/SubmissionSymptomCalendarFragment.kt @@ -3,16 +3,18 @@ package de.rki.coronawarnapp.ui.submission.symptoms.calendar import android.content.res.ColorStateList import android.os.Bundle import android.view.View +import androidx.activity.OnBackPressedCallback import androidx.fragment.app.Fragment -import androidx.navigation.fragment.navArgs import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentSubmissionSymptomCalendarBinding import de.rki.coronawarnapp.submission.Symptoms -import de.rki.coronawarnapp.ui.submission.viewmodel.SubmissionNavigationEvents +import de.rki.coronawarnapp.ui.submission.SubmissionBlockingDialog +import de.rki.coronawarnapp.ui.submission.SubmissionCancelDialog +import de.rki.coronawarnapp.ui.submission.viewmodel.SubmissionNavigationEvents.NavigateToMainActivity +import de.rki.coronawarnapp.ui.submission.viewmodel.SubmissionNavigationEvents.NavigateToResultPositiveOtherWarning import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.formatter.formatCalendarBackgroundButtonStyleByState import de.rki.coronawarnapp.util.formatter.formatCalendarButtonStyleByState -import de.rki.coronawarnapp.util.formatter.isEnableSymptomCalendarButtonByState import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.viewBindingLazy @@ -23,36 +25,43 @@ import javax.inject.Inject class SubmissionSymptomCalendarFragment : Fragment(R.layout.fragment_submission_symptom_calendar), AutoInject { - private val navArgs by navArgs<SubmissionSymptomCalendarFragmentArgs>() - @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val viewModel: SubmissionSymptomCalendarViewModel by cwaViewModelsAssisted( factoryProducer = { viewModelFactory }, constructorCall = { factory, _ -> factory as SubmissionSymptomCalendarViewModel.Factory - factory.create(navArgs.symptomIndication) + factory.create() } ) private val binding: FragmentSubmissionSymptomCalendarBinding by viewBindingLazy() + private lateinit var uploadDialog: SubmissionBlockingDialog override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + uploadDialog = SubmissionBlockingDialog(requireContext()) + binding.symptomCalendarContainer.setDateSelectedListener { viewModel.onDateSelected(it) } + viewModel.showCancelDialog.observe2(this) { + SubmissionCancelDialog(requireContext()).show { + viewModel.onCancelConfirmed() + } + } + viewModel.showUploadDialog.observe2(this) { + uploadDialog.setState(show = it) + } + viewModel.routeToScreen.observe2(this) { when (it) { - is SubmissionNavigationEvents.NavigateToResultPositiveOtherWarning -> doNavigate( + is NavigateToResultPositiveOtherWarning -> doNavigate( SubmissionSymptomCalendarFragmentDirections - .actionSubmissionSymptomCalendarFragmentToSubmissionResultPositiveOtherWarningFragment( - it.symptoms - ) + .actionSubmissionSymptomCalendarFragmentToSubmissionResultPositiveOtherWarningFragment() ) - is SubmissionNavigationEvents.NavigateToSymptomIntroduction -> doNavigate( - SubmissionSymptomCalendarFragmentDirections - .actionSubmissionCalendarFragmentToSubmissionSymptomIntroductionFragment() + is NavigateToMainActivity -> doNavigate( + SubmissionSymptomCalendarFragmentDirections.actionSubmissionSymptomCalendarFragmentToMainFragment() ) } } @@ -66,85 +75,61 @@ class SubmissionSymptomCalendarFragment : Fragment(R.layout.fragment_submission_ updateButtons(it) } - binding.apply { - submissionSymptomCalendarHeader.headerButtonBack.buttonIcon - .setOnClickListener { viewModel.onCalendarPreviousClicked() } - - symptomButtonNext - .setOnClickListener { viewModel.onCalendarNextClicked() } - - symptomCalendarChoiceSelection - .calendarButtonSevenDays - .setOnClickListener { viewModel.onLastSevenDaysStart() } - - symptomCalendarChoiceSelection - .calendarButtonOneTwoWeeks - .setOnClickListener { viewModel.onOneToTwoWeeksAgoStart() } - - symptomCalendarChoiceSelection - .calendarButtonMoreThanTwoWeeks - .setOnClickListener { viewModel.onMoreThanTwoWeeksStart() } + val backCallback: OnBackPressedCallback = object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + viewModel.onCalendarPreviousClicked() + } + } + requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, backCallback) - symptomCalendarChoiceSelection - .targetButtonVerify - .setOnClickListener { viewModel.onNoInformationStart() } + binding.submissionSymptomCalendarHeader.headerButtonBack.buttonIcon.setOnClickListener { + viewModel.onCalendarPreviousClicked() } } private fun updateButtons(symptomStart: Symptoms.StartOf?) { - binding.symptomCalendarChoiceSelection.apply { + binding.apply { calendarButtonSevenDays.apply { setTextColor( formatCalendarButtonStyleByState(symptomStart, Symptoms.StartOf.LastSevenDays) ) backgroundTintList = ColorStateList.valueOf( - formatCalendarBackgroundButtonStyleByState( - symptomStart, Symptoms.StartOf.LastSevenDays - ) + formatCalendarBackgroundButtonStyleByState(symptomStart, Symptoms.StartOf.LastSevenDays) ) + setOnClickListener { viewModel.onLastSevenDaysStart() } } calendarButtonOneTwoWeeks.apply { setTextColor( - formatCalendarButtonStyleByState( - symptomStart, - Symptoms.StartOf.OneToTwoWeeksAgo - ) + formatCalendarButtonStyleByState(symptomStart, Symptoms.StartOf.OneToTwoWeeksAgo) ) backgroundTintList = ColorStateList.valueOf( - formatCalendarBackgroundButtonStyleByState( - symptomStart, Symptoms.StartOf.OneToTwoWeeksAgo - ) + formatCalendarBackgroundButtonStyleByState(symptomStart, Symptoms.StartOf.OneToTwoWeeksAgo) ) + setOnClickListener { viewModel.onOneToTwoWeeksAgoStart() } } calendarButtonMoreThanTwoWeeks.apply { setTextColor( - formatCalendarButtonStyleByState( - symptomStart, - Symptoms.StartOf.MoreThanTwoWeeks - ) + formatCalendarButtonStyleByState(symptomStart, Symptoms.StartOf.MoreThanTwoWeeks) ) backgroundTintList = ColorStateList.valueOf( - formatCalendarBackgroundButtonStyleByState( - symptomStart, Symptoms.StartOf.MoreThanTwoWeeks - ) + formatCalendarBackgroundButtonStyleByState(symptomStart, Symptoms.StartOf.MoreThanTwoWeeks) ) + setOnClickListener { viewModel.onMoreThanTwoWeeksStart() } } targetButtonVerify.apply { - setTextColor( - formatCalendarButtonStyleByState(symptomStart, Symptoms.StartOf.NoInformation) - ) + setTextColor(formatCalendarButtonStyleByState(symptomStart, Symptoms.StartOf.NoInformation)) backgroundTintList = ColorStateList.valueOf( - formatCalendarBackgroundButtonStyleByState( - symptomStart, Symptoms.StartOf.NoInformation - ) + formatCalendarBackgroundButtonStyleByState(symptomStart, Symptoms.StartOf.NoInformation) ) + setOnClickListener { viewModel.onNoInformationStart() } } - } - binding.symptomButtonNext.isEnabled = isEnableSymptomCalendarButtonByState( - symptomStart - ) + symptomButtonNext.apply { + isEnabled = symptomStart != null + setOnClickListener { viewModel.onDone() } + } + } } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/symptoms/calendar/SubmissionSymptomCalendarViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/symptoms/calendar/SubmissionSymptomCalendarViewModel.kt index 394a8b3fecf385c1c1eecbe5a03690c1be372336..2e7385ca21ef2bf16508c5d09a183d27aa6dd107 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/symptoms/calendar/SubmissionSymptomCalendarViewModel.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/symptoms/calendar/SubmissionSymptomCalendarViewModel.kt @@ -1,67 +1,87 @@ package de.rki.coronawarnapp.ui.submission.symptoms.calendar import androidx.lifecycle.asLiveData -import com.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.AssistedInject +import de.rki.coronawarnapp.storage.SubmissionRepository import de.rki.coronawarnapp.submission.Symptoms import de.rki.coronawarnapp.ui.submission.viewmodel.SubmissionNavigationEvents import de.rki.coronawarnapp.util.coroutine.DispatcherProvider import de.rki.coronawarnapp.util.ui.SingleLiveEvent import de.rki.coronawarnapp.util.viewmodel.CWAViewModel import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.map import org.joda.time.LocalDate +import timber.log.Timber class SubmissionSymptomCalendarViewModel @AssistedInject constructor( - @Assisted private val symptomIndication: Symptoms.Indication, - dispatcherProvider: DispatcherProvider + dispatcherProvider: DispatcherProvider, + private val submissionRepository: SubmissionRepository ) : CWAViewModel(dispatcherProvider = dispatcherProvider) { - private val symptomStartInternal = MutableStateFlow<Symptoms.StartOf?>(null) - val symptomStart = symptomStartInternal.asLiveData() + val symptomStart = submissionRepository.currentSymptoms.flow + .map { it?.startOfSymptoms } + .asLiveData(context = dispatcherProvider.Default) val routeToScreen: SingleLiveEvent<SubmissionNavigationEvents> = SingleLiveEvent() - - fun onCalendarNextClicked() { - launch { - val symptoms = Symptoms( - startOfSymptoms = symptomStartInternal.first(), - symptomIndication = symptomIndication - ) - routeToScreen.postValue( - SubmissionNavigationEvents.NavigateToResultPositiveOtherWarning(symptoms) - ) - } - } - - fun onCalendarPreviousClicked() { - routeToScreen.postValue(SubmissionNavigationEvents.NavigateToSymptomIntroduction) - } + val showCancelDialog = SingleLiveEvent<Unit>() + val showUploadDialog = submissionRepository.isSubmissionRunning + .asLiveData(context = dispatcherProvider.Default) fun onLastSevenDaysStart() { - symptomStartInternal.value = Symptoms.StartOf.LastSevenDays + updateSymptomStart(Symptoms.StartOf.LastSevenDays) } fun onOneToTwoWeeksAgoStart() { - symptomStartInternal.value = Symptoms.StartOf.OneToTwoWeeksAgo + updateSymptomStart(Symptoms.StartOf.OneToTwoWeeksAgo) } fun onMoreThanTwoWeeksStart() { - symptomStartInternal.value = Symptoms.StartOf.MoreThanTwoWeeks + updateSymptomStart(Symptoms.StartOf.MoreThanTwoWeeks) } fun onNoInformationStart() { - symptomStartInternal.value = Symptoms.StartOf.NoInformation + updateSymptomStart(Symptoms.StartOf.NoInformation) } fun onDateSelected(localDate: LocalDate?) { - symptomStartInternal.value = localDate?.let { Symptoms.StartOf.Date(it) } + updateSymptomStart(localDate?.let { Symptoms.StartOf.Date(it) }) + } + + private fun updateSymptomStart(startOf: Symptoms.StartOf?) { + submissionRepository.currentSymptoms.update { + (it ?: Symptoms.NO_INFO_GIVEN).copy(startOfSymptoms = startOf) + } + } + + fun onCalendarPreviousClicked() { + showCancelDialog.postValue(Unit) + } + + fun onDone() { + Timber.d("onDone() clicked on calender screen.") + performSubmission() + } + + fun onCancelConfirmed() { + Timber.d("onCancelConfirmed() clicked on calendar screen.") + performSubmission() + } + + private fun performSubmission() { + launch { + try { + submissionRepository.startSubmission() + } catch (e: Exception) { + Timber.e(e, "performSubmission() failed.") + } finally { + routeToScreen.postValue(SubmissionNavigationEvents.NavigateToMainActivity) + } + } } @AssistedInject.Factory interface Factory : CWAViewModelFactory<SubmissionSymptomCalendarViewModel> { - fun create(symptomIndication: Symptoms.Indication): SubmissionSymptomCalendarViewModel + fun create(): SubmissionSymptomCalendarViewModel } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/symptoms/introduction/SubmissionSymptomIntroductionFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/symptoms/introduction/SubmissionSymptomIntroductionFragment.kt index 13e3ab1f7e26879a99204f6945e603b703568fee..cefc1e617e9b8aaea3ca601b10ecdbe508b1418f 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/symptoms/introduction/SubmissionSymptomIntroductionFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/symptoms/introduction/SubmissionSymptomIntroductionFragment.kt @@ -1,20 +1,19 @@ package de.rki.coronawarnapp.ui.submission.symptoms.introduction -import android.app.AlertDialog import android.content.res.ColorStateList import android.os.Bundle import android.view.View -import android.widget.Button import androidx.activity.OnBackPressedCallback import androidx.fragment.app.Fragment import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentSubmissionSymptomIntroBinding import de.rki.coronawarnapp.submission.Symptoms +import de.rki.coronawarnapp.ui.submission.SubmissionBlockingDialog +import de.rki.coronawarnapp.ui.submission.SubmissionCancelDialog import de.rki.coronawarnapp.ui.submission.viewmodel.SubmissionNavigationEvents import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.formatter.formatBackgroundButtonStyleByState import de.rki.coronawarnapp.util.formatter.formatButtonStyleByState -import de.rki.coronawarnapp.util.formatter.isEnableSymptomIntroButtonByState import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.viewBindingLazy @@ -29,116 +28,84 @@ class SubmissionSymptomIntroductionFragment : Fragment(R.layout.fragment_submiss private val viewModel: SubmissionSymptomIntroductionViewModel by cwaViewModels { viewModelFactory } private val binding: FragmentSubmissionSymptomIntroBinding by viewBindingLazy() + private lateinit var uploadDialog: SubmissionBlockingDialog override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + uploadDialog = SubmissionBlockingDialog(requireContext()) viewModel.routeToScreen.observe2(this) { when (it) { is SubmissionNavigationEvents.NavigateToSymptomCalendar -> doNavigate( SubmissionSymptomIntroductionFragmentDirections - .actionSubmissionSymptomIntroductionFragmentToSubmissionSymptomCalendarFragment( - symptomIndication = it.symptomIndication - ) + .actionSubmissionSymptomIntroductionFragmentToSubmissionSymptomCalendarFragment() ) - is SubmissionNavigationEvents.NavigateToResultPositiveOtherWarning -> doNavigate( + is SubmissionNavigationEvents.NavigateToMainActivity -> doNavigate( SubmissionSymptomIntroductionFragmentDirections - .actionSubmissionSymptomIntroductionFragmentToSubmissionResultPositiveOtherWarningFragment( - it.symptoms - ) - ) - is SubmissionNavigationEvents.NavigateToTestResult -> doNavigate( - SubmissionSymptomIntroductionFragmentDirections - .actionSubmissionSymptomIntroductionFragmentToSubmissionResultFragment() + .actionSubmissionSymptomIntroductionFragmentToMainFragment() ) } } viewModel.showCancelDialog.observe2(this) { - showCancelDialog() + SubmissionCancelDialog(requireContext()).show { + viewModel.onCancelConfirmed() + } } - viewModel.symptomIndication.observe2(this) { - updateButtons(it) + viewModel.showUploadDialog.observe2(this) { + uploadDialog.setState(show = it) } - requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, backCallback) - - binding.apply { - submissionSymptomHeader.headerButtonBack.buttonIcon - .setOnClickListener { viewModel.onPreviousClicked() } - - symptomButtonNext - .setOnClickListener { viewModel.onNextClicked() } - - symptomChoiceSelection.targetButtonApply - .setOnClickListener { viewModel.onPositiveSymptomIndication() } - - symptomChoiceSelection.targetButtonReject - .setOnClickListener { viewModel.onNegativeSymptomIndication() } - - symptomChoiceSelection.targetButtonVerify - .setOnClickListener { viewModel.onNoInformationSymptomIndication() } + viewModel.symptomIndication.observe2(this) { + updateButtons(it) } - } - private val backCallback: OnBackPressedCallback = - object : OnBackPressedCallback(true) { + val backCallback: OnBackPressedCallback = object : OnBackPressedCallback(true) { override fun handleOnBackPressed() { viewModel.onPreviousClicked() } } + requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, backCallback) + + binding.submissionSymptomHeader.headerButtonBack.buttonIcon.setOnClickListener { viewModel.onPreviousClicked() } + } private fun updateButtons(symptomIndication: Symptoms.Indication?) { - binding.submissionSymptomContainer.findViewById<Button>(R.id.target_button_apply) - .setTextColor(formatButtonStyleByState(symptomIndication, Symptoms.Indication.POSITIVE)) - binding.submissionSymptomContainer.findViewById<Button>(R.id.target_button_apply).backgroundTintList = - ColorStateList.valueOf( - formatBackgroundButtonStyleByState( - symptomIndication, - Symptoms.Indication.POSITIVE - ) - ) - binding.submissionSymptomContainer.findViewById<Button>(R.id.target_button_reject) - .setTextColor(formatButtonStyleByState(symptomIndication, Symptoms.Indication.NEGATIVE)) - binding.submissionSymptomContainer.findViewById<Button>(R.id.target_button_reject).backgroundTintList = - ColorStateList.valueOf( - formatBackgroundButtonStyleByState( - symptomIndication, - Symptoms.Indication.NEGATIVE - ) + binding.targetButtonApply.apply { + setTextColor(formatButtonStyleByState(symptomIndication, Symptoms.Indication.POSITIVE)) + backgroundTintList = ColorStateList.valueOf( + formatBackgroundButtonStyleByState(symptomIndication, Symptoms.Indication.POSITIVE) ) - binding.submissionSymptomContainer.findViewById<Button>(R.id.target_button_verify) - .setTextColor( - formatButtonStyleByState( - symptomIndication, - Symptoms.Indication.NO_INFORMATION - ) + setOnClickListener { viewModel.onPositiveSymptomIndication() } + } + binding.targetButtonReject.apply { + setTextColor(formatButtonStyleByState(symptomIndication, Symptoms.Indication.NEGATIVE)) + backgroundTintList = ColorStateList.valueOf( + formatBackgroundButtonStyleByState(symptomIndication, Symptoms.Indication.NEGATIVE) ) - binding.submissionSymptomContainer.findViewById<Button>(R.id.target_button_verify).backgroundTintList = - ColorStateList.valueOf( - formatBackgroundButtonStyleByState( - symptomIndication, - Symptoms.Indication.NO_INFORMATION + setOnClickListener { viewModel.onNegativeSymptomIndication() } + } + binding.targetButtonVerify.apply { + setTextColor(formatButtonStyleByState(symptomIndication, Symptoms.Indication.NO_INFORMATION)) + backgroundTintList = + ColorStateList.valueOf( + formatBackgroundButtonStyleByState(symptomIndication, Symptoms.Indication.NO_INFORMATION) ) - ) - binding - .symptomButtonNext.findViewById<Button>(R.id.symptom_button_next).isEnabled = - isEnableSymptomIntroButtonByState( - symptomIndication - ) - } - private fun showCancelDialog() { - AlertDialog.Builder(requireContext()).apply { - setTitle(R.string.submission_error_dialog_confirm_cancellation_title) - setMessage(R.string.submission_error_dialog_confirm_cancellation_body) - setPositiveButton(R.string.submission_error_dialog_confirm_cancellation_button_positive) { _, _ -> - viewModel.cancelSymptomSubmission() - } - setNegativeButton(R.string.submission_error_dialog_confirm_cancellation_button_negative) { _, _ -> - // NOOP - } - }.show() + setOnClickListener { viewModel.onNoInformationSymptomIndication() } + } + + binding.symptomButtonNext.apply { + isEnabled = symptomIndication != null + setText( + when (symptomIndication) { + Symptoms.Indication.NEGATIVE -> R.string.submission_done_button_done + Symptoms.Indication.NO_INFORMATION -> R.string.submission_done_button_done + else -> R.string.submission_symptom_further_button + } + ) + setOnClickListener { viewModel.onNextClicked() } + } } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/symptoms/introduction/SubmissionSymptomIntroductionViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/symptoms/introduction/SubmissionSymptomIntroductionViewModel.kt index d5b01524c5a62b01518be7f8198f92db48428a5f..0ca4d571f47623860bbc9a0ea29504ea9f2c76b7 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/symptoms/introduction/SubmissionSymptomIntroductionViewModel.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/symptoms/introduction/SubmissionSymptomIntroductionViewModel.kt @@ -2,44 +2,40 @@ package de.rki.coronawarnapp.ui.submission.symptoms.introduction import androidx.lifecycle.asLiveData import com.squareup.inject.assisted.AssistedInject +import de.rki.coronawarnapp.storage.SubmissionRepository import de.rki.coronawarnapp.submission.Symptoms import de.rki.coronawarnapp.ui.submission.viewmodel.SubmissionNavigationEvents +import de.rki.coronawarnapp.ui.submission.viewmodel.SubmissionNavigationEvents.NavigateToMainActivity +import de.rki.coronawarnapp.ui.submission.viewmodel.SubmissionNavigationEvents.NavigateToSymptomCalendar import de.rki.coronawarnapp.util.coroutine.DispatcherProvider import de.rki.coronawarnapp.util.ui.SingleLiveEvent import de.rki.coronawarnapp.util.viewmodel.CWAViewModel import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.map import timber.log.Timber class SubmissionSymptomIntroductionViewModel @AssistedInject constructor( - dispatcherProvider: DispatcherProvider + dispatcherProvider: DispatcherProvider, + private val submissionRepository: SubmissionRepository ) : CWAViewModel(dispatcherProvider = dispatcherProvider) { - private val symptomIndicationInternal = MutableStateFlow<Symptoms.Indication?>(null) - val symptomIndication = symptomIndicationInternal + val symptomIndication = submissionRepository.currentSymptoms.flow + .map { it?.symptomIndication } .asLiveData(context = dispatcherProvider.Default) val routeToScreen: SingleLiveEvent<SubmissionNavigationEvents> = SingleLiveEvent() val showCancelDialog = SingleLiveEvent<Unit>() + val showUploadDialog = submissionRepository.isSubmissionRunning + .asLiveData(context = dispatcherProvider.Default) fun onNextClicked() { launch { - when (symptomIndicationInternal.first()) { - Symptoms.Indication.POSITIVE -> SubmissionNavigationEvents.NavigateToSymptomCalendar( - Symptoms.Indication.POSITIVE - ) - Symptoms.Indication.NEGATIVE -> SubmissionNavigationEvents.NavigateToResultPositiveOtherWarning( - symptoms = Symptoms( - startOfSymptoms = null, - symptomIndication = Symptoms.Indication.NEGATIVE - ) - ) - else -> SubmissionNavigationEvents.NavigateToResultPositiveOtherWarning( - symptoms = Symptoms.NO_INFO_GIVEN - ) - }.let { routeToScreen.postValue(it) } + when (submissionRepository.currentSymptoms.value?.symptomIndication) { + Symptoms.Indication.POSITIVE -> routeToScreen.postValue(NavigateToSymptomCalendar) + Symptoms.Indication.NEGATIVE -> doSubmit() + Symptoms.Indication.NO_INFORMATION -> showCancelDialog.postValue(Unit) + } } } @@ -48,20 +44,39 @@ class SubmissionSymptomIntroductionViewModel @AssistedInject constructor( } fun onPositiveSymptomIndication() { - symptomIndicationInternal.value = Symptoms.Indication.POSITIVE + updateSymptomIndication(Symptoms.Indication.POSITIVE) } fun onNegativeSymptomIndication() { - symptomIndicationInternal.value = Symptoms.Indication.NEGATIVE + updateSymptomIndication(Symptoms.Indication.NEGATIVE) } fun onNoInformationSymptomIndication() { - symptomIndicationInternal.value = Symptoms.Indication.NO_INFORMATION + updateSymptomIndication(Symptoms.Indication.NO_INFORMATION) + } + + private fun updateSymptomIndication(indication: Symptoms.Indication) { + Timber.d("updateSymptomIndication(indication=$indication)") + submissionRepository.currentSymptoms.update { + (it ?: Symptoms.NO_INFO_GIVEN).copy(symptomIndication = indication) + } } - fun cancelSymptomSubmission() { + fun onCancelConfirmed() { Timber.d("Symptom submission was cancelled.") - routeToScreen.postValue(SubmissionNavigationEvents.NavigateToTestResult) + doSubmit() + } + + private fun doSubmit() { + launch { + try { + submissionRepository.startSubmission() + } catch (e: Exception) { + Timber.e(e, "doSubmit() failed.") + } finally { + routeToScreen.postValue(NavigateToMainActivity) + } + } } @AssistedInject.Factory diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/tan/SubmissionTanFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/tan/SubmissionTanFragment.kt index b345709829153cd2d5522e15d601fa59808ebda6..28701d7a8d6c75b037c3931199ac5e3bdc5962dc 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/tan/SubmissionTanFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/tan/SubmissionTanFragment.kt @@ -55,7 +55,6 @@ class SubmissionTanFragment : Fragment(R.layout.fragment_submission_tan), AutoIn } binding.submissionTanButtonEnter.setOnClickListener { - // TODO navigation depending on test result and consent viewModel.onTanSubmit() } binding.submissionTanHeader.headerButtonBack.buttonIcon.setOnClickListener { goBack() } @@ -67,8 +66,9 @@ class SubmissionTanFragment : Fragment(R.layout.fragment_submission_tan), AutoIn } if (ApiRequestState.SUCCESS == it) { + // TODO What about negative tests and consent? doNavigate( - SubmissionTanFragmentDirections.actionSubmissionTanFragmentToSubmissionResultFragment() + SubmissionTanFragmentDirections.actionSubmissionTanFragmentToSubmissionTestResultNoConsentFragment() ) } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/tan/SubmissionTanViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/tan/SubmissionTanViewModel.kt index 1a8472cccb0facfa029fd5c3590348f69981d411..2806301c364272ae77b393df419c47183f3bd776 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/tan/SubmissionTanViewModel.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/tan/SubmissionTanViewModel.kt @@ -67,6 +67,8 @@ class SubmissionTanViewModel @AssistedInject constructor( } catch (err: Exception) { registrationState.postValue(ApiRequestState.FAILED) err.report(ExceptionCategory.INTERNAL) + } finally { + submissionRepository.refreshDeviceUIState(refreshTestResult = false) } } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/SubmissionTestResultConsentGivenFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/SubmissionTestResultConsentGivenFragment.kt index 340274ecb9399bb6b7c95d5672dd184d7a42cbff..2e2c04259c1e8ae7b29ae6986899367cb9a5bc9b 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/SubmissionTestResultConsentGivenFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/SubmissionTestResultConsentGivenFragment.kt @@ -4,15 +4,12 @@ import android.app.AlertDialog import android.os.Bundle import android.view.View import android.view.accessibility.AccessibilityEvent +import androidx.activity.OnBackPressedCallback import androidx.fragment.app.Fragment import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentSubmissionTestResultConsentGivenBinding -import de.rki.coronawarnapp.exception.http.CwaClientError -import de.rki.coronawarnapp.exception.http.CwaServerError -import de.rki.coronawarnapp.exception.http.CwaWebException +import de.rki.coronawarnapp.ui.submission.SubmissionBlockingDialog import de.rki.coronawarnapp.ui.submission.viewmodel.SubmissionNavigationEvents -import de.rki.coronawarnapp.util.DialogHelper -import de.rki.coronawarnapp.util.NetworkRequestWrapper.Companion.withFailure import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 @@ -29,27 +26,27 @@ class SubmissionTestResultConsentGivenFragment : Fragment(R.layout.fragment_subm private val binding: FragmentSubmissionTestResultConsentGivenBinding by viewBindingLazy() + private lateinit var uploadDialog: SubmissionBlockingDialog + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + uploadDialog = SubmissionBlockingDialog(requireContext()) + + val backCallback = object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() = viewModel.onShowCancelDialog() + } + requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, backCallback) viewModel.uiState.observe2(this) { - binding.uiState = it - with(binding) { - submissionTestResultSection - .setTestResultSection(uiState?.deviceUiState, uiState?.testResultReceivedDate) - } - it.deviceUiState.withFailure { - if (it is CwaWebException) { - DialogHelper.showDialog(buildErrorDialog(it)) - } + binding.apply { + uiState = it + submissionTestResultSection.setTestResultSection(it.deviceUiState, it.testResultReceivedDate) } } setButtonOnClickListener() - viewModel.showCancelDialog.observe2(this) { - showCancelDialog() - } + viewModel.showCancelDialog.observe2(this) { showCancelDialog() } viewModel.routeToScreen.observe2(this) { when (it) { @@ -65,37 +62,9 @@ class SubmissionTestResultConsentGivenFragment : Fragment(R.layout.fragment_subm ) } } - } - private fun navigateToMainScreen() = - doNavigate( - SubmissionTestResultConsentGivenFragmentDirections - .actionSubmissionTestResultConsentGivenFragmentToHomeFragment() - ) - - private fun buildErrorDialog(exception: CwaWebException): DialogHelper.DialogInstance { - return when (exception) { - is CwaClientError, is CwaServerError -> DialogHelper.DialogInstance( - requireActivity(), - R.string.submission_error_dialog_web_generic_error_title, - getString( - R.string.submission_error_dialog_web_generic_network_error_body, - exception.statusCode - ), - R.string.submission_error_dialog_web_generic_error_button_positive, - null, - true, - ::navigateToMainScreen - ) - else -> DialogHelper.DialogInstance( - requireActivity(), - R.string.submission_error_dialog_web_generic_error_title, - R.string.submission_error_dialog_web_generic_error_body, - R.string.submission_error_dialog_web_generic_error_button_positive, - null, - true, - ::navigateToMainScreen - ) + viewModel.showUploadDialog.observe2(this) { + uploadDialog.setState(it) } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/SubmissionTestResultConsentGivenViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/SubmissionTestResultConsentGivenViewModel.kt index 17013ae991af3588be656b4018911dd43a58285e..62a288f52a75baae8a7079e2fa69e1b7031cce68 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/SubmissionTestResultConsentGivenViewModel.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/SubmissionTestResultConsentGivenViewModel.kt @@ -5,45 +5,30 @@ import androidx.lifecycle.asLiveData import com.squareup.inject.assisted.AssistedInject import de.rki.coronawarnapp.storage.SubmissionRepository import de.rki.coronawarnapp.ui.submission.viewmodel.SubmissionNavigationEvents -import de.rki.coronawarnapp.util.DeviceUIState -import de.rki.coronawarnapp.util.NetworkRequestWrapper.Companion.withSuccess +import de.rki.coronawarnapp.util.coroutine.DispatcherProvider +import de.rki.coronawarnapp.util.flow.combine import de.rki.coronawarnapp.util.ui.SingleLiveEvent import de.rki.coronawarnapp.util.viewmodel.CWAViewModel import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.combineTransform -import kotlinx.coroutines.sync.Mutex -import kotlinx.coroutines.sync.withLock import timber.log.Timber class SubmissionTestResultConsentGivenViewModel @AssistedInject constructor( - private val submissionRepository: SubmissionRepository -) : CWAViewModel() { + private val submissionRepository: SubmissionRepository, + dispatcherProvider: DispatcherProvider +) : CWAViewModel(dispatcherProvider = dispatcherProvider) { - private val showRedeemedTokenWarning = SingleLiveEvent<Unit>() - private var wasRedeemedTokenErrorShown = false - private val tokenErrorMutex = Mutex() + val showUploadDialog = submissionRepository.isSubmissionRunning + .asLiveData(context = dispatcherProvider.Default) - val uiState: LiveData<TestResultUIState> = combineTransform( + val uiState: LiveData<TestResultUIState> = combine( submissionRepository.deviceUIStateFlow, submissionRepository.testResultReceivedDateFlow ) { deviceUiState, resultDate -> - - tokenErrorMutex.withLock { - if (!wasRedeemedTokenErrorShown) { - deviceUiState.withSuccess { - if (it == DeviceUIState.PAIRED_REDEEMED) { - wasRedeemedTokenErrorShown = true - showRedeemedTokenWarning.postValue(Unit) - } - } - } - } - TestResultUIState( deviceUiState = deviceUiState, testResultReceivedDate = resultDate - ).let { emit(it) } + ) }.asLiveData(context = Dispatchers.Default) val routeToScreen: SingleLiveEvent<SubmissionNavigationEvents> = SingleLiveEvent() @@ -60,8 +45,15 @@ class SubmissionTestResultConsentGivenViewModel @AssistedInject constructor( } fun cancelTestSubmission() { - Timber.d("Submission was cancelled.") - routeToScreen.postValue(SubmissionNavigationEvents.NavigateToMainActivity) + launch { + try { + submissionRepository.startSubmission() + } catch (e: Exception) { + Timber.e(e, "cancelTestSubmission() failed.") + } finally { + routeToScreen.postValue(SubmissionNavigationEvents.NavigateToMainActivity) + } + } } @AssistedInject.Factory diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/SubmissionTestResultFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/SubmissionTestResultFragment.kt index 7aa2716938965569330dd8f33f38e051a01cae1e..d4230b2114ff53c20f84b2ec5628fb9933b5efa5 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/SubmissionTestResultFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/SubmissionTestResultFragment.kt @@ -22,8 +22,8 @@ import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject -class SubmissionTestResultFragment : Fragment(R.layout.fragment_submission_test_result), - AutoInject { +@Suppress("LongMethod") +class SubmissionTestResultFragment : Fragment(R.layout.fragment_submission_test_result), AutoInject { @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val viewModel: SubmissionTestResultViewModel by cwaViewModels { viewModelFactory } @@ -74,11 +74,15 @@ class SubmissionTestResultFragment : Fragment(R.layout.fragment_submission_test_ override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + viewModel.consentGiven.observe2(this) { + binding.consentStatus.consent = it + } + viewModel.uiState.observe2(this) { binding.uiState = it with(binding) { - submissionTestResultContent.submissionTestResultSection - .setTestResultSection(uiState?.deviceUiState, uiState?.testResultReceivedDate) + submissionTestResultSection + .setTestResultSection(uiState?.deviceUiState, uiState?.testResultReceivedDate) } it.deviceUiState.withFailure { if (it is CwaWebException) { @@ -126,14 +130,17 @@ class SubmissionTestResultFragment : Fragment(R.layout.fragment_submission_test_ is SubmissionNavigationEvents.NavigateToResultPositiveOtherWarning -> doNavigate( SubmissionTestResultFragmentDirections - .actionSubmissionResultFragmentToSubmissionResultPositiveOtherWarningFragment( - it.symptoms - ) + .actionSubmissionResultFragmentToSubmissionResultPositiveOtherWarningFragment() ) is SubmissionNavigationEvents.NavigateToMainActivity -> doNavigate( SubmissionTestResultFragmentDirections.actionSubmissionResultFragmentToMainFragment() ) + is SubmissionNavigationEvents.NavigateToYourConsent -> + doNavigate( + SubmissionTestResultFragmentDirections + .actionSubmissionResultFragmentToSubmissionYourConsentFragment() + ) } } @@ -151,8 +158,7 @@ class SubmissionTestResultFragment : Fragment(R.layout.fragment_submission_test_ private fun setButtonOnClickListener() { binding.submissionTestResultButtonPendingRefresh.setOnClickListener { viewModel.refreshDeviceUIState() - binding.submissionTestResultContent.submissionTestResultSection - .sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED) + binding.submissionTestResultSection.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED) } binding.submissionTestResultButtonPendingRemoveTest.setOnClickListener { @@ -178,6 +184,7 @@ class SubmissionTestResultFragment : Fragment(R.layout.fragment_submission_test_ binding.submissionTestResultHeader.headerButtonBack.buttonIcon.setOnClickListener { viewModel.onBackPressed() } + binding.consentStatus.setOnClickListener { viewModel.onConsentClicked() } } private fun removeTestAfterConfirmation() { diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/SubmissionTestResultNoConsentFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/SubmissionTestResultNoConsentFragment.kt index 8e51e47e2decb88a2a212175d6cbe6f924e835e0..55b149101b4a904b8a5d0c8accfc422e3b02830a 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/SubmissionTestResultNoConsentFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/SubmissionTestResultNoConsentFragment.kt @@ -4,6 +4,7 @@ import android.app.AlertDialog import android.os.Bundle import android.view.View import android.view.accessibility.AccessibilityEvent +import androidx.activity.OnBackPressedCallback import androidx.fragment.app.Fragment import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentSubmissionTestResultPositiveNoConsentBinding @@ -25,9 +26,16 @@ class SubmissionTestResultNoConsentFragment : Fragment(R.layout.fragment_submiss override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + val backCallback = object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + showCancelDialog() + } + } + requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, backCallback) + viewModel.uiState.observe2(this) { binding.submissionTestResultSection - .setTestResultSection(it.deviceUiState, it.testResultReceivedDate) + .setTestResultSection(it.deviceUiState, it.testResultReceivedDate) } binding.submissionTestResultConsentGivenHeader.headerButtonBack.buttonIcon.setOnClickListener { @@ -38,7 +46,7 @@ class SubmissionTestResultNoConsentFragment : Fragment(R.layout.fragment_submiss showCancelDialog() } binding.submissionTestResultPositiveNoConsentButtonWarnOthers.setOnClickListener { - // TODO navigation + navigateToWarnOthers() } } @@ -49,16 +57,12 @@ class SubmissionTestResultNoConsentFragment : Fragment(R.layout.fragment_submiss private fun showCancelDialog() { AlertDialog.Builder(requireContext()).apply { - setTitle(getString(R.string.submission_test_result_positive_no_consent_dialog_title)) - setMessage(getString(R.string.submission_test_result_positive_no_consent_dialog_message)) - setPositiveButton( - getString(R.string.submission_test_result_positive_no_consent_dialog_positive_button) - ) { _, _ -> + setTitle(R.string.submission_test_result_positive_no_consent_dialog_title) + setMessage(R.string.submission_test_result_positive_no_consent_dialog_message) + setPositiveButton(R.string.submission_test_result_positive_no_consent_dialog_positive_button) { _, _ -> navigateToWarnOthers() } - setNegativeButton( - getString(R.string.submission_test_result_positive_no_consent_dialog_negative_button) - ) { _, _ -> + setNegativeButton(R.string.submission_test_result_positive_no_consent_dialog_negative_button) { _, _ -> navigateToHome() } }.show() @@ -71,6 +75,9 @@ class SubmissionTestResultNoConsentFragment : Fragment(R.layout.fragment_submiss } private fun navigateToWarnOthers() { - // TODO + doNavigate( + SubmissionTestResultNoConsentFragmentDirections + .actionSubmissionTestResultNoConsentFragmentToSubmissionResultPositiveOtherWarningNoConsentFragment() + ) } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/SubmissionTestResultNoConsentViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/SubmissionTestResultNoConsentViewModel.kt index 92560829227160616c6d0edaf459b7c43113662b..02ed5797961294bc26cd8e5afb50a5ac950f60b1 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/SubmissionTestResultNoConsentViewModel.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/SubmissionTestResultNoConsentViewModel.kt @@ -15,7 +15,7 @@ import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock class SubmissionTestResultNoConsentViewModel @AssistedInject constructor( - submissionRepository: SubmissionRepository + val submissionRepository: SubmissionRepository ) : CWAViewModel() { private val showRedeemedTokenWarning = SingleLiveEvent<Unit>() diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/SubmissionTestResultViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/SubmissionTestResultViewModel.kt index 42423b2d532959556bc51559cfdfc82235fd1e47..ecdace89453adf8239b26d04db1a44f373f62699 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/SubmissionTestResultViewModel.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/SubmissionTestResultViewModel.kt @@ -7,7 +7,6 @@ import de.rki.coronawarnapp.nearby.ENFClient import de.rki.coronawarnapp.notification.TestResultNotificationService import de.rki.coronawarnapp.storage.LocalData import de.rki.coronawarnapp.storage.SubmissionRepository -import de.rki.coronawarnapp.submission.Symptoms import de.rki.coronawarnapp.ui.submission.viewmodel.SubmissionNavigationEvents import de.rki.coronawarnapp.util.DeviceUIState import de.rki.coronawarnapp.util.NetworkRequestWrapper.Companion.withSuccess @@ -31,6 +30,7 @@ class SubmissionTestResultViewModel @AssistedInject constructor( val routeToScreen: SingleLiveEvent<SubmissionNavigationEvents> = SingleLiveEvent() val showTracingRequiredScreen = SingleLiveEvent<Unit>() val showRedeemedTokenWarning = SingleLiveEvent<Unit>() + val consentGiven = submissionRepository.hasGivenConsentToSubmission.asLiveData() private var wasRedeemedTokenErrorShown = false private val tokenErrorMutex = Mutex() @@ -81,9 +81,7 @@ class SubmissionTestResultViewModel @AssistedInject constructor( fun onContinueWithoutSymptoms() { Timber.d("onContinueWithoutSymptoms()") requireTracingOrShowError { - Symptoms.NO_INFO_GIVEN - .let { SubmissionNavigationEvents.NavigateToResultPositiveOtherWarning(it) } - .let { routeToScreen.postValue(it) } + routeToScreen.postValue(SubmissionNavigationEvents.NavigateToResultPositiveOtherWarning) } } @@ -99,6 +97,7 @@ class SubmissionTestResultViewModel @AssistedInject constructor( launch { Timber.d("deregisterTestFromDevice()") submissionRepository.deleteTestGUID() + submissionRepository.revokeConsentToSubmission() SubmissionRepository.deleteRegistrationToken() LocalData.isAllowedToSubmitDiagnosisKeys(false) LocalData.initialTestResultReceivedTimestamp(0L) @@ -111,6 +110,10 @@ class SubmissionTestResultViewModel @AssistedInject constructor( submissionRepository.refreshDeviceUIState(refreshTestResult) } + fun onConsentClicked() { + routeToScreen.postValue(SubmissionNavigationEvents.NavigateToYourConsent) + } + @AssistedInject.Factory interface Factory : SimpleCWAViewModelFactory<SubmissionTestResultViewModel> } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/viewmodel/SubmissionDoneViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/viewmodel/SubmissionDoneViewModel.kt deleted file mode 100644 index 7357d9a09c93341be827ce7454a10d4e9af7f500..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/viewmodel/SubmissionDoneViewModel.kt +++ /dev/null @@ -1,22 +0,0 @@ -package de.rki.coronawarnapp.ui.submission.viewmodel - -import com.squareup.inject.assisted.AssistedInject -import de.rki.coronawarnapp.util.ui.SingleLiveEvent -import de.rki.coronawarnapp.util.viewmodel.CWAViewModel -import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory - -class SubmissionDoneViewModel @AssistedInject constructor() : CWAViewModel() { - - val routeToScreen: SingleLiveEvent<SubmissionNavigationEvents> = SingleLiveEvent() - - fun onBackPressed() { - routeToScreen.postValue(SubmissionNavigationEvents.NavigateToMainActivity) - } - - fun onDonePressed() { - routeToScreen.postValue(SubmissionNavigationEvents.NavigateToMainActivity) - } - - @AssistedInject.Factory - interface Factory : SimpleCWAViewModelFactory<SubmissionDoneViewModel> -} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/viewmodel/SubmissionFragmentModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/viewmodel/SubmissionFragmentModule.kt index 20f8a8f822222be0c0c6b73d9fddb27a0e763db3..6fd3542aba334f73be7b3e7144f1a68a112e88ad 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/viewmodel/SubmissionFragmentModule.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/viewmodel/SubmissionFragmentModule.kt @@ -4,7 +4,6 @@ import dagger.Module import dagger.android.ContributesAndroidInjector import de.rki.coronawarnapp.ui.submission.fragment.SubmissionContactFragment import de.rki.coronawarnapp.ui.submission.fragment.SubmissionDispatcherFragment -import de.rki.coronawarnapp.ui.submission.fragment.SubmissionDoneFragment import de.rki.coronawarnapp.ui.submission.fragment.SubmissionIntroFragment import de.rki.coronawarnapp.ui.submission.qrcode.consent.SubmissionConsentFragment import de.rki.coronawarnapp.ui.submission.qrcode.consent.SubmissionConsentModule @@ -12,6 +11,8 @@ import de.rki.coronawarnapp.ui.submission.qrcode.scan.SubmissionQRCodeScanFragme import de.rki.coronawarnapp.ui.submission.qrcode.scan.SubmissionQRCodeScanModule import de.rki.coronawarnapp.ui.submission.resultavailable.SubmissionTestResultAvailableFragment import de.rki.coronawarnapp.ui.submission.resultavailable.SubmissionTestResultAvailableModule +import de.rki.coronawarnapp.ui.submission.resultready.SubmissionResultReadyFragment +import de.rki.coronawarnapp.ui.submission.resultready.SubmissionResultReadyModule import de.rki.coronawarnapp.ui.submission.symptoms.calendar.SubmissionSymptomCalendarFragment import de.rki.coronawarnapp.ui.submission.symptoms.calendar.SubmissionSymptomCalendarModule import de.rki.coronawarnapp.ui.submission.symptoms.introduction.SubmissionSymptomIntroductionFragment @@ -24,11 +25,12 @@ import de.rki.coronawarnapp.ui.submission.testresult.SubmissionTestResultFragmen import de.rki.coronawarnapp.ui.submission.testresult.SubmissionTestResultModule import de.rki.coronawarnapp.ui.submission.testresult.SubmissionTestResultNoConsentFragment import de.rki.coronawarnapp.ui.submission.testresult.SubmissionTestResultNoConsentModule -import de.rki.coronawarnapp.ui.submission.warnothers.SubmissionResultPositiveOtherWarningFragment -import de.rki.coronawarnapp.ui.submission.warnothers.SubmissionResultPositiveOtherWarningModule +import de.rki.coronawarnapp.ui.submission.warnothers.SubmissionResultPositiveOtherWarningNoConsentFragment +import de.rki.coronawarnapp.ui.submission.warnothers.SubmissionResultPositiveOtherWarningNoConsentModule import de.rki.coronawarnapp.ui.submission.yourconsent.SubmissionYourConsentFragment import de.rki.coronawarnapp.ui.submission.yourconsent.SubmissionYourConsentModule +@Suppress("FunctionNaming", "MaxLineLength") @Module internal abstract class SubmissionFragmentModule { @@ -50,8 +52,8 @@ internal abstract class SubmissionFragmentModule { @ContributesAndroidInjector(modules = [SubmissionContactModule::class]) abstract fun submissionContactScreen(): SubmissionContactFragment - @ContributesAndroidInjector(modules = [SubmissionDoneModule::class]) - abstract fun submissionDoneScreen(): SubmissionDoneFragment + @ContributesAndroidInjector(modules = [SubmissionResultReadyModule::class]) + abstract fun submissionDoneNoConsentScreen(): SubmissionResultReadyFragment @ContributesAndroidInjector(modules = [SubmissionIntroModule::class]) abstract fun submissionIntroScreen(): SubmissionIntroFragment @@ -59,9 +61,6 @@ internal abstract class SubmissionFragmentModule { @ContributesAndroidInjector(modules = [SubmissionQRCodeScanModule::class]) abstract fun submissionQRCodeScanScreen(): SubmissionQRCodeScanFragment - @ContributesAndroidInjector(modules = [SubmissionResultPositiveOtherWarningModule::class]) - abstract fun submissionResultPositiveOtherWarningScreen(): SubmissionResultPositiveOtherWarningFragment - @ContributesAndroidInjector(modules = [SubmissionSymptomIntroductionModule::class]) abstract fun submissionSymptomIntroductionScreen(): SubmissionSymptomIntroductionFragment @@ -82,4 +81,7 @@ internal abstract class SubmissionFragmentModule { @ContributesAndroidInjector(modules = [SubmissionTestResultNoConsentModule::class]) abstract fun submissionTestResultNoConsentScreen(): SubmissionTestResultNoConsentFragment + + @ContributesAndroidInjector(modules = [SubmissionResultPositiveOtherWarningNoConsentModule::class]) + abstract fun SubmissionResultPositiveOtherWarningNoConsentScreen(): SubmissionResultPositiveOtherWarningNoConsentFragment } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/viewmodel/SubmissionNavigationEvents.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/viewmodel/SubmissionNavigationEvents.kt index 693bb7016f6c64e954bc1f55aad825d3aef9818a..3fa560ce16dcd29622632004a91d0a06d9b3d0ba 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/viewmodel/SubmissionNavigationEvents.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/viewmodel/SubmissionNavigationEvents.kt @@ -1,7 +1,5 @@ package de.rki.coronawarnapp.ui.submission.viewmodel -import de.rki.coronawarnapp.submission.Symptoms - sealed class SubmissionNavigationEvents { object NavigateToContact : SubmissionNavigationEvents() object NavigateToDispatcher : SubmissionNavigationEvents() @@ -10,23 +8,18 @@ sealed class SubmissionNavigationEvents { object NavigateToQRCodeScan : SubmissionNavigationEvents() object NavigateToDataPrivacy : SubmissionNavigationEvents() - data class NavigateToResultPositiveOtherWarning( - val symptoms: Symptoms - ) : SubmissionNavigationEvents() + object NavigateToResultPositiveOtherWarning : SubmissionNavigationEvents() - data class NavigateToResultPositiveOtherWarningNoConsent( - val symptoms: Symptoms - ) : SubmissionNavigationEvents() + object NavigateToResultPositiveOtherWarningNoConsent : SubmissionNavigationEvents() object NavigateToSymptomSubmission : SubmissionNavigationEvents() - data class NavigateToSymptomCalendar( - val symptomIndication: Symptoms.Indication - ) : SubmissionNavigationEvents() + object NavigateToSymptomCalendar : SubmissionNavigationEvents() object NavigateToSymptomIntroduction : SubmissionNavigationEvents() object NavigateToTAN : SubmissionNavigationEvents() object NavigateToTestResult : SubmissionNavigationEvents() object NavigateToConsent : SubmissionNavigationEvents() + object NavigateToYourConsent : SubmissionNavigationEvents() object NavigateToMainActivity : SubmissionNavigationEvents() object ShowCancelDialog : SubmissionNavigationEvents() } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/warnothers/SubmissionResultPositiveOtherWarningFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/warnothers/SubmissionResultPositiveOtherWarningFragment.kt deleted file mode 100644 index 19dcf06c4176614c9980ad174f6872034bc164d0..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/warnothers/SubmissionResultPositiveOtherWarningFragment.kt +++ /dev/null @@ -1,167 +0,0 @@ -package de.rki.coronawarnapp.ui.submission.warnothers - -import android.content.Intent -import android.os.Bundle -import android.view.View -import android.view.accessibility.AccessibilityEvent -import androidx.fragment.app.Fragment -import androidx.navigation.fragment.findNavController -import androidx.navigation.fragment.navArgs -import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey -import de.rki.coronawarnapp.R -import de.rki.coronawarnapp.databinding.FragmentSubmissionPositiveOtherWarningBinding -import de.rki.coronawarnapp.exception.http.BadRequestException -import de.rki.coronawarnapp.exception.http.CwaClientError -import de.rki.coronawarnapp.exception.http.CwaServerError -import de.rki.coronawarnapp.exception.http.CwaWebException -import de.rki.coronawarnapp.exception.http.ForbiddenException -import de.rki.coronawarnapp.nearby.InternalExposureNotificationPermissionHelper -import de.rki.coronawarnapp.ui.submission.viewmodel.SubmissionNavigationEvents -import de.rki.coronawarnapp.util.DialogHelper -import de.rki.coronawarnapp.util.di.AutoInject -import de.rki.coronawarnapp.util.ui.doNavigate -import de.rki.coronawarnapp.util.ui.observe2 -import de.rki.coronawarnapp.util.ui.viewBindingLazy -import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider -import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted -import javax.inject.Inject - -class SubmissionResultPositiveOtherWarningFragment : - Fragment(R.layout.fragment_submission_positive_other_warning), - InternalExposureNotificationPermissionHelper.Callback, AutoInject { - - private val navArgs by navArgs<SubmissionResultPositiveOtherWarningFragmentArgs>() - - @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory - private val viewModel: SubmissionResultPositiveOtherWarningViewModel by cwaViewModelsAssisted( - factoryProducer = { viewModelFactory }, - constructorCall = { factory, _ -> - factory as SubmissionResultPositiveOtherWarningViewModel.Factory - factory.create(navArgs.symptoms) - } - ) - - private val binding: FragmentSubmissionPositiveOtherWarningBinding by viewBindingLazy() - private lateinit var internalExposureNotificationPermissionHelper: InternalExposureNotificationPermissionHelper - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - viewModel.uiState.observe2(this) { - binding.uiState = it - } - - internalExposureNotificationPermissionHelper = - InternalExposureNotificationPermissionHelper(this, this) - - binding.submissionPositiveOtherWarningButtonNext.setOnClickListener { - viewModel.onWarnOthersPressed() - } - binding.submissionPositiveOtherWarningHeader.headerButtonBack.buttonIcon.setOnClickListener { - viewModel.onBackPressed() - } - - viewModel.routeToScreen.observe2(this) { - when (it) { - is SubmissionNavigationEvents.NavigateToSubmissionIntro -> doNavigate( - SubmissionResultPositiveOtherWarningFragmentDirections - .actionSubmissionResultPositiveOtherWarningFragmentToSubmissionDoneFragment() - ) - is SubmissionNavigationEvents.NavigateToSubmissionDone -> doNavigate( - SubmissionResultPositiveOtherWarningFragmentDirections - .actionSubmissionResultPositiveOtherWarningFragmentToSubmissionDoneFragment() - ) - is SubmissionNavigationEvents.NavigateToTestResult -> findNavController().popBackStack() - } - } - - viewModel.submissionError.observe2(this) { - DialogHelper.showDialog(buildErrorDialog(it)) - } - - viewModel.requestKeySharing.observe2(this) { - internalExposureNotificationPermissionHelper.requestPermissionToShareKeys() - } - - viewModel.showEnableTracingEvent.observe2(this) { - val tracingRequiredDialog = DialogHelper.DialogInstance( - requireActivity(), - R.string.submission_test_result_dialog_tracing_required_title, - R.string.submission_test_result_dialog_tracing_required_message, - R.string.submission_test_result_dialog_tracing_required_button - ) - DialogHelper.showDialog(tracingRequiredDialog) - } - } - - override fun onResume() { - super.onResume() - binding.submissionPositiveOtherPrivacyContainer.sendAccessibilityEvent(AccessibilityEvent.TYPE_ANNOUNCEMENT) - } - - private fun navigateToSubmissionResultFragment() = doNavigate( - SubmissionResultPositiveOtherWarningFragmentDirections - .actionSubmissionResultPositiveOtherWarningFragmentToSubmissionResultFragment() - ) - - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - this.internalExposureNotificationPermissionHelper.onResolutionComplete( - requestCode, - resultCode - ) - } - - // InternalExposureNotificationPermissionHelper - callbacks - override fun onKeySharePermissionGranted(keys: List<TemporaryExposureKey>) { - super.onKeySharePermissionGranted(keys) - viewModel.onKeysShared(keys) - } - - override fun onFailure(exception: Exception?) { - // NOOP - } - - private fun buildErrorDialog(throwable: Throwable): DialogHelper.DialogInstance { - return when (throwable) { - is BadRequestException -> DialogHelper.DialogInstance( - requireActivity(), - R.string.submission_error_dialog_web_paring_invalid_title, - R.string.submission_error_dialog_web_paring_invalid_body, - R.string.submission_error_dialog_web_paring_invalid_button_positive, - null, - true, - ::navigateToSubmissionResultFragment - ) - is ForbiddenException -> DialogHelper.DialogInstance( - requireActivity(), - R.string.submission_error_dialog_web_tan_invalid_title, - R.string.submission_error_dialog_web_tan_invalid_body, - R.string.submission_error_dialog_web_tan_invalid_button_positive, - null, - true, - ::navigateToSubmissionResultFragment - ) - is CwaServerError, is CwaClientError -> DialogHelper.DialogInstance( - requireActivity(), - R.string.submission_error_dialog_web_generic_error_title, - getString( - R.string.submission_error_dialog_web_generic_network_error_body, - (throwable as CwaWebException).statusCode - ), - R.string.submission_error_dialog_web_generic_error_button_positive, - null, - true, - ::navigateToSubmissionResultFragment - ) - else -> DialogHelper.DialogInstance( - requireActivity(), - R.string.submission_error_dialog_web_generic_error_title, - R.string.submission_error_dialog_web_generic_error_body, - R.string.submission_error_dialog_web_generic_error_button_positive, - null, - true, - ::navigateToSubmissionResultFragment - ) - } - } -} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/warnothers/SubmissionResultPositiveOtherWarningModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/warnothers/SubmissionResultPositiveOtherWarningModule.kt deleted file mode 100644 index 3ff8fc4cf5f20ecee8060a6f925b5f16cb43bf13..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/warnothers/SubmissionResultPositiveOtherWarningModule.kt +++ /dev/null @@ -1,18 +0,0 @@ -package de.rki.coronawarnapp.ui.submission.warnothers - -import dagger.Binds -import dagger.Module -import dagger.multibindings.IntoMap -import de.rki.coronawarnapp.util.viewmodel.CWAViewModel -import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory -import de.rki.coronawarnapp.util.viewmodel.CWAViewModelKey - -@Module -abstract class SubmissionResultPositiveOtherWarningModule { - @Binds - @IntoMap - @CWAViewModelKey(SubmissionResultPositiveOtherWarningViewModel::class) - abstract fun submissionResultPositveOtherWarningFragment( - factory: SubmissionResultPositiveOtherWarningViewModel.Factory - ): CWAViewModelFactory<out CWAViewModel> -} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/warnothers/SubmissionResultPositiveOtherWarningNoConsentFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/warnothers/SubmissionResultPositiveOtherWarningNoConsentFragment.kt index 4c41c9537d3a8f0027562f060d1505a5b0ffcdf4..4bd95bee8d186f56241e440632683a2a59246ab5 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/warnothers/SubmissionResultPositiveOtherWarningNoConsentFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/warnothers/SubmissionResultPositiveOtherWarningNoConsentFragment.kt @@ -5,18 +5,8 @@ import android.os.Bundle import android.view.View import android.view.accessibility.AccessibilityEvent import androidx.fragment.app.Fragment -import androidx.navigation.fragment.findNavController -import androidx.navigation.fragment.navArgs -import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentSubmissionNoConsentPositiveOtherWarningBinding -import de.rki.coronawarnapp.exception.http.BadRequestException -import de.rki.coronawarnapp.exception.http.CwaClientError -import de.rki.coronawarnapp.exception.http.CwaServerError -import de.rki.coronawarnapp.exception.http.CwaWebException -import de.rki.coronawarnapp.exception.http.ForbiddenException -import de.rki.coronawarnapp.nearby.InternalExposureNotificationPermissionHelper -import de.rki.coronawarnapp.ui.submission.viewmodel.SubmissionNavigationEvents import de.rki.coronawarnapp.util.DialogHelper import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.doNavigate @@ -27,56 +17,35 @@ import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted import javax.inject.Inject class SubmissionResultPositiveOtherWarningNoConsentFragment : - Fragment(R.layout.fragment_submission_no_consent_positive_other_warning), - InternalExposureNotificationPermissionHelper.Callback, AutoInject { - - private val navArgs by navArgs<SubmissionResultPositiveOtherWarningFragmentArgs>() + Fragment(R.layout.fragment_submission_no_consent_positive_other_warning), AutoInject { @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val viewModel: SubmissionResultPositiveOtherWarningNoConsentViewModel by cwaViewModelsAssisted( factoryProducer = { viewModelFactory }, constructorCall = { factory, _ -> factory as SubmissionResultPositiveOtherWarningNoConsentViewModel.Factory - factory.create(navArgs.symptoms) + factory.create() } ) private val binding: FragmentSubmissionNoConsentPositiveOtherWarningBinding by viewBindingLazy() - private lateinit var internalExposureNotificationPermissionHelper: InternalExposureNotificationPermissionHelper override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - viewModel.uiState.observe2(this) { - binding.uiState = it - } - - internalExposureNotificationPermissionHelper = - InternalExposureNotificationPermissionHelper(this, this) - binding.submissionPositiveOtherWarningNoConsentButtonNext.setOnClickListener { - viewModel.onWarnOthersPressed() + viewModel.onConsentButtonClicked() } binding.submissionPositiveOtherWarningHeader.headerButtonBack.buttonIcon.setOnClickListener { viewModel.onBackPressed() } viewModel.routeToScreen.observe2(this) { - when (it) { - is SubmissionNavigationEvents.NavigateToSubmissionDone -> doNavigate( - SubmissionResultPositiveOtherWarningNoConsentFragmentDirections - .actionSubmissionResultPositiveOtherWarningNoConsentFragmentToSubmissionDoneFragment() - ) - is SubmissionNavigationEvents.NavigateToTestResult -> findNavController().popBackStack() - } + doNavigate(it) } - viewModel.submissionError.observe2(this) { - DialogHelper.showDialog(buildErrorDialog(it)) - } - - viewModel.requestKeySharing.observe2(this) { - internalExposureNotificationPermissionHelper.requestPermissionToShareKeys() + viewModel.showPermissionRequest.observe2(this) { permissionRequest -> + permissionRequest.invoke(requireActivity()) } viewModel.showEnableTracingEvent.observe2(this) { @@ -88,6 +57,14 @@ class SubmissionResultPositiveOtherWarningNoConsentFragment : ) DialogHelper.showDialog(tracingRequiredDialog) } + + binding.submissionConsentMainBottomBody.setOnClickListener { + viewModel.onDataPrivacyClick() + } + + viewModel.countryList.observe2(this) { + binding.countryList.countries = it + } } override fun onResume() { @@ -95,72 +72,7 @@ class SubmissionResultPositiveOtherWarningNoConsentFragment : binding.submissionPositiveOtherPrivacyContainer.sendAccessibilityEvent(AccessibilityEvent.TYPE_ANNOUNCEMENT) } - private fun navigateToSubmissionResultFragment() = doNavigate( - SubmissionResultPositiveOtherWarningFragmentDirections - .actionSubmissionResultPositiveOtherWarningFragmentToSubmissionResultFragment() - ) - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - this.internalExposureNotificationPermissionHelper.onResolutionComplete( - requestCode, - resultCode - ) - } - - // InternalExposureNotificationPermissionHelper - callbacks - override fun onKeySharePermissionGranted(keys: List<TemporaryExposureKey>) { - super.onKeySharePermissionGranted(keys) - viewModel.onKeysShared(keys) - } - - override fun onFailure(exception: Exception?) { - doNavigate( - SubmissionResultPositiveOtherWarningNoConsentFragmentDirections - .actionSubmissionResultPositiveOtherWarningNoConsentFragmentToMainFragment() - ) - } - - private fun buildErrorDialog(throwable: Throwable): DialogHelper.DialogInstance { - return when (throwable) { - is BadRequestException -> DialogHelper.DialogInstance( - requireActivity(), - R.string.submission_error_dialog_web_paring_invalid_title, - R.string.submission_error_dialog_web_paring_invalid_body, - R.string.submission_error_dialog_web_paring_invalid_button_positive, - null, - true, - ::navigateToSubmissionResultFragment - ) - is ForbiddenException -> DialogHelper.DialogInstance( - requireActivity(), - R.string.submission_error_dialog_web_tan_invalid_title, - R.string.submission_error_dialog_web_tan_invalid_body, - R.string.submission_error_dialog_web_tan_invalid_button_positive, - null, - true, - ::navigateToSubmissionResultFragment - ) - is CwaServerError, is CwaClientError -> DialogHelper.DialogInstance( - requireActivity(), - R.string.submission_error_dialog_web_generic_error_title, - getString( - R.string.submission_error_dialog_web_generic_network_error_body, - (throwable as CwaWebException).statusCode - ), - R.string.submission_error_dialog_web_generic_error_button_positive, - null, - true, - ::navigateToSubmissionResultFragment - ) - else -> DialogHelper.DialogInstance( - requireActivity(), - R.string.submission_error_dialog_web_generic_error_title, - R.string.submission_error_dialog_web_generic_error_body, - R.string.submission_error_dialog_web_generic_error_button_positive, - null, - true, - ::navigateToSubmissionResultFragment - ) - } + viewModel.handleActivityRersult(requestCode, resultCode, data) } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/warnothers/SubmissionResultPositiveOtherWarningNoConsentViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/warnothers/SubmissionResultPositiveOtherWarningNoConsentViewModel.kt index c78b0104d9eacf99fcd6873b0624002e2177d220..347832463f556e5745e2419fb1d715120a034e9f 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/warnothers/SubmissionResultPositiveOtherWarningNoConsentViewModel.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/warnothers/SubmissionResultPositiveOtherWarningNoConsentViewModel.kt @@ -1,128 +1,93 @@ package de.rki.coronawarnapp.ui.submission.warnothers +import android.app.Activity +import android.content.Intent import androidx.lifecycle.asLiveData +import androidx.navigation.NavDirections import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey -import com.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.AssistedInject -import de.rki.coronawarnapp.exception.NoRegistrationTokenSetException +import de.rki.coronawarnapp.exception.ExceptionCategory +import de.rki.coronawarnapp.exception.reporting.report import de.rki.coronawarnapp.nearby.ENFClient -import de.rki.coronawarnapp.notification.TestResultNotificationService -import de.rki.coronawarnapp.storage.LocalData -import de.rki.coronawarnapp.storage.SubmissionRepository import de.rki.coronawarnapp.storage.interoperability.InteroperabilityRepository -import de.rki.coronawarnapp.submission.SubmissionTask -import de.rki.coronawarnapp.submission.Symptoms -import de.rki.coronawarnapp.task.TaskController -import de.rki.coronawarnapp.task.TaskState -import de.rki.coronawarnapp.task.common.DefaultTaskRequest -import de.rki.coronawarnapp.ui.submission.viewmodel.SubmissionNavigationEvents +import de.rki.coronawarnapp.submission.data.tekhistory.TEKHistoryUpdater import de.rki.coronawarnapp.util.coroutine.DispatcherProvider import de.rki.coronawarnapp.util.ui.SingleLiveEvent import de.rki.coronawarnapp.util.viewmodel.CWAViewModel import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory -import kotlinx.coroutines.flow.combineTransform import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.onEach import timber.log.Timber -import java.util.UUID class SubmissionResultPositiveOtherWarningNoConsentViewModel @AssistedInject constructor( - @Assisted private val symptoms: Symptoms, dispatcherProvider: DispatcherProvider, private val enfClient: ENFClient, - private val taskController: TaskController, - interoperabilityRepository: InteroperabilityRepository, - private val testResultNotificationService: TestResultNotificationService + private val tekHistoryUpdater: TEKHistoryUpdater, + private val interoperabilityRepository: InteroperabilityRepository ) : CWAViewModel(dispatcherProvider = dispatcherProvider) { - private var currentSubmissionRequestId: UUID? = null - private val currentSubmission = taskController.tasks - .map { it.find { taskInfo -> taskInfo.taskState.request.id == currentSubmissionRequestId }?.taskState } - .onEach { - it?.let { - when { - it.isFailed -> submissionError.postValue(it.error) - it.isSuccessful -> routeToScreen.postValue(SubmissionNavigationEvents.NavigateToSubmissionDone) - } - } - } + val routeToScreen = SingleLiveEvent<NavDirections>() - val uiState = combineTransform( - currentSubmission, - interoperabilityRepository.countryListFlow - ) { state, countries -> - WarnOthersState( - submitTaskState = state, - countryList = countries - ).also { emit(it) } - }.asLiveData(context = dispatcherProvider.Default) + val showPermissionRequest = SingleLiveEvent<(Activity) -> Unit>() - val submissionError = SingleLiveEvent<Throwable>() - val routeToScreen: SingleLiveEvent<SubmissionNavigationEvents> = SingleLiveEvent() - - val requestKeySharing = SingleLiveEvent<Unit>() val showEnableTracingEvent = SingleLiveEvent<Unit>() - private fun updateUI(taskState: TaskState) { - if (taskState.request.id == currentSubmissionRequestId) { - currentSubmissionRequestId = null - when { - taskState.isFailed -> - submissionError.postValue(taskState.error ?: return) - taskState.isSuccessful -> - routeToScreen.postValue(SubmissionNavigationEvents.NavigateToSubmissionDone) + val countryList = interoperabilityRepository.countryListFlow.asLiveData() + + init { + tekHistoryUpdater.callback = object : TEKHistoryUpdater.Callback { + override fun onTEKAvailable(teks: List<TemporaryExposureKey>) { + routeToScreen.postValue( + SubmissionResultPositiveOtherWarningNoConsentFragmentDirections + .actionSubmissionResultPositiveOtherWarningNoConsentFragmentToSubmissionResultReadyFragment() + ) + } + + override fun onPermissionDeclined() { + routeToScreen.postValue( + SubmissionResultPositiveOtherWarningNoConsentFragmentDirections + .actionSubmissionResultPositiveOtherWarningNoConsentFragmentToMainFragment() + ) + } + + override fun onError(error: Throwable) { + Timber.e(error, "Couldn't access temporary exposure key history.") + error.report(ExceptionCategory.EXPOSURENOTIFICATION, "Failed to obtain TEKs.") } } } fun onBackPressed() { - routeToScreen.postValue(SubmissionNavigationEvents.NavigateToTestResult) + routeToScreen.postValue( + SubmissionResultPositiveOtherWarningNoConsentFragmentDirections + .actionSubmissionResultPositiveOtherWarningNoConsentFragmentToMainFragment() + ) } - fun onWarnOthersPressed() { + fun onConsentButtonClicked() { launch { if (enfClient.isTracingEnabled.first()) { - requestKeySharing.postValue(Unit) + tekHistoryUpdater.updateTEKHistoryOrRequestPermission { permissionRequest -> + showPermissionRequest.postValue(permissionRequest) + } } else { showEnableTracingEvent.postValue(Unit) } } } - fun onKeysShared(keys: List<TemporaryExposureKey>) { - if (keys.isNotEmpty()) { - submitDiagnosisKeys(keys) - } else { - submitWithNoDiagnosisKeys() - routeToScreen.postValue(SubmissionNavigationEvents.NavigateToMainActivity) - } - testResultNotificationService.cancelPositiveTestResultNotification() - } - - private fun submitDiagnosisKeys(keys: List<TemporaryExposureKey>) { - Timber.d("submitDiagnosisKeys(keys=%s, symptoms=%s)", keys, symptoms) - val registrationToken = - LocalData.registrationToken() ?: throw NoRegistrationTokenSetException() - val taskRequest = DefaultTaskRequest( - SubmissionTask::class, - SubmissionTask.Arguments(registrationToken, keys, symptoms) + fun onDataPrivacyClick() { + routeToScreen.postValue( + SubmissionResultPositiveOtherWarningNoConsentFragmentDirections + .actionSubmissionResultPositiveOtherWarningNoConsentFragmentToInformationPrivacyFragment() ) - currentSubmissionRequestId = taskRequest.id - taskController.submit(taskRequest) - } - - private fun submitWithNoDiagnosisKeys() { - Timber.d("submitWithNoDiagnosisKeys()") - SubmissionRepository.submissionSuccessful() } - fun onDataPrivacyClick() { - routeToScreen.postValue(SubmissionNavigationEvents.NavigateToDataPrivacy) + fun handleActivityRersult(requestCode: Int, resultCode: Int, data: Intent?) { + tekHistoryUpdater.handleActivityResult(requestCode, resultCode, data) } @AssistedInject.Factory interface Factory : CWAViewModelFactory<SubmissionResultPositiveOtherWarningNoConsentViewModel> { - fun create(symptoms: Symptoms): SubmissionResultPositiveOtherWarningNoConsentViewModel + fun create(): SubmissionResultPositiveOtherWarningNoConsentViewModel } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/warnothers/SubmissionResultPositiveOtherWarningViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/warnothers/SubmissionResultPositiveOtherWarningViewModel.kt deleted file mode 100644 index c35d1beed7a3b70ac031d8477cab8c95cb4c0187..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/warnothers/SubmissionResultPositiveOtherWarningViewModel.kt +++ /dev/null @@ -1,111 +0,0 @@ -package de.rki.coronawarnapp.ui.submission.warnothers - -import androidx.lifecycle.asLiveData -import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey -import com.squareup.inject.assisted.Assisted -import com.squareup.inject.assisted.AssistedInject -import de.rki.coronawarnapp.exception.NoRegistrationTokenSetException -import de.rki.coronawarnapp.nearby.ENFClient -import de.rki.coronawarnapp.notification.TestResultNotificationService -import de.rki.coronawarnapp.storage.LocalData -import de.rki.coronawarnapp.storage.SubmissionRepository -import de.rki.coronawarnapp.storage.interoperability.InteroperabilityRepository -import de.rki.coronawarnapp.submission.SubmissionTask -import de.rki.coronawarnapp.submission.Symptoms -import de.rki.coronawarnapp.task.TaskController -import de.rki.coronawarnapp.task.common.DefaultTaskRequest -import de.rki.coronawarnapp.ui.submission.viewmodel.SubmissionNavigationEvents -import de.rki.coronawarnapp.util.coroutine.DispatcherProvider -import de.rki.coronawarnapp.util.ui.SingleLiveEvent -import de.rki.coronawarnapp.util.viewmodel.CWAViewModel -import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory -import kotlinx.coroutines.flow.combineTransform -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.onEach -import timber.log.Timber -import java.util.UUID - -class SubmissionResultPositiveOtherWarningViewModel @AssistedInject constructor( - @Assisted private val symptoms: Symptoms, - dispatcherProvider: DispatcherProvider, - private val enfClient: ENFClient, - private val taskController: TaskController, - interoperabilityRepository: InteroperabilityRepository, - private val testResultNotificationService: TestResultNotificationService -) : CWAViewModel(dispatcherProvider = dispatcherProvider) { - private var currentSubmissionRequestId: UUID? = null - - private val currentSubmission = taskController.tasks - .map { it.find { taskInfo -> taskInfo.taskState.request.id == currentSubmissionRequestId }?.taskState } - .onEach { - it?.let { - when { - it.isFailed -> submissionError.postValue(it.error) - it.isSuccessful -> routeToScreen.postValue(SubmissionNavigationEvents.NavigateToSubmissionDone) - } - } - } - - val uiState = combineTransform( - currentSubmission, - interoperabilityRepository.countryListFlow - ) { state, countries -> - WarnOthersState( - submitTaskState = state, - countryList = countries - ).also { emit(it) } - }.asLiveData(context = dispatcherProvider.Default) - - val submissionError = SingleLiveEvent<Throwable>() - val routeToScreen: SingleLiveEvent<SubmissionNavigationEvents> = SingleLiveEvent() - - val requestKeySharing = SingleLiveEvent<Unit>() - val showEnableTracingEvent = SingleLiveEvent<Unit>() - - fun onBackPressed() { - routeToScreen.postValue(SubmissionNavigationEvents.NavigateToTestResult) - } - - fun onWarnOthersPressed() { - launch { - if (enfClient.isTracingEnabled.first()) { - requestKeySharing.postValue(Unit) - } else { - showEnableTracingEvent.postValue(Unit) - } - } - } - - fun onKeysShared(keys: List<TemporaryExposureKey>) { - if (keys.isNotEmpty()) { - submitDiagnosisKeys(keys) - } else { - submitWithNoDiagnosisKeys() - routeToScreen.postValue(SubmissionNavigationEvents.NavigateToSubmissionDone) - } - testResultNotificationService.cancelPositiveTestResultNotification() - } - - private fun submitDiagnosisKeys(keys: List<TemporaryExposureKey>) { - Timber.d("submitDiagnosisKeys(keys=%s, symptoms=%s)", keys, symptoms) - val registrationToken = - LocalData.registrationToken() ?: throw NoRegistrationTokenSetException() - val taskRequest = DefaultTaskRequest( - SubmissionTask::class, - SubmissionTask.Arguments(registrationToken, keys, symptoms) - ) - currentSubmissionRequestId = taskRequest.id - taskController.submit(taskRequest) - } - - private fun submitWithNoDiagnosisKeys() { - Timber.d("submitWithNoDiagnosisKeys()") - SubmissionRepository.submissionSuccessful() - } - - @AssistedInject.Factory - interface Factory : CWAViewModelFactory<SubmissionResultPositiveOtherWarningViewModel> { - fun create(symptoms: Symptoms): SubmissionResultPositiveOtherWarningViewModel - } -} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/yourconsent/SubmissionYourConsentFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/yourconsent/SubmissionYourConsentFragment.kt index a93399ffe62b15b2da383a9a46e9122290987d32..4f0fbcc4721487471466a55a638e04bbd793be9b 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/yourconsent/SubmissionYourConsentFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/yourconsent/SubmissionYourConsentFragment.kt @@ -8,6 +8,7 @@ import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentSubmissionYourConsentBinding import de.rki.coronawarnapp.ui.main.MainActivity import de.rki.coronawarnapp.util.di.AutoInject +import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.viewBindingLazy import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider @@ -41,7 +42,10 @@ class SubmissionYourConsentFragment : Fragment(R.layout.fragment_submission_your vm.clickEvent.observe2(this) { when (it) { is SubmissionYourConsentEvents.GoBack -> (activity as MainActivity).goBack() - // TODO: Navigation: is YourConsentEvents.GoLegal -> doNavigate(YourConsentFragmentDirections.actionSubmissionYourConsentFragmentToInformationPrivacyFragment()) + is SubmissionYourConsentEvents.GoLegal -> doNavigate( + SubmissionYourConsentFragmentDirections + .actionSubmissionYourConsentFragmentToInformationPrivacyFragment() + ) } } @@ -52,7 +56,7 @@ class SubmissionYourConsentFragment : Fragment(R.layout.fragment_submission_your vm.switchConsent() } submissionYourConsentSwitch.settingsSwitchRow.setOnClickListener { vm.switchConsent() } - // TODO: Navigation: submissionYourConsentLegalDetailsCard.setOnClickListener { vm.goLegal() } + submissionYourConsentAgreementDetailsText.setOnClickListener { vm.goLegal() } } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/tracing/card/TracingCardState.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/tracing/card/TracingCardState.kt index a2f71aeb12586afed13237c5b390e337bcbb5e91..8495f92558bb58fb6246e5b2e6ae2d942bbfd633 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/tracing/card/TracingCardState.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/tracing/card/TracingCardState.kt @@ -63,29 +63,19 @@ data class TracingCardState( * the persisted risk level is of importance */ fun getSavedRiskBody(c: Context): String { - // Don't display last risk when tracing is disabled - if (isTracingOff()) { - val arg = c.getString(R.string.risk_card_no_calculation_possible_headline) - return c.getString(R.string.risk_card_no_calculation_possible_body_saved_risk).format(arg) - } - - // Don't have any old risk state to display - if (lastSuccessfulRiskState == CALCULATION_FAILED) { - return "" - } - - // If we failed this time, we want to display the old risk - if (riskState == CALCULATION_FAILED) { - val arg = when (lastSuccessfulRiskState) { - INCREASED_RISK -> R.string.risk_card_increased_risk_headline - LOW_RISK -> R.string.risk_card_low_risk_headline - else -> null - }?.let { c.getString(it) } ?: "" - return c.getString(R.string.risk_card_no_calculation_possible_body_saved_risk).format(arg) + val stateToDisplay = when { + riskState == CALCULATION_FAILED -> lastSuccessfulRiskState + isTracingOff() -> riskState + else -> null } - - // We are not in an error state - return "" + return when (stateToDisplay) { + INCREASED_RISK -> R.string.risk_card_increased_risk_headline + LOW_RISK -> R.string.risk_card_low_risk_headline + else -> null + }?.let { + val argumentValue = c.getString(it) + c.getString(R.string.risk_card_no_calculation_possible_body_saved_risk).format(argumentValue) + } ?: "" } /** diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/tracing/settings/SettingsTracingFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/tracing/settings/SettingsTracingFragment.kt index 489f83c59a0bbe31475fd18214d8637bd4cb2752..ca56b4c170fb0ce20d839928dfef67448c34298a 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/tracing/settings/SettingsTracingFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/tracing/settings/SettingsTracingFragment.kt @@ -9,7 +9,6 @@ import androidx.navigation.fragment.findNavController import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentSettingsTracingBinding import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient -import de.rki.coronawarnapp.nearby.InternalExposureNotificationPermissionHelper import de.rki.coronawarnapp.ui.doNavigate import de.rki.coronawarnapp.ui.main.MainActivity import de.rki.coronawarnapp.ui.tracing.settings.SettingsTracingFragmentViewModel.Event @@ -21,8 +20,6 @@ import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.viewBindingLazy import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels -import de.rki.coronawarnapp.worker.BackgroundWorkScheduler -import timber.log.Timber import javax.inject.Inject /** @@ -32,8 +29,7 @@ import javax.inject.Inject * @see InternalExposureNotificationClient * @see InternalExposureNotificationPermissionHelper */ -class SettingsTracingFragment : Fragment(R.layout.fragment_settings_tracing), - InternalExposureNotificationPermissionHelper.Callback, AutoInject { +class SettingsTracingFragment : Fragment(R.layout.fragment_settings_tracing), AutoInject { @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val vm: SettingsTracingFragmentViewModel by cwaViewModels( @@ -43,8 +39,6 @@ class SettingsTracingFragment : Fragment(R.layout.fragment_settings_tracing), private val binding: FragmentSettingsTracingBinding by viewBindingLazy() - private lateinit var exposureNotificationPermissionHelper: InternalExposureNotificationPermissionHelper - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -64,11 +58,9 @@ class SettingsTracingFragment : Fragment(R.layout.fragment_settings_tracing), } } - exposureNotificationPermissionHelper = InternalExposureNotificationPermissionHelper(this, this) - vm.events.observe2(this) { when (it) { - Event.RequestPermissions -> exposureNotificationPermissionHelper.requestPermissionToStartTracing() + is Event.RequestPermissions -> it.permissionRequest.invoke(requireActivity()) Event.ShowConsentDialog -> showConsentDialog() Event.ManualCheckingDialog -> showManualCheckingRequiredDialog() } @@ -83,18 +75,7 @@ class SettingsTracingFragment : Fragment(R.layout.fragment_settings_tracing), } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - exposureNotificationPermissionHelper.onResolutionComplete( - requestCode, - resultCode - ) - } - - override fun onStartPermissionGranted() { - BackgroundWorkScheduler.startWorkScheduler() - } - - override fun onFailure(exception: Exception?) { - Timber.w(exception, "onPermissionFaliure") + vm.handleActivityResult(requestCode, resultCode, data) } private fun setButtonOnClickListener() { @@ -150,16 +131,19 @@ class SettingsTracingFragment : Fragment(R.layout.fragment_settings_tracing), private fun showConsentDialog() { val dialog = DialogHelper.DialogInstance( - requireActivity(), - R.string.onboarding_tracing_headline_consent, - R.string.onboarding_tracing_body_consent, - R.string.onboarding_button_enable, - R.string.onboarding_button_cancel, - true, { - exposureNotificationPermissionHelper.requestPermissionToStartTracing() - }, { + context = requireActivity(), + title = R.string.onboarding_tracing_headline_consent, + message = R.string.onboarding_tracing_body_consent, + positiveButton = R.string.onboarding_button_enable, + negativeButton = R.string.onboarding_button_cancel, + cancelable = true, + positiveButtonFunction = { + vm.startStopTracing() + }, + negativeButtonFunction = { // Declined - }) + } + ) DialogHelper.showDialog(dialog) } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/tracing/settings/SettingsTracingFragmentViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/tracing/settings/SettingsTracingFragmentViewModel.kt index 6b2e57dfa22ec73593740d62705248d4ce98e6fe..e81d19c1b504d0e380a54eb8d1299f973c0814e5 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/tracing/settings/SettingsTracingFragmentViewModel.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/tracing/settings/SettingsTracingFragmentViewModel.kt @@ -1,5 +1,7 @@ package de.rki.coronawarnapp.ui.tracing.settings +import android.app.Activity +import android.content.Intent import androidx.lifecycle.LiveData import androidx.lifecycle.asLiveData import androidx.lifecycle.viewModelScope @@ -7,6 +9,7 @@ import com.squareup.inject.assisted.AssistedInject import de.rki.coronawarnapp.exception.ExceptionCategory import de.rki.coronawarnapp.exception.reporting.report import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient +import de.rki.coronawarnapp.nearby.TracingPermissionHelper import de.rki.coronawarnapp.storage.LocalData import de.rki.coronawarnapp.tracing.GeneralTracingStatus import de.rki.coronawarnapp.ui.tracing.details.TracingDetailsState @@ -28,7 +31,8 @@ class SettingsTracingFragmentViewModel @AssistedInject constructor( dispatcherProvider: DispatcherProvider, tracingDetailsStateProvider: TracingDetailsStateProvider, tracingStatus: GeneralTracingStatus, - private val backgroundPrioritization: BackgroundPrioritization + private val backgroundPrioritization: BackgroundPrioritization, + private val tracingPermissionHelper: TracingPermissionHelper ) : CWAViewModel(dispatcherProvider = dispatcherProvider) { val tracingDetailsState: LiveData<TracingDetailsState> = tracingDetailsStateProvider.state @@ -46,6 +50,20 @@ class SettingsTracingFragmentViewModel @AssistedInject constructor( val events = SingleLiveEvent<Event>() + init { + tracingPermissionHelper.callback = object : TracingPermissionHelper.Callback { + override fun onUpdateTracingStatus(isTracingEnabled: Boolean) { + if (isTracingEnabled) { + BackgroundWorkScheduler.startWorkScheduler() + } + } + + override fun onError(error: Throwable) { + Timber.w(error, "Failed to start tracing") + } + } + } + fun startStopTracing() { // if tracing is enabled when listener is activated it should be disabled launch { @@ -56,7 +74,9 @@ class SettingsTracingFragmentViewModel @AssistedInject constructor( } else { // tracing was already activated if (LocalData.initialTracingActivationTimestamp() != null) { - events.postValue(Event.RequestPermissions) + tracingPermissionHelper.startTracing { permissionRequest -> + events.postValue(Event.RequestPermissions(permissionRequest)) + } } else { // tracing was never activated // ask for consent via dialog for initial tracing activation when tracing was not @@ -79,8 +99,12 @@ class SettingsTracingFragmentViewModel @AssistedInject constructor( } } + fun handleActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + tracingPermissionHelper.handleActivityResult(requestCode, resultCode, data) + } + sealed class Event { - object RequestPermissions : Event() + data class RequestPermissions(val permissionRequest: (Activity) -> Unit) : Event() object ShowConsentDialog : Event() object ManualCheckingDialog : Event() } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/view/TestResultSectionView.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/view/TestResultSectionView.kt index 0a84f8e0bd59961c871258307db6645fbc1e50aa..adc72f7f193c8f8a3291d365452577d59dfecec3 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/view/TestResultSectionView.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/view/TestResultSectionView.kt @@ -45,6 +45,7 @@ constructor( } fun setTestResultSection(uiState: NetworkRequestWrapper<DeviceUIState, Throwable>?, registeredAt: Date?) { + test_result_section_headline.text = context.getString(R.string.test_result_card_headline) test_result_section_registered_at_text.text = formatTestResultRegisteredAtText(registeredAt) val testResultIcon = formatTestStatusIcon(uiState) test_result_section_status_icon.setImageDrawable(testResultIcon) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterSubmissionHelper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterSubmissionHelper.kt index e2844d69be9b9e267a8734dbf38a00701d78fa81..9b307b8007a2ebd711dfc60065486395bb239d9d 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterSubmissionHelper.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterSubmissionHelper.kt @@ -43,14 +43,6 @@ fun formatCalendarBackgroundButtonStyleByState( ): Int = formatColor(currentState == state, R.color.colorTextSemanticNeutral, R.color.colorSurface2) -fun isEnableSymptomIntroButtonByState(currentState: Symptoms.Indication?): Boolean { - return currentState != null -} - -fun isEnableSymptomCalendarButtonByState(currentState: Symptoms.StartOf?): Boolean { - return currentState != null -} - fun formatTestResultSpinnerVisible(uiState: NetworkRequestWrapper<DeviceUIState, Throwable>?): Int = uiState.withSuccess(View.VISIBLE) { View.GONE diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/preferences/FlowPreference.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/preferences/FlowPreference.kt index 2e97359373b6de42a333ade72b7b4542c5e42a73..cedc77fb85879cc53f57095072b201b046d24b8a 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/preferences/FlowPreference.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/preferences/FlowPreference.kt @@ -91,3 +91,14 @@ inline fun <reified T : Any?> SharedPreferences.createFlowPreference( reader = FlowPreference.basicReader(defaultValue), writer = FlowPreference.basicWriter() ) + +inline fun <reified T : Any?> SharedPreferences.createFlowPreference( + key: String, + noinline reader: SharedPreferences.(key: String) -> T, + noinline writer: SharedPreferences.Editor.(key: String, value: T) -> Unit +) = FlowPreference( + preferences = this, + key = key, + reader = reader, + writer = writer +) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/serialization/SerializationModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/serialization/SerializationModule.kt index c2c33f43b43745b32465362577c0a0bffae874b9..e41065b3c8ee61e11a10d85ea24fdbf3c0ed4fff 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/serialization/SerializationModule.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/serialization/SerializationModule.kt @@ -8,8 +8,10 @@ import dagger.Reusable import de.rki.coronawarnapp.util.serialization.adapter.ByteArrayAdapter import de.rki.coronawarnapp.util.serialization.adapter.DurationAdapter import de.rki.coronawarnapp.util.serialization.adapter.InstantAdapter +import de.rki.coronawarnapp.util.serialization.adapter.LocalDateAdapter import org.joda.time.Duration import org.joda.time.Instant +import org.joda.time.LocalDate @Module class SerializationModule { @@ -19,6 +21,7 @@ class SerializationModule { @Provides fun baseGson(): Gson = GsonBuilder() .registerTypeAdapter(Instant::class.java, InstantAdapter()) + .registerTypeAdapter(LocalDate::class.java, LocalDateAdapter()) .registerTypeAdapter(Duration::class.java, DurationAdapter()) .registerTypeAdapter(ByteArray::class.java, ByteArrayAdapter()) .create() diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/serialization/adapter/LocalDateAdapter.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/serialization/adapter/LocalDateAdapter.kt new file mode 100644 index 0000000000000000000000000000000000000000..14fca9f059fca6d661eb3af6f8442de7d8c0ad8f --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/serialization/adapter/LocalDateAdapter.kt @@ -0,0 +1,19 @@ +package de.rki.coronawarnapp.util.serialization.adapter + +import com.google.gson.TypeAdapter +import com.google.gson.stream.JsonReader +import com.google.gson.stream.JsonWriter +import org.joda.time.LocalDate +import org.json.JSONObject + +class LocalDateAdapter : TypeAdapter<LocalDate>() { + override fun write(out: JsonWriter, value: LocalDate?) { + if (value == null) out.nullValue() + else out.value(value.toString()) + } + + override fun read(reader: JsonReader): LocalDate? = when (reader.peek()) { + JSONObject.NULL -> reader.nextNull().let { null } + else -> LocalDate.parse(reader.nextString()) + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/serialization/adapter/RuntimeTypeAdapterFactory.java b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/serialization/adapter/RuntimeTypeAdapterFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..dbd77b1364fcf2d847839b00512e1f449afddcb8 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/serialization/adapter/RuntimeTypeAdapterFactory.java @@ -0,0 +1,279 @@ +/* + * Copyright (C) 2011 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package de.rki.coronawarnapp.util.serialization.adapter; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonPrimitive; +import com.google.gson.TypeAdapter; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.internal.Streams; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +import java.io.IOException; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Adapts values whose runtime type may differ from their declaration type. This + * is necessary when a field's type is not the same type that GSON should create + * when deserializing that field. For example, consider these types: + * <pre> {@code + * abstract class Shape { + * int x; + * int y; + * } + * class Circle extends Shape { + * int radius; + * } + * class Rectangle extends Shape { + * int width; + * int height; + * } + * class Diamond extends Shape { + * int width; + * int height; + * } + * class Drawing { + * Shape bottomShape; + * Shape topShape; + * } + * }</pre> + * <p>Without additional type information, the serialized JSON is ambiguous. Is + * the bottom shape in this drawing a rectangle or a diamond? <pre> {@code + * { + * "bottomShape": { + * "width": 10, + * "height": 5, + * "x": 0, + * "y": 0 + * }, + * "topShape": { + * "radius": 2, + * "x": 4, + * "y": 1 + * } + * }}</pre> + * This class addresses this problem by adding type information to the + * serialized JSON and honoring that type information when the JSON is + * deserialized: <pre> {@code + * { + * "bottomShape": { + * "type": "Diamond", + * "width": 10, + * "height": 5, + * "x": 0, + * "y": 0 + * }, + * "topShape": { + * "type": "Circle", + * "radius": 2, + * "x": 4, + * "y": 1 + * } + * }}</pre> + * Both the type field name ({@code "type"}) and the type labels ({@code + * "Rectangle"}) are configurable. + * + * <h3>Registering Types</h3> + * Create a {@code RuntimeTypeAdapterFactory} by passing the base type and type field + * name to the {@link #of} factory method. If you don't supply an explicit type + * field name, {@code "type"} will be used. <pre> {@code + * RuntimeTypeAdapterFactory<Shape> shapeAdapterFactory + * = RuntimeTypeAdapterFactory.of(Shape.class, "type"); + * }</pre> + * Next register all of your subtypes. Every subtype must be explicitly + * registered. This protects your application from injection attacks. If you + * don't supply an explicit type label, the type's simple name will be used. + * <pre> {@code + * shapeAdapterFactory.registerSubtype(Rectangle.class, "Rectangle"); + * shapeAdapterFactory.registerSubtype(Circle.class, "Circle"); + * shapeAdapterFactory.registerSubtype(Diamond.class, "Diamond"); + * }</pre> + * Finally, register the type adapter factory in your application's GSON builder: + * <pre> {@code + * Gson gson = new GsonBuilder() + * .registerTypeAdapterFactory(shapeAdapterFactory) + * .create(); + * }</pre> + * Like {@code GsonBuilder}, this API supports chaining: <pre> {@code + * RuntimeTypeAdapterFactory<Shape> shapeAdapterFactory = RuntimeTypeAdapterFactory.of(Shape.class) + * .registerSubtype(Rectangle.class) + * .registerSubtype(Circle.class) + * .registerSubtype(Diamond.class); + * }</pre> + * + * <h3>Serialization and deserialization</h3> + * In order to serialize and deserialize a polymorphic object, + * you must specify the base type explicitly. + * <pre> {@code + * Diamond diamond = new Diamond(); + * String json = gson.toJson(diamond, Shape.class); + * }</pre> + * And then: + * <pre> {@code + * Shape shape = gson.fromJson(json, Shape.class); + * }</pre> + */ +public final class RuntimeTypeAdapterFactory<T> implements TypeAdapterFactory { + private final Class<?> baseType; + private final String typeFieldName; + private final Map<String, Class<?>> labelToSubtype = new LinkedHashMap<String, Class<?>>(); + private final Map<Class<?>, String> subtypeToLabel = new LinkedHashMap<Class<?>, String>(); + private final boolean maintainType; + + private RuntimeTypeAdapterFactory(Class<?> baseType, String typeFieldName, boolean maintainType) { + if (typeFieldName == null || baseType == null) { + throw new NullPointerException(); + } + this.baseType = baseType; + this.typeFieldName = typeFieldName; + this.maintainType = maintainType; + } + + /** + * Creates a new runtime type adapter using for {@code baseType} using {@code + * typeFieldName} as the type field name. Type field names are case sensitive. + * {@code maintainType} flag decide if the type will be stored in pojo or not. + */ + public static <T> RuntimeTypeAdapterFactory<T> of(Class<T> baseType, String typeFieldName, boolean maintainType) { + return new RuntimeTypeAdapterFactory<T>(baseType, typeFieldName, maintainType); + } + + /** + * Creates a new runtime type adapter using for {@code baseType} using {@code + * typeFieldName} as the type field name. Type field names are case sensitive. + */ + public static <T> RuntimeTypeAdapterFactory<T> of(Class<T> baseType, String typeFieldName) { + return new RuntimeTypeAdapterFactory<T>(baseType, typeFieldName, false); + } + + /** + * Creates a new runtime type adapter for {@code baseType} using {@code "type"} as + * the type field name. + */ + public static <T> RuntimeTypeAdapterFactory<T> of(Class<T> baseType) { + return new RuntimeTypeAdapterFactory<T>(baseType, "type", false); + } + + /** + * Registers {@code type} identified by {@code label}. Labels are case + * sensitive. + * + * @throws IllegalArgumentException if either {@code type} or {@code label} + * have already been registered on this type adapter. + */ + public RuntimeTypeAdapterFactory<T> registerSubtype(Class<? extends T> type, String label) { + if (type == null || label == null) { + throw new NullPointerException(); + } + if (subtypeToLabel.containsKey(type) || labelToSubtype.containsKey(label)) { + throw new IllegalArgumentException("types and labels must be unique"); + } + labelToSubtype.put(label, type); + subtypeToLabel.put(type, label); + return this; + } + + /** + * Registers {@code type} identified by its {@link Class#getSimpleName simple + * name}. Labels are case sensitive. + * + * @throws IllegalArgumentException if either {@code type} or its simple name + * have already been registered on this type adapter. + */ + public RuntimeTypeAdapterFactory<T> registerSubtype(Class<? extends T> type) { + return registerSubtype(type, type.getSimpleName()); + } + + public <R> TypeAdapter<R> create(Gson gson, TypeToken<R> type) { + if (type.getRawType() != baseType) { + return null; + } + + final Map<String, TypeAdapter<?>> labelToDelegate + = new LinkedHashMap<String, TypeAdapter<?>>(); + final Map<Class<?>, TypeAdapter<?>> subtypeToDelegate + = new LinkedHashMap<Class<?>, TypeAdapter<?>>(); + for (Map.Entry<String, Class<?>> entry : labelToSubtype.entrySet()) { + TypeAdapter<?> delegate = gson.getDelegateAdapter(this, TypeToken.get(entry.getValue())); + labelToDelegate.put(entry.getKey(), delegate); + subtypeToDelegate.put(entry.getValue(), delegate); + } + + return new TypeAdapter<R>() { + @Override + public R read(JsonReader in) throws IOException { + JsonElement jsonElement = Streams.parse(in); + JsonElement labelJsonElement; + if (maintainType) { + labelJsonElement = jsonElement.getAsJsonObject().get(typeFieldName); + } else { + labelJsonElement = jsonElement.getAsJsonObject().remove(typeFieldName); + } + + if (labelJsonElement == null) { + throw new JsonParseException("cannot deserialize " + baseType + + " because it does not define a field named " + typeFieldName); + } + String label = labelJsonElement.getAsString(); + @SuppressWarnings("unchecked") // registration requires that subtype extends T + TypeAdapter<R> delegate = (TypeAdapter<R>) labelToDelegate.get(label); + if (delegate == null) { + throw new JsonParseException("cannot deserialize " + baseType + " subtype named " + + label + "; did you forget to register a subtype?"); + } + return delegate.fromJsonTree(jsonElement); + } + + @Override + public void write(JsonWriter out, R value) throws IOException { + Class<?> srcType = value.getClass(); + String label = subtypeToLabel.get(srcType); + @SuppressWarnings("unchecked") // registration requires that subtype extends T + TypeAdapter<R> delegate = (TypeAdapter<R>) subtypeToDelegate.get(srcType); + if (delegate == null) { + throw new JsonParseException("cannot serialize " + srcType.getName() + + "; did you forget to register a subtype?"); + } + JsonObject jsonObject = delegate.toJsonTree(value).getAsJsonObject(); + + if (maintainType) { + Streams.write(jsonObject, out); + return; + } + + JsonObject clone = new JsonObject(); + + if (jsonObject.has(typeFieldName)) { + throw new JsonParseException("cannot serialize " + srcType.getName() + + " because it already defines a field named " + typeFieldName); + } + clone.add(typeFieldName, new JsonPrimitive(label)); + + for (Map.Entry<String, JsonElement> e : jsonObject.entrySet()) { + clone.add(e.getKey(), e.getValue()); + } + Streams.write(clone, out); + } + }.nullSafe(); + } +} \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/layout/fragment_submission_no_consent_positive_other_warning.xml b/Corona-Warn-App/src/main/res/layout/fragment_submission_no_consent_positive_other_warning.xml index b0e416d86beb4922aba151c71120a4cc93eb7eb1..c8ba6938c9021af9d3a28c66218964f9b7c2452c 100644 --- a/Corona-Warn-App/src/main/res/layout/fragment_submission_no_consent_positive_other_warning.xml +++ b/Corona-Warn-App/src/main/res/layout/fragment_submission_no_consent_positive_other_warning.xml @@ -29,43 +29,173 @@ app:layout_constraintTop_toTopOf="parent" app:title="@{@string/submission_positive_other_warning_title}" /> - <include - layout="@layout/include_submission_positive_other_warning_no_consent" - android:layout_width="@dimen/match_constraint" - android:layout_height="@dimen/match_constraint" - app:countryData="@{uiState.countryList}" + <ScrollView + android:id="@+id/content_scrollcontainer" + android:layout_width="0dp" + android:layout_height="0dp" app:layout_constraintBottom_toTopOf="@+id/guideline_action" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.0" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/submission_positive_other_warning_header" - app:layout_constraintVertical_bias="0.0" /> + app:layout_constraintVertical_bias="0.0"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:paddingBottom="@dimen/spacing_normal" + android:layout_height="wrap_content"> + + <ImageView + android:id="@+id/submission_positive_other_warning_hero_illustration" + bind:cwaContentDescription="@{@string/submission_positive_other_illustration_description}" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:src="@drawable/ic_submission_illustration_other_warning" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + tools:ignore="ContentDescription" /> + + <TextView + android:id="@+id/submission_positive_other_warning_headline" + style="@style/headline5" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + android:accessibilityHeading="true" + android:focusable="true" + android:text="@string/submission_positive_other_warning_headline" + app:layout_constraintEnd_toEndOf="@id/guideline_end" + app:layout_constraintStart_toStartOf="@id/guideline_start" + app:layout_constraintTop_toBottomOf="@+id/submission_positive_other_warning_hero_illustration" /> + + <TextView + android:id="@+id/submission_positive_other_warning_text_first_part" + style="@style/subtitle" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + android:focusable="true" + android:text="@string/submission_positive_other_warning_no_consent_body_first_part" + app:layout_constraintEnd_toEndOf="@id/guideline_end" + app:layout_constraintStart_toStartOf="@id/guideline_start" + app:layout_constraintTop_toBottomOf="@+id/submission_positive_other_warning_headline" /> + + <TextView + android:id="@+id/submission_positive_other_warning_text_second_part" + style="@style/subtitle" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + android:focusable="true" + android:text="@string/submission_positive_other_warning_no_consent_body_second_part" + app:layout_constraintEnd_toEndOf="@id/guideline_end" + app:layout_constraintStart_toStartOf="@id/guideline_start" + app:layout_constraintTop_toBottomOf="@+id/submission_positive_other_warning_text_first_part" /> + + + <de.rki.coronawarnapp.ui.view.CountryListView + android:id="@+id/countryList" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_tiny" + app:layout_constraintEnd_toEndOf="@+id/guideline_end" + app:layout_constraintStart_toStartOf="@+id/guideline_start" + app:layout_constraintTop_toBottomOf="@+id/submission_positive_other_warning_text_second_part" /> + + <include + android:id="@+id/submission_positive_other_privacy" + layout="@layout/include_privacy_card_no_consent" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_small" + app:layout_constraintEnd_toStartOf="@+id/guideline_card_end" + app:layout_constraintStart_toStartOf="@+id/guideline_card_start" + app:layout_constraintTop_toBottomOf="@+id/countryList" /> + + <include + android:id="@+id/submission_no_consent_main_first_point" + layout="@layout/view_bullet_point_text" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + app:itemText="@{@string/submission_consent_main_first_point}" + app:layout_constraintEnd_toEndOf="@id/guideline_end" + app:layout_constraintStart_toStartOf="@id/guideline_start" + app:layout_constraintTop_toBottomOf="@id/submission_positive_other_privacy" /> + + <include + android:id="@+id/submission_no_consent_main_second_point" + layout="@layout/view_bullet_point_text" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_tiny" + app:itemText="@{@string/submission_consent_main_third_point}" + app:layout_constraintEnd_toEndOf="@id/guideline_end" + app:layout_constraintStart_toStartOf="@id/guideline_start" + app:layout_constraintTop_toBottomOf="@id/submission_no_consent_main_first_point" /> + + <include + android:id="@+id/submission_no_consent_main_third_point" + layout="@layout/view_bullet_point_text" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_tiny" + app:itemText="@{@string/submission_consent_main_fourth_point}" + app:layout_constraintEnd_toEndOf="@id/guideline_end" + app:layout_constraintStart_toStartOf="@id/guideline_start" + app:layout_constraintTop_toBottomOf="@id/submission_no_consent_main_second_point" /> + + <FrameLayout + android:id="@+id/divider" + android:layout_width="@dimen/match_constraint" + android:layout_height="@dimen/card_divider" + android:layout_marginTop="@dimen/spacing_small" + android:background="@color/colorHairline" + app:layout_constraintEnd_toEndOf="@id/guideline_end" + app:layout_constraintStart_toStartOf="@id/guideline_start" + app:layout_constraintTop_toBottomOf="@id/submission_no_consent_main_third_point" /> + + <TextView + android:id="@+id/submission_consent_main_bottom_body" + style="@style/subtitle" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:background="?selectableItemBackground" + android:clickable="true" + android:focusable="true" + android:paddingVertical="@dimen/spacing_tiny" + android:text="@string/submission_consent_main_bottom_body" + app:layout_constraintEnd_toEndOf="@id/guideline_end" + app:layout_constraintStart_toStartOf="@id/guideline_start" + app:layout_constraintTop_toBottomOf="@id/divider" /> + + <FrameLayout + android:layout_width="@dimen/match_constraint" + android:layout_height="@dimen/card_divider" + android:background="@color/colorHairline" + app:layout_constraintEnd_toEndOf="@id/guideline_end" + app:layout_constraintStart_toStartOf="@id/guideline_start" + app:layout_constraintTop_toBottomOf="@id/submission_consent_main_bottom_body" /> + + <include layout="@layout/merge_guidelines_side" /> + + <include layout="@layout/merge_guidelines_card" /> + + </androidx.constraintlayout.widget.ConstraintLayout> + </ScrollView> <Button android:id="@+id/submission_positive_other_warning_no_consent_button_next" style="@style/buttonPrimary" android:layout_width="@dimen/match_constraint" android:layout_height="wrap_content" - android:enabled="@{uiState != null && uiState.isSubmitButtonEnabled()}" android:text="@string/submission_accept_button" android:textAllCaps="true" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="@id/guideline_end" app:layout_constraintStart_toStartOf="@id/guideline_start" - app:layout_constraintTop_toBottomOf="@id/guideline_action" /> - - <ProgressBar - android:id="@+id/submission_positive_other_warning_spinner" - style="?android:attr/progressBarStyleHorizontal" - android:layout_width="@dimen/match_constraint" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_large" - android:indeterminate="true" - gone="@{uiState == null || !uiState.isSubmitSpinnerVisible()}" - app:layout_constraintBottom_toBottomOf="@+id/submission_positive_other_warning_no_consent_button_next" - app:layout_constraintEnd_toEndOf="@+id/submission_positive_other_warning_no_consent_button_next" - app:layout_constraintStart_toStartOf="@+id/submission_positive_other_warning_no_consent_button_next" - app:layout_constraintTop_toTopOf="@+id/submission_positive_other_warning_no_consent_button_next" /> + app:layout_constraintTop_toBottomOf="@id/content_scrollcontainer" /> <androidx.constraintlayout.widget.Guideline android:id="@+id/guideline_action" diff --git a/Corona-Warn-App/src/main/res/layout/fragment_submission_result_ready.xml b/Corona-Warn-App/src/main/res/layout/fragment_submission_result_ready.xml new file mode 100644 index 0000000000000000000000000000000000000000..c22d46bd8e62975f57f15c99b5b5938395d6fcfe --- /dev/null +++ b/Corona-Warn-App/src/main/res/layout/fragment_submission_result_ready.xml @@ -0,0 +1,123 @@ +<?xml version="1.0" encoding="utf-8"?> +<layout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:bind="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/submission_done_no_consent_container" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:contentDescription="@string/submission_done_no_consent_title" + android:fillViewport="true" + tools:context=".ui.submission.resultready.SubmissionResultReadyFragment"> + + <include + android:id="@+id/submission_done_no_consent_header" + layout="@layout/include_header" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + app:icon="@{@drawable/ic_close}" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:title="@{@string/submission_done_no_consent_title}" /> + + <ScrollView + android:id="@+id/content_scrollcontainer" + android:layout_width="@dimen/match_constraint" + android:layout_height="@dimen/match_constraint" + android:fillViewport="true" + app:layout_constraintBottom_toTopOf="@+id/submission_done_button_continue_with_symptom_recording" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/submission_done_no_consent_header" + app:layout_constraintVertical_bias="1.0"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingBottom="@dimen/spacing_normal" + android:focusable="true"> + + <ImageView + android:id="@+id/submission_done_hero_illustration" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:focusable="true" + android:src="@drawable/ic_illustration_together" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + bind:cwaContentDescription="@{@string/submission_done_no_consent_illustration_description}" + tools:ignore="ContentDescription" /> + <TextView + android:id="@+id/submission_done_text" + style="@style/headline6" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/spacing_normal" + android:layout_marginEnd="@dimen/spacing_normal" + android:focusable="true" + android:text="@string/submission_test_result_consent_given_subtitle" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/submission_done_hero_illustration" /> + + <TextView + android:id="@+id/submission_done_subtitle" + style="@style/headline6" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + android:accessibilityHeading="true" + android:focusable="true" + android:text="@string/submission_done_no_consent_body_title" + app:layout_constraintEnd_toEndOf="@id/submission_done_text" + app:layout_constraintStart_toStartOf="@id/submission_done_text" + app:layout_constraintTop_toBottomOf="@+id/submission_done_text" /> + + <TextView + android:id="@+id/submission_done_no_consent_body" + style="@style/subtitle" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + android:accessibilityHeading="true" + android:focusable="true" + android:text="@string/submission_done_no_consent_body" + app:layout_constraintEnd_toEndOf="@id/submission_done_text" + app:layout_constraintStart_toStartOf="@id/submission_done_text" + app:layout_constraintTop_toBottomOf="@+id/submission_done_subtitle" /> + </androidx.constraintlayout.widget.ConstraintLayout> + </ScrollView> + + <Button + android:id="@+id/submission_done_button_continue_with_symptom_recording" + style="@style/buttonPrimary" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/spacing_normal" + android:layout_marginEnd="@dimen/spacing_normal" + android:layout_marginBottom="@dimen/spacing_small" + android:text="@string/submission_done_no_consent_continue_with_symptom_recording" + app:layout_constraintBottom_toTopOf="@+id/submission_done_contact_button_finish_flow" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/content_scrollcontainer" /> + + <Button + android:id="@+id/submission_done_contact_button_finish_flow" + style="@style/buttonPrimary" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginBottom="@dimen/spacing_small" + android:text="@string/submission_done_no_consent_break_flow" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="@id/submission_done_button_continue_with_symptom_recording" + app:layout_constraintStart_toStartOf="@id/submission_done_button_continue_with_symptom_recording" + app:layout_constraintTop_toBottomOf="@+id/submission_done_button_continue_with_symptom_recording" /> + + + </androidx.constraintlayout.widget.ConstraintLayout> +</layout> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/layout/fragment_submission_symptom_calendar.xml b/Corona-Warn-App/src/main/res/layout/fragment_submission_symptom_calendar.xml index ecf73ebc437f034b2ec90d622215160aba1e9a20..c747b4a3cc0c20c9a503a98d73234f7167514f7c 100644 --- a/Corona-Warn-App/src/main/res/layout/fragment_submission_symptom_calendar.xml +++ b/Corona-Warn-App/src/main/res/layout/fragment_submission_symptom_calendar.xml @@ -4,109 +4,107 @@ xmlns:tools="http://schemas.android.com/tools"> <data> - - <import type="de.rki.coronawarnapp.util.formatter.FormatterSubmissionHelper" /> - <import type="de.rki.coronawarnapp.submission.Symptoms.StartOf" /> - </data> - <ScrollView + <LinearLayout android:layout_width="match_parent" - android:layout_height="match_parent"> + android:layout_height="wrap_content" + android:orientation="vertical"> - <androidx.constraintlayout.widget.ConstraintLayout + <include + android:id="@+id/submission_symptom_calendar_header" + layout="@layout/include_header" android:layout_width="match_parent" android:layout_height="wrap_content" - android:fillViewport="true" - android:focusable="true" - tools:context=".ui.submission.symptoms.calendar.SubmissionSymptomCalendarFragment"> + app:icon="@{@drawable/ic_back}" + app:title="@{@string/submission_symptom_calendar_title}" /> - <include - android:id="@+id/submission_symptom_calendar_header" - layout="@layout/include_header" - android:layout_width="@dimen/match_constraint" - android:layout_height="wrap_content" - app:icon="@{@drawable/ic_back}" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent" - app:title="@{@string/submission_symptom_calendar_title}" /> - - <TextView - android:id="@+id/submission_symptom_calendar_headline" - style="@style/headline5" - android:layout_width="@dimen/match_constraint" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_normal" - android:accessibilityHeading="true" - android:text="@string/submission_symptom_calendar_headline" - app:layout_constraintEnd_toEndOf="@id/guideline_end" - app:layout_constraintStart_toStartOf="@id/guideline_start" - app:layout_constraintTop_toBottomOf="@+id/submission_symptom_calendar_header" /> - - <TextView - android:id="@+id/submission_symptom_calendar_body" - style="@style/body1" - android:layout_width="@dimen/match_constraint" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_normal" - android:accessibilityHeading="true" - android:text="@string/submission_symptom_calendar_body" - app:layout_constraintEnd_toEndOf="@id/guideline_end" - app:layout_constraintStart_toStartOf="@id/guideline_start" - app:layout_constraintTop_toBottomOf="@+id/submission_symptom_calendar_headline" /> - - <de.rki.coronawarnapp.ui.calendar.CalendarView - android:id="@+id/symptom_calendar_container" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_normal" - app:layout_constraintEnd_toEndOf="@id/guideline_end" - app:layout_constraintStart_toStartOf="@id/guideline_start" - app:layout_constraintTop_toBottomOf="@+id/submission_symptom_calendar_body"/> + <ScrollView + android:layout_width="match_parent" + android:layout_height="match_parent"> - <include - android:id="@+id/symptom_calendar_choice_selection" - layout="@layout/include_submission_symptom_length_selection" - android:layout_width="@dimen/match_constraint" + <LinearLayout + android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_marginStart="@dimen/spacing_normal" + android:layout_marginEnd="@dimen/spacing_normal" + android:fillViewport="true" android:focusable="true" - app:layout_constraintEnd_toEndOf="@id/guideline_end" - app:layout_constraintStart_toStartOf="@id/guideline_start" - app:layout_constraintTop_toBottomOf="@+id/symptom_calendar_container" /> - - <Button - android:id="@+id/symptom_button_next" - style="@style/buttonPrimary" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_marginBottom="@dimen/spacing_small" - android:layout_marginTop="@dimen/spacing_small" - android:text="@string/submission_symptom_further_button" - app:layout_constraintBottom_toTopOf="@id/guideline_bottom" - app:layout_constraintEnd_toEndOf="@id/guideline_end" - app:layout_constraintStart_toStartOf="@id/guideline_start" - app:layout_constraintTop_toBottomOf="@+id/symptom_calendar_choice_selection"/> - - <include layout="@layout/merge_guidelines_side" /> - - <androidx.constraintlayout.widget.Guideline - android:id="@+id/guideline_top" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:orientation="horizontal" - app:layout_constraintGuide_begin="@dimen/guideline_top" /> - - <androidx.constraintlayout.widget.Guideline - android:id="@+id/guideline_bottom" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:orientation="horizontal" - app:layout_constraintGuide_end="@dimen/spacing_small" /> - - </androidx.constraintlayout.widget.ConstraintLayout> - - </ScrollView> - + android:orientation="vertical" + tools:context=".ui.submission.symptoms.calendar.SubmissionSymptomCalendarFragment"> + + <TextView + android:id="@+id/submission_symptom_calendar_headline" + style="@style/headline6" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + android:accessibilityHeading="true" + android:text="@string/submission_symptom_calendar_headline" /> + + <TextView + android:id="@+id/submission_symptom_calendar_body" + style="@style/body1" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + android:accessibilityHeading="true" + android:text="@string/submission_symptom_calendar_body" /> + + <de.rki.coronawarnapp.ui.calendar.CalendarView + android:id="@+id/symptom_calendar_container" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" /> + + <Button + android:id="@+id/calendar_button_seven_days" + style="@style/selectionButton" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_small" + android:enabled="true" + android:text="@string/submission_symptom_less_seven" /> + + <Button + android:id="@+id/calendar_button_one_two_weeks" + style="@style/selectionButton" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_small" + android:enabled="true" + android:text="@string/submission_symptom_one_two_weeks" /> + + <Button + android:id="@+id/calendar_button_more_than_two_weeks" + style="@style/selectionButton" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_small" + android:enabled="true" + android:text="@string/submission_symptom_more_two_weeks" /> + + <Button + android:id="@+id/target_button_verify" + style="@style/selectionButton" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_small" + android:layout_marginBottom="@dimen/spacing_small" + android:enabled="true" + android:text="@string/submission_symptom_verify" /> + + <Button + android:id="@+id/symptom_button_next" + style="@style/buttonPrimary" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginBottom="@dimen/spacing_small" + android:text="@string/submission_done_button_done" /> + + </LinearLayout> + + </ScrollView> + </LinearLayout> </layout> diff --git a/Corona-Warn-App/src/main/res/layout/fragment_submission_symptom_intro.xml b/Corona-Warn-App/src/main/res/layout/fragment_submission_symptom_intro.xml index e577341719fc20305e51f0ef2b7ea5eaeb8d37e2..340a9a07456425ce15c039907ee01eabe20d75e7 100644 --- a/Corona-Warn-App/src/main/res/layout/fragment_submission_symptom_intro.xml +++ b/Corona-Warn-App/src/main/res/layout/fragment_submission_symptom_intro.xml @@ -1,113 +1,97 @@ <?xml version="1.0" encoding="utf-8"?> <layout 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"> - - <data> - - <import type="de.rki.coronawarnapp.util.formatter.FormatterSubmissionHelper" /> - - </data> - - <ScrollView + xmlns:app="http://schemas.android.com/apk/res-auto"> + <LinearLayout android:layout_width="match_parent" - android:layout_height="match_parent"> + android:layout_height="wrap_content" + android:orientation="vertical"> - <androidx.constraintlayout.widget.ConstraintLayout - android:id="@+id/submission_symptom_container" + <include + android:id="@+id/submission_symptom_header" + layout="@layout/include_header" android:layout_width="match_parent" android:layout_height="wrap_content" - android:fillViewport="true" - android:focusable="true" - tools:context=".ui.submission.fragment.SubmissionIntroFragment"> - - <include - android:id="@+id/submission_symptom_header" - layout="@layout/include_header" - android:layout_width="@dimen/match_constraint" - android:layout_height="wrap_content" - app:icon="@{@drawable/ic_back}" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent" - app:title="@{@string/submission_symptom_title}" /> + app:icon="@{@drawable/ic_back}" + app:title="@{@string/submission_symptom_title}" /> - <TextView - android:id="@+id/submission_symptom_initial_headline" - style="@style/headline5" - android:layout_width="@dimen/match_constraint" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_normal" - android:accessibilityHeading="true" - android:text="@string/submission_symptom_initial_headline" - app:layout_constraintEnd_toEndOf="@id/guideline_end" - app:layout_constraintStart_toStartOf="@id/guideline_start" - app:layout_constraintTop_toBottomOf="@+id/submission_symptom_header" /> - - <de.rki.coronawarnapp.ui.view.BulletPointList - android:id="@+id/further_info_text" - android:layout_width="@dimen/match_constraint" - android:layout_height="wrap_content" - android:focusable="true" - android:layout_marginTop="@dimen/spacing_normal" - app:entries="@array/submission_symptom_symptom_bullets" - app:layout_constraintEnd_toEndOf="@id/guideline_end" - app:layout_constraintStart_toStartOf="@id/guideline_start" - app:layout_constraintTop_toBottomOf="@+id/submission_symptom_initial_headline" /> - - <TextView - android:id="@+id/submission_symptom_intro_explanation" - style="@style/subtitleMedium" - android:layout_width="@dimen/match_constraint" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_normal" - android:text="@string/submission_symptom_initial_explanation" - app:layout_constraintEnd_toEndOf="@id/guideline_end" - app:layout_constraintStart_toStartOf="@id/guideline_start" - app:layout_constraintTop_toBottomOf="@+id/further_info_text" /> + <ScrollView + android:layout_width="match_parent" + android:layout_height="match_parent"> - <include - android:id="@+id/symptom_choice_selection" - layout="@layout/include_submission_target_selection" - android:layout_width="@dimen/match_constraint" + <LinearLayout + android:id="@+id/submission_symptom_container" + android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_normal" + android:layout_marginStart="@dimen/spacing_normal" + android:layout_marginEnd="@dimen/spacing_normal" + android:fillViewport="true" android:focusable="true" - app:layout_constraintEnd_toEndOf="@id/guideline_end" - app:layout_constraintStart_toStartOf="@id/guideline_start" - app:layout_constraintTop_toBottomOf="@+id/submission_symptom_intro_explanation" /> - - <Button - android:id="@+id/symptom_button_next" - style="@style/buttonPrimary" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_marginBottom="@dimen/spacing_small" - android:layout_marginTop="@dimen/spacing_small" - android:text="@string/submission_symptom_further_button" - app:layout_constraintBottom_toTopOf="@id/guideline_bottom" - app:layout_constraintEnd_toEndOf="@id/guideline_end" - app:layout_constraintStart_toStartOf="@id/guideline_start" - app:layout_constraintTop_toBottomOf="@+id/symptom_choice_selection"/> - - <include layout="@layout/merge_guidelines_side" /> - - <androidx.constraintlayout.widget.Guideline - android:id="@+id/guideline_top" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:orientation="horizontal" - app:layout_constraintGuide_begin="@dimen/guideline_top" /> - - <androidx.constraintlayout.widget.Guideline - android:id="@+id/guideline_bottom" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:orientation="horizontal" - app:layout_constraintGuide_end="@dimen/spacing_small" /> - - </androidx.constraintlayout.widget.ConstraintLayout> - - </ScrollView> - + android:orientation="vertical"> + + <TextView + android:id="@+id/submission_symptom_initial_headline" + style="@style/headline6" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + android:accessibilityHeading="true" + android:text="@string/submission_symptom_initial_headline" /> + + <de.rki.coronawarnapp.ui.view.BulletPointList + android:id="@+id/further_info_text" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + android:focusable="true" + app:entries="@array/submission_symptom_symptom_bullets" /> + + <TextView + android:id="@+id/submission_symptom_intro_explanation" + style="@style/subtitleMedium" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + android:text="@string/submission_symptom_initial_explanation" /> + + + <Button + android:id="@+id/target_button_apply" + style="@style/selectionButton" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_small" + android:enabled="true" + android:text="@string/submission_symptom_positive_button" /> + + <Button + android:id="@+id/target_button_reject" + style="@style/selectionButton" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_small" + android:enabled="true" + android:text="@string/submission_symptom_negative_button" /> + + <Button + android:id="@+id/target_button_verify" + style="@style/selectionButton" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_small" + android:enabled="true" + android:text="@string/submission_symptom_no_information_button" /> + + <Button + android:id="@+id/symptom_button_next" + style="@style/buttonPrimary" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_small" + android:layout_marginBottom="@dimen/spacing_small" + android:text="@string/submission_symptom_further_button" /> + + </LinearLayout> + + </ScrollView> + </LinearLayout> </layout> diff --git a/Corona-Warn-App/src/main/res/layout/fragment_submission_test_result.xml b/Corona-Warn-App/src/main/res/layout/fragment_submission_test_result.xml index d49564836bfe50f625dc07692df7f6ef597836f0..3e185410851021986b2a712996c22f5963f29a9e 100644 --- a/Corona-Warn-App/src/main/res/layout/fragment_submission_test_result.xml +++ b/Corona-Warn-App/src/main/res/layout/fragment_submission_test_result.xml @@ -13,10 +13,10 @@ <androidx.constraintlayout.widget.ConstraintLayout android:id="@+id/submission_test_result_container" - android:contentDescription="@string/submission_test_result_headline" - android:accessibilityLiveRegion="assertive" android:layout_width="match_parent" - android:layout_height="match_parent"> + android:layout_height="match_parent" + android:accessibilityLiveRegion="assertive" + android:contentDescription="@string/submission_test_result_headline"> <include android:id="@+id/submission_test_result_header" @@ -40,9 +40,9 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> - <include + <ScrollView + android:id="@+id/submission_test_result_content" - layout="@layout/include_submission_test_result" android:layout_width="@dimen/match_constraint" android:layout_height="@dimen/match_constraint" android:layout_marginBottom="@dimen/button_padding_top_bottom" @@ -52,8 +52,111 @@ app:layout_constraintBottom_toTopOf="@+id/include_submission_test_result_buttons" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@+id/submission_test_result_header" - app:uiState="@{uiState}" /> + app:layout_constraintTop_toBottomOf="@+id/submission_test_result_header"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <de.rki.coronawarnapp.ui.view.TestResultSectionView + android:id="@+id/submission_test_result_section" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_small" + android:focusable="true" + android:importantForAccessibility="yes" + app:layout_constraintEnd_toEndOf="@+id/guideline_card_end" + app:layout_constraintStart_toStartOf="@+id/guideline_card_start" + app:layout_constraintTop_toTopOf="parent" + app:test_result_section_headline="@string/test_result_card_headline" /> + + <TextView + android:id="@+id/submission_test_result_subtitle" + style="@style/headline5" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_medium" + android:accessibilityHeading="true" + android:text="@string/submission_test_result_subtitle" + app:layout_constraintEnd_toEndOf="@+id/guideline_end" + app:layout_constraintStart_toStartOf="@+id/guideline_start" + app:layout_constraintTop_toBottomOf="@+id/submission_test_result_section" /> + + <include + android:id="@+id/submission_test_result_pending_steps" + layout="@layout/include_test_result_pending_steps" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + android:visibility="@{FormatterSubmissionHelper.formatTestResultPendingStepsVisible(uiState.deviceUiState)}" + app:layout_constraintEnd_toEndOf="@+id/guideline_end" + app:layout_constraintStart_toStartOf="@+id/guideline_start" + app:layout_constraintTop_toBottomOf="@+id/submission_test_result_subtitle" /> + + <de.rki.coronawarnapp.ui.submission.consentstatus.ConsentStatusView + android:id="@+id/consent_status" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginBottom="@dimen/spacing_medium" + android:focusable="true" + android:paddingBottom="@dimen/spacing_small" + android:visibility="@{FormatterSubmissionHelper.formatTestResultPendingStepsVisible(uiState.deviceUiState)}" + app:layout_constraintEnd_toEndOf="@id/guideline_end" + app:layout_constraintStart_toStartOf="@id/guideline_start" + app:layout_constraintTop_toBottomOf="@+id/submission_test_result_pending_steps" /> + + <include + android:id="@+id/submission_test_result_negative_steps" + layout="@layout/include_test_result_negative_steps" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + android:visibility="@{FormatterSubmissionHelper.formatTestResultNegativeStepsVisible(uiState.deviceUiState)}" + app:layout_constraintEnd_toEndOf="@+id/guideline_end" + app:layout_constraintStart_toStartOf="@+id/guideline_start" + app:layout_constraintTop_toBottomOf="@+id/submission_test_result_subtitle" /> + + <include + android:id="@+id/submission_test_result_negative_info" + layout="@layout/include_submission_test_result_negative_further_info" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + android:visibility="@{FormatterSubmissionHelper.formatTestResultNegativeStepsVisible(uiState.deviceUiState)}" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/submission_test_result_negative_steps" /> + + <include + android:id="@+id/submission_test_result_positive_steps" + layout="@layout/include_test_result_positive_steps" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + android:visibility="@{FormatterSubmissionHelper.formatTestResultPositiveStepsVisible(uiState.deviceUiState)}" + app:layout_constraintEnd_toEndOf="@+id/guideline_end" + app:layout_constraintStart_toStartOf="@+id/guideline_start" + app:layout_constraintTop_toBottomOf="@+id/submission_test_result_subtitle" /> + + <include + android:id="@+id/submission_test_result_invalid_steps" + layout="@layout/include_test_result_invalid_steps" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + android:visibility="@{FormatterSubmissionHelper.formatTestResultInvalidStepsVisible(uiState.deviceUiState)}" + app:layout_constraintEnd_toEndOf="@+id/guideline_end" + app:layout_constraintStart_toStartOf="@+id/guideline_start" + app:layout_constraintTop_toBottomOf="@+id/submission_test_result_subtitle" /> + + + <include layout="@layout/merge_guidelines_side" /> + + <include layout="@layout/merge_guidelines_card" /> + + </androidx.constraintlayout.widget.ConstraintLayout> + </ScrollView> + <androidx.constraintlayout.widget.Barrier android:id="@+id/include_submission_test_result_buttons" android:layout_width="wrap_content" diff --git a/Corona-Warn-App/src/main/res/layout/fragment_submission_test_result_available.xml b/Corona-Warn-App/src/main/res/layout/fragment_submission_test_result_available.xml index b7f47def3e6821ccd10d68c4976e2d177368b6de..ce68d1236ec7c23becc6ffca39d595d40ab33e5d 100644 --- a/Corona-Warn-App/src/main/res/layout/fragment_submission_test_result_available.xml +++ b/Corona-Warn-App/src/main/res/layout/fragment_submission_test_result_available.xml @@ -72,7 +72,7 @@ app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@+id/submission_consent_status" /> + app:layout_constraintTop_toBottomOf="@+id/submission_test_result_available_consent_status" /> <include layout="@layout/merge_guidelines_side" /> @@ -86,7 +86,7 @@ android:layout_width="@dimen/match_constraint" android:layout_height="wrap_content" android:layout_marginVertical="@dimen/spacing_normal" - android:text="@string/submission_done_button_done" + android:text="@string/submission_intro_button_next" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="@id/guideline_end" app:layout_constraintStart_toStartOf="@id/guideline_start" diff --git a/Corona-Warn-App/src/main/res/layout/fragment_submission_test_result_positive_no_consent.xml b/Corona-Warn-App/src/main/res/layout/fragment_submission_test_result_positive_no_consent.xml index 1abb894a25f35de4b6884e082c208711e0f3860d..c2e176272b8da319ca764390f9cd1a703d770a11 100644 --- a/Corona-Warn-App/src/main/res/layout/fragment_submission_test_result_positive_no_consent.xml +++ b/Corona-Warn-App/src/main/res/layout/fragment_submission_test_result_positive_no_consent.xml @@ -1,9 +1,9 @@ <?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto"> + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools"> - <data> - </data> + <data></data> <androidx.constraintlayout.widget.ConstraintLayout android:id="@+id/submission_test_result_layout" @@ -53,12 +53,13 @@ <TextView android:id="@+id/submission_test_result_positive_no_consent_subtitle" - style="@style/headline6" + style="@style/headline5" android:accessibilityHeading="true" android:layout_width="@dimen/match_constraint" android:layout_height="wrap_content" android:layout_marginTop="@dimen/spacing_medium" android:text="@string/submission_test_result_positive_no_consent_subtitle" + tools:text="Bitte helfen Sie mit" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/submission_test_result_section" /> @@ -83,6 +84,7 @@ android:layout_height="wrap_content" android:layout_marginTop="@dimen/spacing_normal" android:layout_marginStart="@dimen/spacing_small" + tools:text="Helfen Sie mit, Ihre Mitmenschen vor Ansteckungen zu schützen und teilen Sie Ihr Testergebnis." app:layout_constraintTop_toBottomOf="@+id/submission_test_result_positive_no_consent_subtitle" app:layout_constraintStart_toEndOf="@id/submission_test_result_positive_no_consent_icon_1" app:layout_constraintEnd_toEndOf="parent" diff --git a/Corona-Warn-App/src/main/res/layout/fragment_submission_your_consent.xml b/Corona-Warn-App/src/main/res/layout/fragment_submission_your_consent.xml index 25b2b937186b9bbeaddb6fd01981933a423ac9ea..d0bfb607b07904a05019b1f3adc8e61cad586b90 100644 --- a/Corona-Warn-App/src/main/res/layout/fragment_submission_your_consent.xml +++ b/Corona-Warn-App/src/main/res/layout/fragment_submission_your_consent.xml @@ -122,7 +122,9 @@ style="@style/subtitle" android:layout_width="@dimen/match_constraint" android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_small" + android:background="?selectableItemBackground" + android:paddingTop="@dimen/spacing_small" + android:paddingBottom="@dimen/spacing_small" android:text="@string/submission_your_consent_agreement_details" app:layout_constraintEnd_toEndOf="@id/guideline_end" app:layout_constraintStart_toStartOf="@id/guideline_start" @@ -132,7 +134,6 @@ android:id="@+id/submission_your_consent_agreement_details_divider_bottom" android:layout_width="@dimen/match_constraint" android:layout_height="@dimen/card_divider" - android:layout_marginTop="@dimen/spacing_small" android:background="@color/colorHairline" app:layout_constraintEnd_toEndOf="@+id/guideline_end" app:layout_constraintStart_toStartOf="@+id/guideline_start" diff --git a/Corona-Warn-App/src/main/res/layout/fragment_test_submission_tekhistory_line.xml b/Corona-Warn-App/src/main/res/layout/fragment_test_submission_tekhistory_line.xml new file mode 100644 index 0000000000000000000000000000000000000000..bfe4c877e830d20f6fcd18f50657bf96b054bc89 --- /dev/null +++ b/Corona-Warn-App/src/main/res/layout/fragment_test_submission_tekhistory_line.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.constraintlayout.widget.ConstraintLayout 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="wrap_content"> + <TextView + android:id="@+id/primary" + style="@style/body2" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginStart="16dp" + android:layout_marginTop="8dp" + android:layout_marginEnd="16dp" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + tools:text="rollingStartIntervalNumber=2677680 rollingPeriod=144" /> + + <TextView + android:id="@+id/secondary" + style="@style/TextAppearance.AppCompat.Caption" + android:layout_width="0dp" + android:layout_height="wrap_content" + app:layout_constraintEnd_toEndOf="@id/primary" + app:layout_constraintStart_toStartOf="@id/primary" + app:layout_constraintTop_toBottomOf="@id/primary" + tools:text="daysSinceOnsetOfSymptoms=2147483647\ntransmissionRiskLevel=0 reportType=0" /> + +</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/layout/include_submission_positive_other_warning_no_consent.xml b/Corona-Warn-App/src/main/res/layout/include_submission_positive_other_warning_no_consent.xml deleted file mode 100644 index 22414b1cd08281e3647a626fcf05c9ebadd931bb..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/res/layout/include_submission_positive_other_warning_no_consent.xml +++ /dev/null @@ -1,156 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<layout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto" - xmlns:bind="http://schemas.android.com/apk/res-auto" - xmlns:tools="http://schemas.android.com/tools"> - - <data> - - <variable - name="countryData" - type="java.util.List<de.rki.coronawarnapp.ui.Country>" /> - - <variable - name="viewModel" - type="de.rki.coronawarnapp.ui.submission.warnothers.SubmissionResultPositiveOtherWarningNoConsentViewModel" /> - - </data> - - <ScrollView - android:layout_width="match_parent" - android:layout_height="match_parent"> - - <androidx.constraintlayout.widget.ConstraintLayout - android:layout_width="match_parent" - android:layout_height="wrap_content"> - - <ImageView - android:id="@+id/submission_positive_other_warning_hero_illustration" - android:layout_width="@dimen/match_constraint" - android:layout_height="wrap_content" - android:src="@drawable/ic_submission_illustration_other_warning" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent" - bind:cwaContentDescription="@{@string/submission_positive_other_illustration_description}" - tools:ignore="ContentDescription" /> - - <TextView - android:id="@+id/submission_positive_other_warning_headline" - style="@style/headline5" - android:layout_width="@dimen/match_constraint" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_normal" - android:accessibilityHeading="true" - android:focusable="true" - android:text="@string/submission_positive_other_warning_headline" - app:layout_constraintEnd_toEndOf="@id/guideline_end" - app:layout_constraintStart_toStartOf="@id/guideline_start" - app:layout_constraintTop_toBottomOf="@+id/submission_positive_other_warning_hero_illustration" /> - - <TextView - android:id="@+id/submission_positive_other_warning_text_first_part" - style="@style/subtitle" - android:layout_width="@dimen/match_constraint" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_normal" - android:focusable="true" - android:text="@string/submission_positive_other_warning_no_consent_body_first_part" - app:layout_constraintEnd_toEndOf="@id/guideline_end" - app:layout_constraintStart_toStartOf="@id/guideline_start" - app:layout_constraintTop_toBottomOf="@+id/submission_positive_other_warning_headline" /> - - <TextView - android:id="@+id/submission_positive_other_warning_text_second_part" - style="@style/subtitle" - android:layout_width="@dimen/match_constraint" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_normal" - android:focusable="true" - android:text="@string/submission_positive_other_warning_no_consent_body_second_part" - app:layout_constraintEnd_toEndOf="@id/guideline_end" - app:layout_constraintStart_toStartOf="@id/guideline_start" - app:layout_constraintTop_toBottomOf="@+id/submission_positive_other_warning_text_first_part" /> - - - <de.rki.coronawarnapp.ui.view.CountryListView - android:id="@+id/countryList" - android:layout_width="@dimen/match_constraint" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_tiny" - app:countryList="@{countryData}" - app:layout_constraintEnd_toEndOf="@+id/guideline_end" - app:layout_constraintStart_toStartOf="@+id/guideline_start" - app:layout_constraintTop_toBottomOf="@+id/submission_positive_other_warning_text_second_part" /> - - <include - android:id="@+id/submission_positive_other_privacy" - layout="@layout/include_privacy_card_no_consent" - android:layout_width="@dimen/match_constraint" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_large" - app:layout_constraintEnd_toStartOf="@+id/guideline_card_end" - app:layout_constraintStart_toStartOf="@+id/guideline_card_start" - app:layout_constraintTop_toBottomOf="@+id/countryList" /> - - <include layout="@layout/view_bullet_point_text" - android:id="@+id/submission_no_consent_main_first_point" - android:layout_width="@dimen/match_constraint" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_normal" - app:layout_constraintEnd_toEndOf="@id/guideline_end" - app:layout_constraintStart_toStartOf="@id/guideline_start" - app:layout_constraintTop_toBottomOf="@id/submission_positive_other_privacy" - app:itemText="@{@string/submission_consent_main_first_point}" /> - - <include layout="@layout/view_bullet_point_text" - android:id="@+id/submission_no_consent_main_second_point" - android:layout_width="@dimen/match_constraint" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_tiny" - app:layout_constraintEnd_toEndOf="@id/guideline_end" - app:layout_constraintStart_toStartOf="@id/guideline_start" - app:layout_constraintTop_toBottomOf="@id/submission_no_consent_main_first_point" - app:itemText="@{@string/submission_consent_main_third_point}" /> - - - <include layout="@layout/view_bullet_point_text" - android:id="@+id/submission_no_consent_main_third_point" - android:layout_width="@dimen/match_constraint" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_tiny" - app:layout_constraintEnd_toEndOf="@id/guideline_end" - app:layout_constraintStart_toStartOf="@id/guideline_start" - app:layout_constraintTop_toBottomOf="@id/submission_no_consent_main_second_point" - app:itemText="@{@string/submission_consent_main_fourth_point}" /> - - - - <TextView - android:id="@+id/submission_consent_main_bottom_body" - style="@style/subtitle" - android:layout_width="@dimen/match_constraint" - android:layout_height="wrap_content" - android:background="?selectableItemBackground" - android:clickable="true" - android:focusable="true" - android:onClick="@{ () -> viewModel.onDataPrivacyClick() }" - android:paddingVertical="@dimen/spacing_tiny" - android:text="@string/submission_consent_main_bottom_body" - app:layout_constraintEnd_toEndOf="@id/guideline_end" - app:layout_constraintStart_toStartOf="@id/guideline_start" - app:layout_constraintTop_toBottomOf="@id/submission_no_consent_main_third_point" /> - - <androidx.constraintlayout.widget.Guideline - android:id="@+id/guideline_action" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:orientation="horizontal" - app:layout_constraintGuide_end="@dimen/guideline_action" /> - <include layout="@layout/merge_guidelines_side" /> - - <include layout="@layout/merge_guidelines_card" /> - - </androidx.constraintlayout.widget.ConstraintLayout> - </ScrollView> -</layout> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/layout/include_submission_status_card_done.xml b/Corona-Warn-App/src/main/res/layout/include_submission_status_card_done.xml index 44aae6bb807ed617ca3bf333ec91a1ca86949b9e..f1516fb761529e5b1e79ac139c656fe310af9e0c 100644 --- a/Corona-Warn-App/src/main/res/layout/include_submission_status_card_done.xml +++ b/Corona-Warn-App/src/main/res/layout/include_submission_status_card_done.xml @@ -19,22 +19,10 @@ android:layout_marginTop="@dimen/spacing_normal" android:layout_marginEnd="@dimen/spacing_small" android:text="@string/submission_done_title" - app:layout_constraintEnd_toStartOf="@+id/submission_done_card_icon" + app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> - <include - android:id="@+id/submission_done_card_icon" - layout="@layout/include_button_icon" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginEnd="@dimen/spacing_normal" - app:icon="@{@drawable/ic_forward}" - app:iconDescription="@{@string/accessibility_next}" - app:layout_constraintBottom_toBottomOf="@+id/submission_done_card_title" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintTop_toTopOf="@+id/submission_done_card_title" /> - <ImageView android:id="@+id/submission_done_card_illustration" android:layout_width="@dimen/match_constraint" diff --git a/Corona-Warn-App/src/main/res/layout/include_submission_status_card_positive.xml b/Corona-Warn-App/src/main/res/layout/include_submission_status_card_positive.xml index e10fd40921c3cf0fb810bedd9bc9a85aa855cb5c..5d57d6819bb3003d2ed5a99ae2475b3186b07898 100644 --- a/Corona-Warn-App/src/main/res/layout/include_submission_status_card_positive.xml +++ b/Corona-Warn-App/src/main/res/layout/include_submission_status_card_positive.xml @@ -105,7 +105,7 @@ android:layout_width="@dimen/match_constraint" android:layout_height="wrap_content" android:layout_marginTop="@dimen/spacing_normal" - android:text="@string/submission_test_result_positive_continue_button" + android:text="@string/submission_test_result_positive_no_consent_button_warn_others" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/submission_status_card_positive_result_share" /> diff --git a/Corona-Warn-App/src/main/res/layout/include_submission_symptom_length_selection.xml b/Corona-Warn-App/src/main/res/layout/include_submission_symptom_length_selection.xml deleted file mode 100644 index 6cbbd318066a22c37059ae2209bd487f7851b341..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/res/layout/include_submission_symptom_length_selection.xml +++ /dev/null @@ -1,69 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<layout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto"> - - <data> - - <import type="de.rki.coronawarnapp.util.formatter.FormatterSubmissionHelper" /> - - <import type="de.rki.coronawarnapp.submission.Symptoms.StartOf" /> - - </data> - - <androidx.constraintlayout.widget.ConstraintLayout - android:id="@+id/target_layout" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:focusable="true"> - - <Button - android:id="@+id/calendar_button_seven_days" - style="@style/selectionButton" - android:enabled="true" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_small" - android:text="@{@string/submission_symptom_less_seven}" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent" - /> - - <Button - android:id="@+id/calendar_button_one_two_weeks" - style="@style/selectionButton" - android:enabled="true" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_small" - android:text="@{@string/submission_symptom_one_two_weeks}" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@id/calendar_button_seven_days" /> - - <Button - android:id="@+id/calendar_button_more_than_two_weeks" - style="@style/selectionButton" - android:enabled="true" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_small" - android:text="@{@string/submission_symptom_more_two_weeks}" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintTop_toBottomOf="@id/calendar_button_one_two_weeks" /> - - <Button - android:id="@+id/target_button_verify" - style="@style/selectionButton" - android:enabled="true" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_small" - android:text="@{@string/submission_symptom_verify}" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintTop_toBottomOf="@id/calendar_button_more_than_two_weeks" /> - - </androidx.constraintlayout.widget.ConstraintLayout> -</layout> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/layout/include_submission_target_selection.xml b/Corona-Warn-App/src/main/res/layout/include_submission_target_selection.xml deleted file mode 100644 index 885289e1986f84037042802f1800f3aa632997b4..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/res/layout/include_submission_target_selection.xml +++ /dev/null @@ -1,48 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<layout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto"> - - <androidx.constraintlayout.widget.ConstraintLayout - android:id="@+id/target_layout" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:focusable="true"> - - <Button - android:id="@+id/target_button_apply" - style="@style/selectionButton" - android:enabled="true" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_small" - android:text="@{@string/submission_symptom_positive_button}" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent" /> - - <Button - android:id="@+id/target_button_reject" - style="@style/selectionButton" - android:enabled="true" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_small" - android:text="@{@string/submission_symptom_negative_button}" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@id/target_button_apply" /> - - <Button - android:id="@+id/target_button_verify" - style="@style/selectionButton" - android:enabled="true" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_small" - android:text="@{@string/submission_symptom_no_information_button}" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintTop_toBottomOf="@id/target_button_reject" /> - - </androidx.constraintlayout.widget.ConstraintLayout> -</layout> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/layout/include_submission_test_result.xml b/Corona-Warn-App/src/main/res/layout/include_submission_test_result.xml deleted file mode 100644 index b162d9145f4056bf027767cb44a8c7d775932b64..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/res/layout/include_submission_test_result.xml +++ /dev/null @@ -1,119 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<layout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto"> - - <data> - <import type="de.rki.coronawarnapp.util.formatter.FormatterSubmissionHelper" /> - <variable - name="uiState" - type="de.rki.coronawarnapp.ui.submission.testresult.TestResultUIState" /> - </data> - - - <ScrollView - android:layout_width="match_parent" - android:layout_height="match_parent"> - - <androidx.constraintlayout.widget.ConstraintLayout - android:layout_width="match_parent" - android:layout_height="wrap_content"> - - <de.rki.coronawarnapp.ui.view.TestResultSectionView - android:id="@+id/submission_test_result_section" - android:layout_width="@dimen/match_constraint" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_small" - android:focusable="true" - android:importantForAccessibility="yes" - app:test_result_section_headline="@string/test_result_card_headline" - app:layout_constraintEnd_toEndOf="@+id/guideline_card_end" - app:layout_constraintStart_toStartOf="@+id/guideline_card_start" - app:layout_constraintTop_toTopOf="parent"/> - - <TextView - android:id="@+id/submission_test_result_subtitle" - style="@style/headline5" - android:accessibilityHeading="true" - android:layout_width="@dimen/match_constraint" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_medium" - android:text="@string/submission_test_result_subtitle" - app:layout_constraintEnd_toEndOf="@+id/guideline_end" - app:layout_constraintStart_toStartOf="@+id/guideline_start" - app:layout_constraintTop_toBottomOf="@+id/submission_test_result_section" /> - - <include - android:id="@+id/submission_test_result_pending_steps" - layout="@layout/include_test_result_pending_steps" - android:layout_width="@dimen/match_constraint" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_normal" - android:visibility="@{FormatterSubmissionHelper.formatTestResultPendingStepsVisible(uiState.deviceUiState)}" - app:layout_constraintEnd_toEndOf="@+id/guideline_end" - app:layout_constraintStart_toStartOf="@+id/guideline_start" - app:layout_constraintTop_toBottomOf="@+id/submission_test_result_subtitle" /> - - <de.rki.coronawarnapp.ui.submission.consentstatus.ConsentStatusView - android:id="@+id/consent_status" - android:layout_width="@dimen/match_constraint" - android:layout_height="wrap_content" - android:layout_marginBottom="@dimen/spacing_medium" - android:paddingBottom="@dimen/spacing_small" - android:focusable="true" - android:visibility="@{FormatterSubmissionHelper.formatTestResultPendingStepsVisible(uiState.deviceUiState)}" - app:layout_constraintEnd_toEndOf="@id/guideline_end" - app:layout_constraintStart_toStartOf="@id/guideline_start" - app:layout_constraintTop_toBottomOf="@+id/submission_test_result_pending_steps" /> - - <include - android:id="@+id/submission_test_result_negative_steps" - layout="@layout/include_test_result_negative_steps" - android:layout_width="@dimen/match_constraint" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_normal" - android:visibility="@{FormatterSubmissionHelper.formatTestResultNegativeStepsVisible(uiState.deviceUiState)}" - app:layout_constraintEnd_toEndOf="@+id/guideline_end" - app:layout_constraintStart_toStartOf="@+id/guideline_start" - app:layout_constraintTop_toBottomOf="@+id/submission_test_result_subtitle" /> - - <include - android:id="@+id/submission_test_result_negative_info" - layout="@layout/include_submission_test_result_negative_further_info" - android:layout_width="@dimen/match_constraint" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_normal" - android:visibility="@{FormatterSubmissionHelper.formatTestResultNegativeStepsVisible(uiState.deviceUiState)}" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@+id/submission_test_result_negative_steps" /> - - <include - android:id="@+id/submission_test_result_positive_steps" - layout="@layout/include_test_result_positive_steps" - android:layout_width="@dimen/match_constraint" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_normal" - android:visibility="@{FormatterSubmissionHelper.formatTestResultPositiveStepsVisible(uiState.deviceUiState)}" - app:layout_constraintEnd_toEndOf="@+id/guideline_end" - app:layout_constraintStart_toStartOf="@+id/guideline_start" - app:layout_constraintTop_toBottomOf="@+id/submission_test_result_subtitle" /> - - <include - android:id="@+id/submission_test_result_invalid_steps" - layout="@layout/include_test_result_invalid_steps" - android:layout_width="@dimen/match_constraint" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_normal" - android:visibility="@{FormatterSubmissionHelper.formatTestResultInvalidStepsVisible(uiState.deviceUiState)}" - app:layout_constraintEnd_toEndOf="@+id/guideline_end" - app:layout_constraintStart_toStartOf="@+id/guideline_start" - app:layout_constraintTop_toBottomOf="@+id/submission_test_result_subtitle" /> - - - <include layout="@layout/merge_guidelines_side" /> - - <include layout="@layout/merge_guidelines_card" /> - - </androidx.constraintlayout.widget.ConstraintLayout> - </ScrollView> -</layout> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/layout/submission_blocking_dialog_view.xml b/Corona-Warn-App/src/main/res/layout/submission_blocking_dialog_view.xml new file mode 100644 index 0000000000000000000000000000000000000000..40cf09352152cdeeae077ace3141b38048ff4d62 --- /dev/null +++ b/Corona-Warn-App/src/main/res/layout/submission_blocking_dialog_view.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="wrap_content" + android:layout_height="wrap_content"> + + <ProgressBar + android:id="@+id/progress_indicator" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="16dp" + android:layout_marginTop="16dp" + android:layout_marginBottom="16dp" + android:progressTint="@color/colorAccentTintIcon" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <TextView + android:id="@+id/progress_message" + style="@style/body1" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="16dp" + android:layout_marginEnd="16dp" + android:text="@string/submission_status_card_title_fetching" + app:layout_constraintBottom_toBottomOf="@+id/progress_indicator" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.0" + app:layout_constraintStart_toEndOf="@+id/progress_indicator" + app:layout_constraintTop_toTopOf="@+id/progress_indicator" /> + +</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/layout/view_bullet_point_text.xml b/Corona-Warn-App/src/main/res/layout/view_bullet_point_text.xml index 1a679cd56d0e36b364d4a0cb7c95176d9094e104..0c676402ab170956a97c336f3ba66eb2df7ded29 100644 --- a/Corona-Warn-App/src/main/res/layout/view_bullet_point_text.xml +++ b/Corona-Warn-App/src/main/res/layout/view_bullet_point_text.xml @@ -12,7 +12,7 @@ <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent" - android:paddingBottom="@dimen/spacing_normal"> + android:paddingBottom="@dimen/spacing_small"> <ImageView android:id="@+id/bullet_point" diff --git a/Corona-Warn-App/src/main/res/navigation/nav_graph.xml b/Corona-Warn-App/src/main/res/navigation/nav_graph.xml index e0b357ede3dde79efbcd906846e0a764b92622ef..5cc60903c46b9c3bb3508af4471ee884b297a582 100644 --- a/Corona-Warn-App/src/main/res/navigation/nav_graph.xml +++ b/Corona-Warn-App/src/main/res/navigation/nav_graph.xml @@ -31,9 +31,6 @@ <action android:id="@+id/action_mainFragment_to_submissionResultFragment" app:destination="@id/submissionResultFragment" /> - <action - android:id="@+id/action_mainFragment_to_submissionDoneFragment" - app:destination="@id/submissionDoneFragment" /> <action android:id="@+id/action_mainFragment_to_mainOverviewFragment" app:destination="@id/mainOverviewFragment" /> @@ -46,6 +43,9 @@ <action android:id="@+id/action_mainFragment_to_test_nav_graph" app:destination="@id/test_nav_graph" /> + <action + android:id="@+id/action_mainFragment_to_submissionResultPositiveOtherWarningNoConsentFragment" + app:destination="@id/submissionResultPositiveOtherWarningNoConsentFragment" /> </fragment> <fragment @@ -222,49 +222,24 @@ android:id="@+id/action_submissionDispatcherFragment_to_submissionConsentFragment" app:destination="@id/submissionConsentFragment" /> </fragment> - <fragment - android:id="@+id/submissionResultPositiveOtherWarningFragment" - android:name="de.rki.coronawarnapp.ui.submission.warnothers.SubmissionResultPositiveOtherWarningFragment" - android:label="fragment_submission_result_positive_other_warning" - tools:layout="@layout/fragment_submission_positive_other_warning"> - <action - android:id="@+id/action_submissionResultPositiveOtherWarningFragment_to_submissionResultFragment" - app:destination="@id/submissionResultFragment" - app:popUpTo="@id/submissionResultFragment" - app:popUpToInclusive="true" /> - <action - android:id="@+id/action_submissionResultPositiveOtherWarningFragment_to_submissionDoneFragment" - app:destination="@id/submissionDoneFragment" - app:popUpTo="@id/submissionDoneFragment" - app:popUpToInclusive="true" /> - <action - android:id="@+id/action_submissionResultPositiveOtherWarningFragment_to_submissionSymptomCalendarFragment" - app:destination="@id/submissionSymptomCalendarFragment" /> - <action - android:id="@+id/action_submissionResultPositiveOtherWarningFragment_to_submissionSymptomIntroductionFragment" - app:destination="@id/submissionSymptomIntroductionFragment" /> - <argument - android:name="symptoms" - app:argType="de.rki.coronawarnapp.submission.Symptoms" /> - </fragment> <fragment android:id="@+id/submissionResultPositiveOtherWarningNoConsentFragment" android:name="de.rki.coronawarnapp.ui.submission.warnothers.SubmissionResultPositiveOtherWarningNoConsentFragment" android:label="fragment_submission_result_positive_other_no_consent_warning" tools:layout="@layout/fragment_submission_no_consent_positive_other_warning"> - <argument - android:name="symptoms" - app:argType="de.rki.coronawarnapp.submission.Symptoms" /> <action android:id="@+id/action_submissionResultPositiveOtherWarningNoConsentFragment_to_mainFragment" app:destination="@id/mainFragment" app:popUpTo="@id/mainFragment" app:popUpToInclusive="true" /> <action - android:id="@+id/action_submissionResultPositiveOtherWarningNoConsentFragment_to_submissionDoneFragment" - app:destination="@id/submissionDoneFragment" + android:id="@+id/action_submissionResultPositiveOtherWarningNoConsentFragment_to_informationPrivacyFragment" + app:destination="@id/informationPrivacyFragment" /> + <action + android:id="@+id/action_submissionResultPositiveOtherWarningNoConsentFragment_to_submissionResultReadyFragment" + app:destination="@id/submissionResultReadyFragment" app:popUpTo="@id/mainFragment" - app:popUpToInclusive="false" /> + app:popUpToInclusive="true" /> </fragment> <fragment android:id="@+id/submissionResultFragment" @@ -285,7 +260,10 @@ app:destination="@id/submissionSymptomIntroductionFragment" /> <action android:id="@+id/action_submissionResultFragment_to_submissionResultPositiveOtherWarningFragment" - app:destination="@id/submissionResultPositiveOtherWarningFragment" /> + app:destination="@id/submissionResultPositiveOtherWarningNoConsentFragment" /> + <action + android:id="@+id/action_submissionResultFragment_to_submissionYourConsentFragment" + app:destination="@id/submissionYourConsentFragment" /> </fragment> <fragment @@ -312,7 +290,7 @@ android:id="@+id/action_submissionTanFragment_to_submissionTestResultNoConsentFragment" app:destination="@id/submissionTestResultNoConsentFragment" app:popUpTo="@id/mainFragment" - app:popUpToInclusive="false"/> + app:popUpToInclusive="false" /> </fragment> <fragment @@ -355,16 +333,27 @@ android:defaultValue="true" app:argType="boolean" /> </action> + <action + android:id="@+id/action_submissionQRCodeScanFragment_to_submissionTestResultAvailableFragment" + app:destination="@id/submissionTestResultAvailableFragment" + app:popUpTo="@id/mainFragment" + app:popUpToInclusive="true" /> </fragment> <fragment - android:id="@+id/submissionDoneFragment" - android:name="de.rki.coronawarnapp.ui.submission.fragment.SubmissionDoneFragment" - android:label="SubmissionDoneFragment"> + android:id="@+id/submissionResultReadyFragment" + android:name="de.rki.coronawarnapp.ui.submission.resultready.SubmissionResultReadyFragment" + android:label="SubmissionResultReadyFragment" + tools:layout="@layout/fragment_submission_result_ready"> <action - android:id="@+id/action_submissionDoneFragment_to_mainFragment" + android:id="@+id/action_submissionResultReadyFragment_to_mainFragment" app:destination="@id/mainFragment" app:popUpTo="@id/mainFragment" app:popUpToInclusive="true" /> + <action + android:id="@+id/action_submissionResultReadyFragment_to_submissionSymptomIntroductionFragment" + app:destination="@id/submissionSymptomIntroductionFragment" + app:popUpTo="@id/submissionSymptomIntroductionFragment" + app:popUpToInclusive="true" /> </fragment> <fragment android:id="@+id/submissionContactFragment" @@ -378,16 +367,14 @@ android:id="@+id/submissionSymptomIntroductionFragment" android:name="de.rki.coronawarnapp.ui.submission.symptoms.introduction.SubmissionSymptomIntroductionFragment" android:label="SubmissionSymptomIntroductionFragment"> - <action android:id="@+id/action_submissionSymptomIntroductionFragment_to_submissionSymptomCalendarFragment" app:destination="@id/submissionSymptomCalendarFragment" /> <action - android:id="@+id/action_submissionSymptomIntroductionFragment_to_submissionResultFragment" - app:destination="@id/submissionResultFragment" /> - <action - android:id="@+id/action_submissionSymptomIntroductionFragment_to_submissionResultPositiveOtherWarningFragment" - app:destination="@id/submissionResultPositiveOtherWarningFragment" /> + android:id="@+id/action_submissionSymptomIntroductionFragment_to_mainFragment" + app:destination="@id/mainFragment" + app:popUpTo="@id/mainFragment" + app:popUpToInclusive="true" /> </fragment> <fragment android:id="@+id/submissionSymptomCalendarFragment" @@ -398,10 +385,12 @@ app:destination="@id/submissionSymptomIntroductionFragment" /> <action android:id="@+id/action_submissionSymptomCalendarFragment_to_submissionResultPositiveOtherWarningFragment" - app:destination="@id/submissionResultPositiveOtherWarningFragment" /> - <argument - android:name="symptomIndication" - app:argType="de.rki.coronawarnapp.submission.Symptoms$Indication" /> + app:destination="@id/submissionResultPositiveOtherWarningNoConsentFragment" /> + <action + android:id="@+id/action_submissionSymptomCalendarFragment_to_mainFragment" + app:destination="@id/mainFragment" + app:popUpTo="@id/mainFragment" + app:popUpToInclusive="true" /> </fragment> <fragment android:id="@+id/submissionConsentFragment" @@ -425,8 +414,9 @@ android:label="SubmissionTestResultConsentFragment"> <action android:id="@+id/action_submissionTestResultConsentGivenFragment_to_homeFragment" + app:destination="@id/mainFragment" app:popUpTo="@id/mainFragment" - app:popUpToInclusive="false" /> + app:popUpToInclusive="true" /> <action android:id="@+id/action_submissionTestResultConsentGivenFragment_to_submissionSymptomIntroductionFragment" app:destination="@id/submissionSymptomIntroductionFragment" /> @@ -437,7 +427,44 @@ android:label="SubmissionTestResultNoConsentFragment"> <action android:id="@+id/action_submissionTestResultNoConsentFragment_to_homeFragment" + app:destination="@id/mainFragment" app:popUpTo="@id/mainFragment" - app:popUpToInclusive="false"/> + app:popUpToInclusive="true" /> + <action + android:id="@+id/action_submissionTestResultNoConsentFragment_to_submissionResultPositiveOtherWarningNoConsentFragment" + app:destination="@id/submissionResultPositiveOtherWarningNoConsentFragment" /> + </fragment> + <fragment + android:id="@+id/submissionYourConsentFragment" + android:name="de.rki.coronawarnapp.ui.submission.yourconsent.SubmissionYourConsentFragment" + android:label="SubmissionYourConsentFragment"> + <action + android:id="@+id/action_submissionYourConsentFragment_to_informationPrivacyFragment" + app:destination="@id/informationPrivacyFragment" /> + </fragment> + <fragment + android:id="@+id/submissionTestResultAvailableFragment" + android:name="de.rki.coronawarnapp.ui.submission.resultavailable.SubmissionTestResultAvailableFragment" + android:label="SubmissionTestResultAvailableFragment" + tools:layout="@layout/fragment_submission_test_result_available"> + <action + android:id="@+id/action_submissionTestResultAvailableFragment_to_mainFragment" + app:destination="@id/mainFragment" + app:popUpTo="@id/mainFragment" + app:popUpToInclusive="true" /> + <action + android:id="@+id/action_submissionTestResultAvailableFragment_to_submissionYourConsentFragment" + app:destination="@id/submissionYourConsentFragment" /> + <action + android:id="@+id/action_submissionTestResultAvailableFragment_to_submissionTestResultConsentGivenFragment" + app:destination="@id/submissionTestResultConsentGivenFragment" + app:popUpTo="@id/mainFragment" + app:popUpToInclusive="true" /> + <action + android:id="@+id/action_submissionTestResultAvailableFragment_to_submissionTestResultNoConsentFragment" + app:destination="@id/submissionTestResultNoConsentFragment" + app:popUpTo="@id/mainFragment" + app:popUpToInclusive="true" /> + </fragment> </navigation> diff --git a/Corona-Warn-App/src/main/res/values-bg/strings.xml b/Corona-Warn-App/src/main/res/values-bg/strings.xml index 972e4ef924f96fbb94835205aaab9b4905dc7c55..db6aace94f4df52b7ccd9b283800e5b6ba087205 100644 --- a/Corona-Warn-App/src/main/res/values-bg/strings.xml +++ b/Corona-Warn-App/src/main/res/values-bg/strings.xml @@ -162,7 +162,7 @@ <string name="risk_card_low_risk_no_encounters_body">"До момента нÑма излагане на риÑк"</string> <!-- XTXT: risk card - Low risk state - Days with low risk encounters --> <plurals name="risk_card_low_risk_encounter_days_body"> - <item quantity="one">"Брой дни Ñ Ð¸Ð·Ð»Ð°Ð³Ð°Ð½Ð¸Ñ Ñ Ð½Ð¸Ñък риÑк - %1$d"</item> + <item quantity="one">"Брой дни Ñ Ð¸Ð·Ð»Ð°Ð³Ð°Ð½Ð¸Ñ Ð½Ð° ниÑък риÑк: 1"</item> <item quantity="other">"Брой дни Ñ Ð¸Ð·Ð»Ð°Ð³Ð°Ð½Ð¸Ñ Ñ Ð½Ð¸Ñък риÑк - %1$d"</item> <item quantity="zero">"Брой дни Ñ Ð¸Ð·Ð»Ð°Ð³Ð°Ð½Ð¸Ñ Ñ Ð½Ð¸Ñък риÑк - %1$d"</item> <item quantity="two">"Брой дни Ñ Ð¸Ð·Ð»Ð°Ð³Ð°Ð½Ð¸Ñ Ñ Ð½Ð¸Ñък риÑк - %1$d"</item> @@ -174,7 +174,7 @@ <string name="risk_card_high_risk_no_encounters_body">"До момента нÑма излагане на риÑк"</string> <!-- XTXT: risk card - High risk state - Days with high risk encounters --> <plurals name="risk_card_high_risk_encounter_days_body"> - <item quantity="one">"Брой дни Ñ Ð¸Ð·Ð»Ð°Ð³Ð°Ð½Ð¸Ñ Ñ Ð¿Ð¾Ð²Ð¸ÑˆÐµÐ½ риÑк - %1$d"</item> + <item quantity="one">"Брой дни Ñ Ð¸Ð·Ð»Ð°Ð³Ð°Ð½Ð¸Ñ Ð½Ð° повишен риÑк: 1"</item> <item quantity="other">"Брой дни Ñ Ð¸Ð·Ð»Ð°Ð³Ð°Ð½Ð¸Ñ Ñ Ð¿Ð¾Ð²Ð¸ÑˆÐµÐ½ риÑк - %1$d"</item> <item quantity="zero">"Брой дни Ñ Ð¸Ð·Ð»Ð°Ð³Ð°Ð½Ð¸Ñ Ñ Ð¿Ð¾Ð²Ð¸ÑˆÐµÐ½ риÑк - %1$d"</item> <item quantity="two">"Брой дни Ñ Ð¸Ð·Ð»Ð°Ð³Ð°Ð½Ð¸Ñ Ñ Ð¿Ð¾Ð²Ð¸ÑˆÐµÐ½ риÑк - %1$d"</item> @@ -242,7 +242,7 @@ <!-- XHED: App overview subtitle for risk explanation --> <string name="main_overview_subtitle_risk">"РиÑк от заразÑване"</string> <!-- YTXT: App overview body text about risk levels --> - <string name="main_overview_body_risk">"Ðко през поÑледните 14 дни Ñте имали контакт Ñ Ð»Ð¸Ñ†Ðµ, което е било диагноÑтицирано Ñ COVID-19, приложението изчиÑлÑва какъв е ВашиÑÑ‚ риÑк от заразÑване, като измерва продължителноÑтта и близоÑтта на излагането."</string> + <string name="main_overview_body_risk">"Ðко през поÑледните 14 дни Ñте имали контакт Ñ Ð»Ð¸Ñ†Ðµ, диагноÑтицирано Ñ ÐºÐ¾Ñ€Ð¾Ð½Ð°Ð²Ð¸Ñ€ÑƒÑ, приложението изчиÑлÑва какъв е ВашиÑÑ‚ риÑк от заразÑване, като измерва продължителноÑтта и близоÑтта на излагането."</string> <!-- XHED: App overview subtitle for risk level list --> <string name="main_overview_subtitle_risk_levels">"Възможни Ñа Ñледните нива на риÑк:"</string> <!-- XTXT: App overview increased risk level --> @@ -254,7 +254,7 @@ <!-- XHED: App overview subtitle for test procedure explanation --> <string name="main_overview_headline_test">"УведомÑване на други потребители"</string> <!-- YTXT: App overview body text about rest procedure --> - <string name="main_overview_body_test">"Друга оÑновна Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ðµ региÑтрирането на теÑтове и извличането на резултати. Ðко имате поÑтавена диагноза COVID-19, може да уведомите оÑтаналите потребители и да прекъÑнете веригата на заразÑване."</string> + <string name="main_overview_body_test">"Друга оÑновна Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ðµ региÑтрирането на теÑтове и извличането на резултати. Ðко имате поÑтавена диагноза \"коронавируÑ\", може да уведомите оÑтаналите потребители и да прекъÑнете веригата на заразÑване."</string> <!-- XHED: App overview headline for glossary --> <string name="main_overview_headline_glossary">"Дефиниции на термини:"</string> <!-- XHED: App overview subtitle for glossary key storage --> @@ -276,7 +276,7 @@ <!-- XHED: App overview subtitle for glossary keys --> <string name="main_overview_subtitle_glossary_keys">"Случаен идентификатор"</string> <!-- YTXT: App overview body for glossary keys --> - <string name="main_overview_body_glossary_keys">"Случайните идентификатори Ñа произволно генерирани комбинации от цифри и букви, които уÑтройÑтвата Ñи разменÑÑ‚, когато Ñа в близоÑÑ‚ едно до друго. Идентифицирането на конкретни лица поÑредÑтвом проÑледÑването им е невъзможно. ОÑвен това те Ñе изтриват автоматично Ñлед 14 дни. Лицата, диагноÑтицирани Ñ COVID-19, могат да ÑподелÑÑ‚ Ñ Ð¾Ñтаналите потребители на приложението Ñвоите Ñлучайни идентификатори, генерирани през поÑледните 14 дни."</string> + <string name="main_overview_body_glossary_keys">"Случайните идентификатори Ñа произволно генерирани комбинации от цифри и букви, които Ñмартфоните Ñи разменÑÑ‚, когато Ñа в близоÑÑ‚ един до друг. Идентифицирането на конкретни лица поÑредÑтвом проÑледÑването им е невъзможно. ОÑвен това те Ñе изтриват автоматично Ñлед 14 дни. Лицата, диагноÑтицирани Ñ ÐºÐ¾Ñ€Ð¾Ð½Ð°Ð²Ð¸Ñ€ÑƒÑ, могат да ÑподелÑÑ‚ Ñ Ð¾Ñтаналите потребители на приложението Ñвоите Ñлучайни идентификатори, генерирани през поÑледните 14 дни."</string> <!-- XACT: main (overview) - illustraction description, explanation image --> <string name="main_overview_illustration_description">"Смартфон, показващ различни блокове Ñъдържание Ñ Ð½Ð¾Ð¼ÐµÑ€Ð° от 1 до 3."</string> <!-- XACT: App main page title --> @@ -293,11 +293,11 @@ <!-- XHED: risk details - subtitle for additional info in case of encounter with low risk --> <string name="risk_details_additional_info_subtitle">"Защо риÑкът Ви от заразÑване е ниÑък"</string> <!-- XHED: risk details - text for additional info in case of encounter with low risk --> - <string name="risk_details_additional_info_text">"Били Ñте в контакт Ñ Ð»Ð¸Ñ†Ðµ, което на по-къÑен етап е диагноÑтицирано Ñ COVID-19. Ðо отчитайки региÑтрираните от Ð²Ð°Ñ Ð´Ð°Ð½Ð½Ð¸ за излагането, риÑкът ви от заразÑване Ñе Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»Ñ ÐºÐ°Ñ‚Ð¾ ниÑък. Той е такъв, когато контактът е бил за кратко или е оÑъщеÑтвен от разÑтоÑние.\nÐе Ñ‚Ñ€Ñбва да Ñе притеÑнÑвате и не е нужно да предприемате определени дейÑтвиÑ. Препоръчваме Ви да Ñпазвате широкоразпроÑтранените правила за Ñоциално диÑтанциране и поддържане на хигиена."</string> + <string name="risk_details_additional_info_text">"Били Ñте в контакт Ñ Ð»Ð¸Ñ†Ðµ, което на по-къÑен етап е диагноÑтицирано Ñ ÐºÐ¾Ñ€Ð¾Ð½Ð°Ð²Ð¸Ñ€ÑƒÑ. Отчитайки региÑтрираните от Ð’Ð°Ñ Ð´Ð°Ð½Ð½Ð¸ за излагането, Вашето ниво на риÑк от заразÑване е ниÑко, Ñ‚.е. контактът е бил кратък или е оÑъщеÑтвен от разÑтоÑние.\nÐе Ñ‚Ñ€Ñбва да Ñе притеÑнÑвате и не е нужно да предприемате определени дейÑтвиÑ. Препоръчваме Ви да Ñледвате общоприетите правила за Ñпазване на диÑÑ‚Ð°Ð½Ñ†Ð¸Ñ Ð¸ хигиена."</string> <!-- XHED: risk details - headline, how a user should act --> <string name="risk_details_headline_behavior">"ÐаÑоки"</string> <!-- XHED: risk details - multiline headline, bold, how to act correct --> - <string name="risk_details_subtitle_behavior">"Ето какво Ñ‚Ñ€Ñбва да направите"</string> + <string name="risk_details_subtitle_behavior">"Ето какво Ñ‚Ñ€Ñбва да направите:"</string> <!-- XMSG: risk details - go/stay home, something like a bullet point --> <string name="risk_details_behavior_body_stay_home">"По възможноÑÑ‚ Ñе приберете и Ñи оÑтанете вкъщи."</string> <!-- XMSG: risk details - get in touch with the corresponding people, something like a bullet point --> @@ -327,23 +327,23 @@ <!-- XHED: risk details - infection period logged information body, below behaviors --> <string name="risk_details_information_body_period_logged_assessment">"РегиÑтрирането на Ð¸Ð·Ð»Ð°Ð³Ð°Ð½Ð¸Ñ Ð½Ð° риÑк покрива поÑледните 14 дни. За този период от време функциÑта е била активна на Ð’Ð°ÑˆÐ¸Ñ Ñмартфон в продължение на %1$s дни. Приложението изтрива автоматично по-Ñтарите региÑтри, тъй като те вече не могат да Ñлужат за предотвратÑване на заразÑването."</string> <!-- XHED: risk details - how your risk level was calculated, below behaviors --> - <string name="risk_details_subtitle_infection_risk_past">"Ето как е изчиÑлено Вашето ниво на риÑк"</string> + <string name="risk_details_subtitle_infection_risk_past">"Ето как е изчиÑлено Вашето ниво на риÑк."</string> <!-- XHED: risk details - how your risk level will be calculated, below behaviors --> - <string name="risk_details_subtitle_infection_risk">"Ето как Ñе изчиÑлÑва Вашето ниво на риÑк"</string> + <string name="risk_details_subtitle_infection_risk">"Ето как Ñе изчиÑлÑва Вашето ниво на риÑк."</string> <!-- XMSG: risk details - risk calculation wasn't possible for 24h, below behaviors --> <string name="risk_details_information_body_outdated_risk">"РегиÑтърът на излаганиÑта на риÑк не е обновÑван повече от 24 чаÑа."</string> <!-- YTXT: risk details - low risk explanation text --> - <string name="risk_details_information_body_low_risk">"Вашето ниво на риÑк от заразÑване е ниÑко, защото нÑмате региÑтрирани контакти Ñ Ð»Ð¸Ñ†Ð°, които впоÑледÑтвие Ñа били диагноÑтицирани Ñ COVID-19, или ако Ñте имали такива, те Ñа били краткотрайни и от по-голÑмо разÑтоÑние."</string> + <string name="risk_details_information_body_low_risk">"Вашето ниво на риÑк от заразÑване е ниÑко, защото нÑмате региÑтрирани контакти Ñ Ð»Ð¸Ñ†Ð°, които впоÑледÑтвие Ñа били диагноÑтицирани Ñ ÐºÐ¾Ñ€Ð¾Ð½Ð°Ð²Ð¸Ñ€ÑƒÑ, или ако Ñте имали такива, те Ñа били краткотрайни и от по-голÑмо разÑтоÑние."</string> <!-- YTXT: risk details - low risk explanation text with encounter with low risk --> - <string name="risk_details_information_body_low_risk_with_encounter">"РиÑкът от заразÑване Ñе изчиÑлÑва локално на Ñмартфона Ви въз оÑнова на региÑтрираните данни за излагане. ИзчиÑлението включва Ñъщо така разÑтоÑнието от и продължителноÑтта на вÑички контакти Ñ Ð»Ð¸Ñ†Ð°, диагноÑтицирани Ñ COVID-19., както и възможноÑтта им да заразÑÑ‚ околните. Ðикой оÑвен Ð’Ð°Ñ Ð½Ðµ може да види или да получи данни за Вашето ниво на риÑк."</string> + <string name="risk_details_information_body_low_risk_with_encounter">"РиÑкът от заразÑване Ñе изчиÑлÑва локално на Ñмартфона Ви въз оÑнова на региÑтрираните данни за излагане. ИзчиÑлението включва Ñъщо така разÑтоÑнието от и продължителноÑтта на вÑички контакти Ñ Ð»Ð¸Ñ†Ð°, диагноÑтицирани Ñ ÐºÐ¾Ñ€Ð¾Ð½Ð°Ð²Ð¸Ñ€ÑƒÑ, както и възможноÑтта им да заразÑÑ‚ околните. Ðикой оÑвен Ð’Ð°Ñ Ð½Ðµ може да види или да получи данни за Вашето ниво на риÑк."</string> <!-- YTXT: risk details - increased risk explanation text with variable for day(s) since last contact --> <plurals name="risk_details_information_body_increased_risk"> - <item quantity="one">"Изложени Ñте на повишен риÑк от заразÑване, защото преди %1$s дни Ñте имали продължителен и близък контакт Ñ Ð¿Ð¾Ð½Ðµ едно лице, диагноÑтицирано Ñ COVID-19."</item> - <item quantity="other">"Изложени Ñте на повишен риÑк от заразÑване, защото преди %1$s дни Ñте имали продължителен и близък контакт Ñ Ð¿Ð¾Ð½Ðµ едно лице, диагноÑтицирано Ñ COVID-19."</item> - <item quantity="zero">"Изложени Ñте на повишен риÑк от заразÑване, защото преди %1$s дни Ñте имали продължителен и близък контакт Ñ Ð¿Ð¾Ð½Ðµ едно лице, диагноÑтицирано Ñ COVID-19."</item> - <item quantity="two">"Изложени Ñте на повишен риÑк от заразÑване, защото преди %1$s дни Ñте имали продължителен и близък контакт Ñ Ð¿Ð¾Ð½Ðµ едно лице, диагноÑтицирано Ñ COVID-19."</item> - <item quantity="few">"Изложени Ñте на повишен риÑк от заразÑване, защото преди %1$s дни Ñте имали продължителен и близък контакт Ñ Ð¿Ð¾Ð½Ðµ едно лице, диагноÑтицирано Ñ COVID-19."</item> - <item quantity="many">"Изложени Ñте на повишен риÑк от заразÑване, защото преди %1$s дни Ñте имали продължителен и близък контакт Ñ Ð¿Ð¾Ð½Ðµ едно лице, диагноÑтицирано Ñ COVID-19."</item> + <item quantity="one">"Ðивото на риÑка Ви от заразÑване е повишено, защото преди %1$s дни Ñте имали продължителен и близък контакт Ñ Ð¿Ð¾Ð½Ðµ едно лице, диагноÑтицирано Ñ ÐºÐ¾Ñ€Ð¾Ð½Ð°Ð²Ð¸Ñ€ÑƒÑ."</item> + <item quantity="other">"Ðивото на риÑка Ви от заразÑване е повишено, защото преди %1$s дни Ñте имали продължителен и близък контакт Ñ Ð¿Ð¾Ð½Ðµ едно лице, диагноÑтицирано Ñ ÐºÐ¾Ñ€Ð¾Ð½Ð°Ð²Ð¸Ñ€ÑƒÑ."</item> + <item quantity="zero">"Ðивото на риÑка Ви от заразÑване е повишено, защото преди %1$s дни Ñте имали продължителен и близък контакт Ñ Ð¿Ð¾Ð½Ðµ едно лице, диагноÑтицирано Ñ ÐºÐ¾Ñ€Ð¾Ð½Ð°Ð²Ð¸Ñ€ÑƒÑ."</item> + <item quantity="two">"Ðивото на риÑка Ви от заразÑване е повишено, защото преди %1$s дни Ñте имали продължителен и близък контакт Ñ Ð¿Ð¾Ð½Ðµ едно лице, диагноÑтицирано Ñ ÐºÐ¾Ñ€Ð¾Ð½Ð°Ð²Ð¸Ñ€ÑƒÑ."</item> + <item quantity="few">"Ðивото на риÑка Ви от заразÑване е повишено, защото преди %1$s дни Ñте имали продължителен и близък контакт Ñ Ð¿Ð¾Ð½Ðµ едно лице, диагноÑтицирано Ñ ÐºÐ¾Ñ€Ð¾Ð½Ð°Ð²Ð¸Ñ€ÑƒÑ."</item> + <item quantity="many">"Ðивото на риÑка Ви от заразÑване е повишено, защото преди %1$s дни Ñте имали продължителен и близък контакт Ñ Ð¿Ð¾Ð½Ðµ едно лице, диагноÑтицирано Ñ ÐºÐ¾Ñ€Ð¾Ð½Ð°Ð²Ð¸Ñ€ÑƒÑ."</item> </plurals> <!-- YTXT: risk details - risk calculation explanation --> <string name="risk_details_information_body_notice">"РиÑкът от заразÑване Ñе изчиÑлÑва въз оÑнова на данните за излагане (продължителноÑÑ‚ и близоÑÑ‚ на контакта), региÑтрирани във Ð²Ð°ÑˆÐ¸Ñ Ñмартфон. Ðикой оÑвен Ð’Ð°Ñ Ð½Ðµ може да види или да получи данни за Вашето ниво на риÑк."</string> @@ -404,7 +404,7 @@ <!-- XHED: onboarding(together) - two/three line headline under an illustration --> <string name="onboarding_subtitle">"Повече защита за Ð’Ð°Ñ Ð¸ за вÑички наÑ. С помощта на приложението Corona-Warn-App можем да прекъÑнем веригите на заразÑване много по-бързо."</string> <!-- YTXT: onboarding(together) - inform about the app --> - <string name="onboarding_body">"Превърнете Ñмартфона Ñи в предупредителна ÑиÑтема за коронавируÑ. Прегледайте ÑÐ²Ð¾Ñ ÑÑ‚Ð°Ñ‚ÑƒÑ Ð½Ð° риÑк и разберете дали през поÑледните 14 дни Ñте имали близък контакт Ñ Ð»Ð¸Ñ†Ðµ, диагноÑтицирано Ñ COVID-19."</string> + <string name="onboarding_body">"Превърнете Ñмартфона Ñи в предупредителна ÑиÑтема за коронавируÑ. Прегледайте ÑÐ²Ð¾Ñ ÑÑ‚Ð°Ñ‚ÑƒÑ Ð½Ð° риÑк и разберете дали през поÑледните 14 дни Ñте имали близък контакт Ñ Ð»Ð¸Ñ†Ðµ, диагноÑтицирано Ñ ÐºÐ¾Ñ€Ð¾Ð½Ð°Ð²Ð¸Ñ€ÑƒÑ."</string> <!-- YTXT: onboarding(together) - explain application --> <string name="onboarding_body_emphasized">"Приложението региÑтрира контакти на лица поÑредÑтвом обмÑна на криптирани Ñлучайни ИД кодове между уÑтройÑтвата им, без да оÑъщеÑтвÑва доÑтъп до каквито и да било лични данни."</string> <!-- XACT: onboarding(together) - illustraction description, header image --> @@ -421,9 +421,9 @@ <!-- XHED: onboarding(tracing) - how to enable tracing --> <string name="onboarding_tracing_headline">"Как да активирате региÑтрирането на Ð¸Ð·Ð»Ð°Ð³Ð°Ð½Ð¸Ñ Ð½Ð° риÑк"</string> <!-- XHED: onboarding(tracing) - two/three line headline under an illustration --> - <string name="onboarding_tracing_subtitle">"За да уÑтановите дали Ñте заÑтрашени от заразÑване, Ñ‚Ñ€Ñбва да активирате функциÑта за региÑтриране на Ð¸Ð·Ð»Ð°Ð³Ð°Ð½Ð¸Ñ Ð½Ð° риÑк."</string> + <string name="onboarding_tracing_subtitle">"За да уÑтановите дали за Ð’Ð°Ñ ÑъщеÑтвува риÑк от заразÑване, Ñ‚Ñ€Ñбва да активирате функциÑта за региÑтриране на Ð¸Ð·Ð»Ð°Ð³Ð°Ð½Ð¸Ñ Ð½Ð° риÑк."</string> <!-- YTXT: onboarding(tracing) - explain tracing --> - <string name="onboarding_tracing_body">"РегиÑтрирането на Ð¸Ð·Ð»Ð°Ð³Ð°Ð½Ð¸Ñ Ð½Ð° риÑк Ñе извършва Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰Ñ‚Ð° на Bluetooth връзка, при коÑто ВашиÑÑ‚ Ñмартфон получава криптираните Ñлучайни идентификационни кодове на други потребители и изпраща до техните уÑтройÑтва Вашите Ñлучайни ИД. ФункциÑта може да бъде дезактивирана по вÑÑко време. "</string> + <string name="onboarding_tracing_body">"РегиÑтрирането на Ð¸Ð·Ð»Ð°Ð³Ð°Ð½Ð¸Ñ Ð½Ð° риÑк Ñе извършва Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰Ñ‚Ð° на Bluetooth връзка, при коÑто ВашиÑÑ‚ Ñмартфон Ñ Android получава криптираните Ñлучайни идентификационни кодове на други потребители и изпраща до техните уÑтройÑтва Вашите Ñлучайни ИД. ФункциÑта може да бъде дезактивирана по вÑÑко време. "</string> <!-- YTXT: onboarding(tracing) - explain tracing --> <string name="onboarding_tracing_body_emphasized">"Криптираните Ñлучайни идентификатори предават Ñамо Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° дата, продължителноÑÑ‚ и близоÑÑ‚ на контакта (изчиÑлена от Ñилата на Ñигнала). СамоличноÑтта Ви не може да бъде уÑтановена по Ñлучайните ИД."</string> <!-- YTXT: onboarding(tracing) - easy language explain tracing link--> @@ -471,9 +471,9 @@ <!-- XBUT: onboarding(tracing) - button enable tracing --> <string name="onboarding_tracing_location_button">"Към наÑтройките на уÑтройÑтвото"</string> <!-- XACT: Onboarding (test) page title --> - <string name="onboarding_test_accessibility_title">"Въведение - Ñтраница 5 от 6: Ðко имате поÑтавена диагноза COVID-19"</string> + <string name="onboarding_test_accessibility_title">"Въведение – Ñтраница 5 от 6: Ðко имате поÑтавена диагноза \"коронавируÑ\""</string> <!-- XHED: onboarding(test) - about positive tests --> - <string name="onboarding_test_headline">"Ðко имате поÑтавена диагноза COVID-19,..."</string> + <string name="onboarding_test_headline">"Ðко имате поÑтавена диагноза \"коронавируÑ\",..."</string> <!-- XHED: onboarding(test) - two/three line headline under an illustration --> <string name="onboarding_test_subtitle">"... Ð¼Ð¾Ð»Ñ Ñъобщете за това в приложението Corona-Warn-App. СподелÑнето на резултатите от Вашите теÑтове е доброволно и безопаÑно. Ðаправете го в името на общото здраве."</string> <!-- YTXT: onboarding(test) - explain test --> @@ -525,7 +525,7 @@ <!-- XTXT: settings(tracing) - shows status under header in home, inactive location --> <string name="settings_tracing_body_inactive_location">"УÑлугите за ÑподелÑне на меÑтоположението Ñа дезактивирани"</string> <!-- YTXT: settings(tracing) - explains tracings --> - <string name="settings_tracing_body_text">"За да може приложението да определи дали има вероÑтноÑÑ‚ да Ñте Ñе заразили в ÑледÑтвие на контакт ÑÑŠÑ Ð·Ð°Ñ€Ð°Ð·ÐµÐ½ потребител, Ñ‚Ñ€Ñбва да активирате функциÑта за региÑтриране на излаганиÑта на риÑк. Ð¢Ñ Ñ€Ð°Ð±Ð¾Ñ‚Ð¸ в различни държави, което означава, че Ñе вземат предвид и контактите Ви Ñ Ð¿Ð¾Ñ‚Ñ€ÐµÐ±Ð¸Ñ‚ÐµÐ»Ð¸ на други официални Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð·Ð° борба Ñ ÐºÐ¾Ñ€Ð¾Ð½Ð°Ð²Ð¸Ñ€ÑƒÑа.\n\nФункциÑта за региÑтриране на излаганиÑта получава чрез Bluetooth и запиÑва на уÑтройÑтвото ви криптираните Ñлучайни идентификатори на оÑтаналите потребители в обхвата и изпраща към техните Ñмартфони Вашите Ñлучайни идентификатори Приложението вÑеки ден Ð¸Ð·Ñ‚ÐµÐ³Ð»Ñ ÑпиÑък ÑÑŠÑ Ñлучайните ИД и евентуални данни за развитието на Ñимптомите на вÑички потребители Ñ Ð¿Ð¾Ð»Ð¾Ð¶Ð¸Ñ‚ÐµÐ»ÐµÐ½ теÑÑ‚ за коронавируÑ, които доброволно Ñа Ñподелили тази Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ñ‡Ñ€ÐµÐ· приложението Ñи. ПоÑле ÑпиÑъкът Ñе ÑравнÑва ÑÑŠÑ Ñлучайните ИД, запиÑани на Ð’Ð°ÑˆÐ¸Ñ Ñмартфон и така Ñе изчиÑлÑва вероÑтноÑтта да Ñте Ñе заразили и, ако е необходимо, получавате предупреждение. Можете да активирате и дезактивирате региÑтрирането на излаганиÑта по вÑÑко време.\n\nПриложението никога не Ñъбира лични данни от типа на име, Ð°Ð´Ñ€ÐµÑ Ð¸ меÑтоположение и не ÑÐ¿Ð¾Ð´ÐµÐ»Ñ Ð¿Ð¾Ð´Ð¾Ð±Ð½Ð° Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ñ Ð´Ñ€ÑƒÐ³Ð¸ потребители. СамоличноÑтта Ви не може да бъде определена по Вашите Ñлучайни ИД."</string> + <string name="settings_tracing_body_text">"За да може приложението да определи дали има вероÑтноÑÑ‚ да Ñте Ñе заразили вÑледÑтвие на контакт ÑÑŠÑ Ð·Ð°Ñ€Ð°Ð·ÐµÐ½ потребител, Ñ‚Ñ€Ñбва да активирате функциÑта за региÑтриране на излаганиÑта на риÑк. Ð¢Ñ Ñ€Ð°Ð±Ð¾Ñ‚Ð¸ в различни държави, което означава, че Ñе вземат предвид и контактите Ви Ñ Ð¿Ð¾Ñ‚Ñ€ÐµÐ±Ð¸Ñ‚ÐµÐ»Ð¸ на други официални Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð·Ð° борба Ñ ÐºÐ¾Ñ€Ð¾Ð½Ð°Ð²Ð¸Ñ€ÑƒÑа.\n\nФункциÑта за региÑтриране на излаганиÑта получава чрез Bluetooth и запиÑва на Android уÑтройÑтвото Ви криптираните Ñлучайни идентификатори на оÑтаналите потребители в обхвата и изпраща към техните Ñмартфони Вашите Ñлучайни идентификатори. Приложението вÑеки ден Ð¸Ð·Ñ‚ÐµÐ³Ð»Ñ ÑпиÑък ÑÑŠÑ Ñлучайните ИД и евентуални данни за развитието на Ñимптомите на вÑички потребители Ñ Ð¿Ð¾Ð»Ð¾Ð¶Ð¸Ñ‚ÐµÐ»ÐµÐ½ теÑÑ‚ за коронавируÑ, които доброволно Ñа Ñподелили тази Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ (и по-конкретно Ñвоите Ñлучайните ИД) чрез приложението Ñи. ПоÑле ÑпиÑъкът Ñе ÑравнÑва ÑÑŠÑ Ñлучайните ИД на други потребители, Ñ ÐºÐ¾Ð¸Ñ‚Ð¾ Ñте Ñе Ñрещали, запиÑани на Ð’Ð°ÑˆÐ¸Ñ Android Ñмартфон и така Ñе изчиÑлÑва вероÑтноÑтта да Ñте Ñе заразили. Ðко е необходимо, получавате предупреждение. Можете да активирате и дезактивирате региÑтрирането на излаганиÑта по вÑÑко време.\n\nПриложението никога не Ñъбира лични данни от типа на име, Ð°Ð´Ñ€ÐµÑ Ð¸ меÑтоположение и не ÑÐ¿Ð¾Ð´ÐµÐ»Ñ Ð¿Ð¾Ð´Ð¾Ð±Ð½Ð° Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ñ Ð´Ñ€ÑƒÐ³Ð¸ потребители. СамоличноÑтта Ви не може да бъде определена по Вашите Ñлучайни ИД."</string> <!-- XTXT: settings(tracing) - status next to switch under title --> <string name="settings_tracing_status_active">"Ðктивно"</string> <!-- XTXT: settings(tracing) - status next to switch under title --> @@ -595,7 +595,7 @@ <!-- XTXT: settings(notification) - next to a switch --> <string name="settings_notifications_subtitle_update_risk">"ПромÑна на Ð’Ð°ÑˆÐ¸Ñ Ñ€Ð¸Ñк от заразÑване"</string> <!-- XTXT: settings(notification) - next to a switch --> - <string name="settings_notifications_subtitle_update_test">"Ð¡Ñ‚Ð°Ñ‚ÑƒÑ Ð½Ð° Ð’Ð°ÑˆÐ¸Ñ Ñ‚ÐµÑÑ‚ за COVID-19"</string> + <string name="settings_notifications_subtitle_update_test">"Ð¡Ñ‚Ð°Ñ‚ÑƒÑ Ð½Ð° Ð’Ð°ÑˆÐ¸Ñ Ñ‚ÐµÑÑ‚ за коронавируÑ"</string> <!-- XBUT: settings(notification) - go to operating settings --> <string name="settings_notifications_button_open_settings">"Към наÑтройките на уÑтройÑтвото"</string> <!-- XACT: main (overview) - illustraction description, explanation image, displays notificatin status, active --> @@ -604,7 +604,7 @@ <string name="settings_notifications_illustration_description_inactive">"Жена, коÑто е дезактивирала извеÑтиÑта от приложението Corona-Warn-App."</string> <!-- XBUT: settings - go to reset application --> <string name="settings_reset_title">"ИзчиÑтване на данните в приложението"</string> - <!-- XTXT: settings(reset) - explains the user what do expect when he navigates to reset --> + <!-- XTXT: settings(reset) - explains the user what do expect when navigating to reset --> <string name="settings_reset_body_description">"Изтрийте вÑички Ñвои данни в приложението."</string> <!-- XHED: settings(reset) - multiline headline below illustration --> <string name="settings_reset_headline">"Потвърждавате ли, че желаете да изчиÑтите данните в приложението?"</string> @@ -660,7 +660,7 @@ <!-- YTXT: Body text for about information page --> <string name="information_about_body_emphasized">"ИнÑтитутът „Роберт Кох“ (RKI) е федералната Ñлужба за общеÑтвено здравеопазване в ГерманиÑ. Той е издател на приложението Corona-Warn-App по поръчка на федералното правителÑтво. Приложението е предназначено да бъде дигитално допълнение на вече въведените мерки за опазване на общеÑтвеното здраве: Ñоциално диÑтанциране, поддържане на виÑока хигиена и ноÑене на маÑки."</string> <!-- YTXT: Body text for about information page --> - <string name="information_about_body">"Хората, които използват приложението, помагат за проÑледÑване и прекъÑване на веригите на заразÑване. Приложението запазва във Вашето уÑтройÑтво данните за контактите Ви Ñ Ð´Ñ€ÑƒÐ³Ð¸ хора. Получавате извеÑтие, ако Ñте били в контакт Ñ Ð»Ð¸Ñ†Ð°, които впоÑледÑтвие Ñа били диагноÑтицирани Ñ COVID-19. Вашата ÑамоличноÑÑ‚ и неприкоÑновеноÑтта на данните Ви Ñа защитени по вÑÑко време."</string> + <string name="information_about_body">"Хората, които използват приложението, помагат за проÑледÑване и прекъÑване на веригите на заразÑване. Приложението запазва във Вашето уÑтройÑтво данните за контактите Ви Ñ Ð´Ñ€ÑƒÐ³Ð¸ хора. Получавате извеÑтие, ако Ñте били в контакт Ñ Ð»Ð¸Ñ†Ð°, които впоÑледÑтвие Ñа били диагноÑтицирани Ñ ÐºÐ¾Ñ€Ð¾Ð½Ð°Ð²Ð¸Ñ€ÑƒÑ. Вашата ÑамоличноÑÑ‚ и неприкоÑновеноÑтта на данните Ви Ñа защитени по вÑÑко време."</string> <!-- XACT: describes illustration --> <string name="information_about_illustration_description">"Група лица използват Ñмартфоните Ñи, придвижвайки Ñе из града."</string> <!-- XHED: Page title for privacy information page, also menu item / button text --> @@ -754,7 +754,7 @@ <!-- XHED: Dialog title for already paired test error: qr --> <string name="submission_error_dialog_web_test_paired_title">"Ðевалиден QR код"</string> <!-- XMSG: Dialog body for already paired test error: qr --> - <string name="submission_error_dialog_web_test_paired_body">"QR кодът е невалиден или вече е региÑтриран на друг Ñмартфон. Ще получите резултата Ñи от център за теÑтване или лабораториÑ, незавиÑимо от валидноÑтта на QR кода. Ðко Ви бъде поÑтавена диагноза COVID-19, Ñлужбата за общеÑтвено оÑигурÑване ще Ви уведоми за това."</string> + <string name="submission_error_dialog_web_test_paired_body">"QR кодът е невалиден или вече е региÑтриран на друг Ñмартфон. Ще получите резултата Ñи от център за теÑтване или лабораториÑ, незавиÑимо от валидноÑтта на QR кода. Ðко Ви бъде поÑтавена диагноза \"коронавируÑ\", Ñлужбата за общеÑтвено оÑигурÑване ще Ви уведоми за това."</string> <!-- XHED: Dialog title for already paired test error: tan --> <string name="submission_error_dialog_web_test_paired_title_tan">"ТÐРкодът е невалиден"</string> <!-- XMSG: Dialog body for already paired test via tan - error: tan --> @@ -784,9 +784,9 @@ <string name="submission_error_dialog_web_tan_redeemed_button_positive">"OK"</string> <!-- XHED: Dialog title for keys submission process cancellation --> - <string name="submission_error_dialog_confirm_cancellation_title">"Желаете ли отмÑна?"</string> + <string name="submission_error_dialog_confirm_cancellation_title">"ИÑкате ли да отмените въвеждането на Вашите Ñимптоми?"</string> <!-- XMSG: Dialog body for keys submission process cancellation --> - <string name="submission_error_dialog_confirm_cancellation_body">"Въведените от Ð’Ð°Ñ Ð´Ð°Ð½Ð½Ð¸ нÑма да бъдат запазени."</string> + <string name="submission_error_dialog_confirm_cancellation_body">"Ðко предоÑтавите Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° Вашите Ñимптоми, Ñ‚Ñ Ð¼Ð¾Ð¶Ðµ да Ñлужи като по-точно предупреждение за оÑтаналите."</string> <!-- XBUT: Positive button for keys submission process cancellation --> <string name="submission_error_dialog_confirm_cancellation_button_positive">"Да"</string> <!-- XBUT: Negative button for keys submission process cancellation --> @@ -814,7 +814,7 @@ <!-- XHED: Dialog headline for invalid QR code --> <string name="submission_qr_code_scan_invalid_dialog_headline">"Ðевалиден QR код"</string> <!-- YTXT: Dialog Body text for invalid QR code --> - <string name="submission_qr_code_scan_invalid_dialog_body">"QR кодът е невалиден или вече е региÑтриран на друг Ñмартфон. Ще получите резултата Ñи от център за теÑтване или лабораториÑ, незавиÑимо от валидноÑтта на QR кода. Ðко Ви бъде поÑтавена диагноза COVID-19, Ñлужбата за общеÑтвено оÑигурÑване ще бъде уведомена за това по уÑÑ‚Ð°Ð½Ð¾Ð²ÐµÐ½Ð¸Ñ Ð¾Ñ‚ правните норми канал и ще Ñе Ñвърже Ñ Ð’Ð°Ñ."</string> + <string name="submission_qr_code_scan_invalid_dialog_body">"QR кодът е невалиден или вече е региÑтриран на друг Ñмартфон. Ще получите резултата Ñи от център за теÑтване или лабораториÑ, незавиÑимо от валидноÑтта на QR кода. Ðко Ви бъде поÑтавена диагноза \"коронавируÑ\", Ñлужбата за общеÑтвено оÑигурÑване ще бъде уведомена за това по уÑÑ‚Ð°Ð½Ð¾Ð²ÐµÐ½Ð¸Ñ Ð¾Ñ‚ правните норми канал и ще Ñе Ñвърже Ñ Ð’Ð°Ñ."</string> <!-- XBUT: Dialog(Invalid QR code) - positive button (right) --> <string name="submission_qr_code_scan_invalid_dialog_button_positive">"МолÑ, опитайте отново."</string> <!-- XBUT: Dialog(Invalid QR code) - negative button (left) --> @@ -825,6 +825,34 @@ <!-- YTXT: instruction text for QR code scanning --> <string name="submission_qr_code_scan_body">"Позиционирайте QR кода в рамката."</string> + <!-- QR Code Consent Screen --> + <!-- XHED: Page headline for Submission consent --> + <string name="submission_consent_main_headline">"Вашето ÑъглаÑие"</string> + <!-- YTXT: Body for Submissionconsent --> + <string name="submission_consent_main_headline_body">"За да можете да получите резултата от Ð’Ð°ÑˆÐ¸Ñ Ñ‚ÐµÑÑ‚ и да предупредите оÑтаналите, Ñ‚Ñ€Ñбва да дадете Ñвоето ÑъглаÑие."</string> + <!-- XHED: Page subheadline for consent call test result --> + <string name="submission_consent_call_test_result">"Извличане на резултат от теÑÑ‚"</string> + <!-- YTXT: Body for Submission Consent call test result body --> + <string name="submission_consent_call_test_result_body">"Ð’ Ñледващата Ñтъпка Ñканирайте QR кода от Ð’Ð°ÑˆÐ¸Ñ Ñ‚ÐµÑÑ‚, за да получите резултата."</string> + <!-- YTXT: Body sub text 1 for Submission Consent call test result --> + <string name="submission_consent_call_test_result_scan_your_test_only">"Сканирайте Ñамо Ð’Ð°ÑˆÐ¸Ñ ÑобÑтвен теÑÑ‚."</string> + <!-- YTXT: Body sub text 2 for Submission Consent call test result --> + <string name="submission_consent_call_test_result_scan_test_only_once">"Можете да Ñканирате Ð’Ð°ÑˆÐ¸Ñ Ñ‚ÐµÑÑ‚ Ñамо веднъж. Приложението не може да обработва нÑколко теÑта едновременно."</string> + <!-- XHED: Page subheadline for consent help by warning others --> + <string name="submission_consent_help_by_warning_others_headline">"МолÑ, помогнете на хората, Ñ ÐºÐ¾Ð¸Ñ‚Ð¾ Ñте имали контакт, като ги предупредите!"</string> + <!-- YTXT: Body for consent help by warning others --> + <string name="submission_consent_help_by_warning_others_body">"Ðко Ви е поÑтавена диагноза \"коронавируÑ\", можете да предупредите оÑтаналите Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰Ñ‚Ð° на приложението. ФункциÑта за предупреждаване работи в нÑколко държави. Към момента това Ñа:"</string> + <!-- YTXT: Page bottom text for consent screen --> + <string name="submission_consent_main_bottom_body">"Подробна Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° обработването на данни и Вашето ÑъглаÑие"</string> + <!-- YTXT: Body for consent main section first point --> + <string name="submission_consent_main_first_point">"Вашето ÑъглаÑие е доброволно."</string> + <!-- YTXT: Body for consent main section second point --> + <string name="submission_consent_main_second_point">"Можете да получите резултата от Ð’Ð°ÑˆÐ¸Ñ Ñ‚ÐµÑÑ‚, без да е необходимо да го ÑподелÑте, но ако Ñподелите резултата Ñи, ще помогнете на другите да Ñе предпазÑÑ‚ от заразÑване."</string> + <!-- YTXT: Body for consent main section third point --> + <string name="submission_consent_main_third_point">"Вашата ÑамоличноÑÑ‚ нÑма да бъде разкрита. Другите потребители нÑма да знаÑÑ‚ кой е Ñподелил резултатите Ñи от теÑта."</string> + <!-- YTXT: Body for consent main section fourth point --> + <string name="submission_consent_main_fourth_point">"За да дадете ÑъглаÑието Ñи, Ñ‚Ñ€Ñбва да имате навършени 16 години."</string> + <!-- Submission Test Result --> <!-- XHED: Page headline for test result --> <string name="submission_test_result_headline">"Резултат от теÑÑ‚"</string> @@ -835,9 +863,9 @@ <!-- YTXT: Body text for for results next steps --> <string name="submission_test_result_steps_added_body">"ВашиÑÑ‚ теÑÑ‚ е запазен в приложението Corona-Warn-App."</string> <!-- XHED: Page headline for pending test result next steps --> - <string name="submission_test_result_pending_steps_waiting_heading">"Ð’Ñе още нÑма резултат от теÑта"</string> + <string name="submission_test_result_pending_steps_waiting_heading">"Ð’Ñе още нÑма резултат от теÑта Ви."</string> <!-- YTXT: Body text for next steps section of waiting test result page --> - <string name="submission_test_result_pending_steps_waiting_body">"МолÑ, бъдете търпеливи, тъй като определÑнето на резултата може да отнеме нÑколко дни.\n\nРезултатът от Ð’Ð°ÑˆÐ¸Ñ Ñ‚ÐµÑÑ‚ ще Ви бъде изпратен Ñъщо и извън приложението. Службата за общеÑтвено оÑигурÑване ще Ви уведоми, ако той е положителен.\n\nÐко резултатът Ви е положителен, Ð¼Ð¾Ð»Ñ Ð¾Ð±Ð°Ð´ÐµÑ‚Ðµ Ñе на номера, показан под “ЗаÑвка за ТÐРкодâ€, за да го региÑтрирате в приложението и да предупредите оÑтаналите потребители."</string> + <string name="submission_test_result_pending_steps_waiting_body">"Резултатът от Ð’Ð°ÑˆÐ¸Ñ Ñ‚ÐµÑÑ‚ ще Ñе покаже в приложението веднага щом бъде готов."</string> <!-- XBUT: test result pending : refresh button --> <string name="submission_test_result_pending_refresh_button">"Ðктуализиране"</string> <!-- XBUT: test result pending : remove the test button --> @@ -873,7 +901,7 @@ <!-- XHED: Dialog title for test removal --> <string name="submission_test_result_dialog_remove_test_title">"ТеÑÑ‚ÑŠÑ‚ може да Ñе Ñканира Ñамо веднъж."</string> <!-- YTXT: Dialog text for test removal --> - <string name="submission_test_result_dialog_remove_test_message">"Ðко изтриете теÑта, повече нÑма да можете да извлечете данните за резултата Ñи. Ще получите резултата Ñи от център за теÑтване или лабораториÑ, незавиÑимо от валидноÑтта на QR кода. Ðко Ви бъде поÑтавена диагноза COVID-19, Ñлужбата за общеÑтвено оÑигурÑване ще бъде уведомена за това по уÑÑ‚Ð°Ð½Ð¾Ð²ÐµÐ½Ð¸Ñ Ð¾Ñ‚ правните норми канал и ще Ñе Ñвърже Ñ Ð’Ð°Ñ."</string> + <string name="submission_test_result_dialog_remove_test_message">"Ðко изтриете теÑта, повече нÑма да можете да извлечете данните за резултата Ñи. Ще получите резултата Ñи от център за теÑтване или лабораториÑ, незавиÑимо от валидноÑтта на QR кода. Ðко Ви бъде поÑтавена диагноза \"коронавируÑ\", Ñлужбата за общеÑтвено оÑигурÑване ще бъде уведомена за това по уÑÑ‚Ð°Ð½Ð¾Ð²ÐµÐ½Ð¸Ñ Ð¾Ñ‚ правните норми канал и ще Ñе Ñвърже Ñ Ð’Ð°Ñ."</string> <!-- XBUT: Positive button for test removal --> <string name="submission_test_result_dialog_remove_test_button_positive">"Изтриване"</string> <!-- XBUT: Negative button for test removal --> @@ -882,6 +910,16 @@ <string name="submission_test_result_card_positive_title">"Положителен резултат за SARS-CoV-2"</string> <!-- YTXT: Body text for test result card positive --> <string name="submission_test_result_card_positive_body">"Вашето заразÑване ÑÑŠÑ SARS-CoV-2 е потвърдено."</string> + <!-- XHED: Page headline for test result with consent given --> + <string name="submission_test_result_consent_given_heading">"Резултатът от Ð’Ð°ÑˆÐ¸Ñ Ñ‚ÐµÑÑ‚"</string> + <!-- XHED: Subtitle text for test result card with consent given --> + <string name="submission_test_result_consent_given_subtitle">"Благодарим Ви, че помагате да Ñе Ñпре разпроÑтранението на коронавируÑа."</string> + <!-- YTXT: body text for test result card with consent given --> + <string name="submission_test_result_consent_given_body"><b>"Хората, Ñ ÐºÐ¾Ð¸Ñ‚Ð¾ Ñте имали контакт, ще бъдат предупредени."</b>" "<br/><br/>"Сега можете да помогнете за подобрÑване на точноÑтта на предупреждениÑта. За тази цел, в Ñледващата Ñтъпка ни кажете кога развихте първите Ñимптоми. Можете да отмените Ñтъпката във вÑеки един момент."</string> + <!-- XBUT: button text for the 'break up' button option on test result consent given page --> + <string name="submission_test_result_consent_given_breakup_button">"Изход"</string> + + <!-- Submission Tan --> <!-- XHED: Page title for TAN submission pge --> @@ -903,7 +941,7 @@ <!-- XHED: Page headline for menu the at start of the submission process --> <string name="submission_intro_headline">"Ето как работи приложението Corona-Warn-App"</string> <!-- YTXT: submission introduction text --> - <string name="submission_intro_text">"За да работи добре приложението, разчитаме на подкрепата на хората, диагноÑтицирани Ñ COVID-19.\n\nТъй като Ñе разменÑÑ‚ Ñамо криптирани Ñлучайни ИД кодове, анонимноÑтта Ви е гарантирана. Може да предприемете Ñледните Ñтъпки:"</string> + <string name="submission_intro_text">"За да работи добре приложението, разчитаме на подкрепата на хората, диагноÑтицирани Ñ ÐºÐ¾Ñ€Ð¾Ð½Ð°Ð²Ð¸Ñ€ÑƒÑ.\n\nТъй като Ñе разменÑÑ‚ Ñамо криптирани Ñлучайни ИД кодове, анонимноÑтта Ви е гарантирана. Може да предприемете Ñледните Ñтъпки:"</string> <!-- XBUT: Submission introduction next button--> <string name="submission_intro_button_next">"Ðапред"</string> <!-- XACT: Submission intro - illustration description, explanation image --> @@ -911,7 +949,7 @@ <!-- YTXT: submission introduction bullet points --> <string-array name="submission_intro_bullet_points"> <item>"Ðко в документа Ñ Ñ€ÐµÐ·ÑƒÐ»Ñ‚Ð°Ñ‚Ð° от теÑта Ви има QR код, можете да го Ñканирате и да региÑтрирате теÑта Ñи. Ð’ момента, в който резултатът бъде готов, ще можете да го видите в приложението."</item> - <item>"Ðко Ви е поÑтавена диагноза COVID-19, можете да предупредите оÑтаналите потребители."</item> + <item>"Ðко Ви е поÑтавена диагноза \"коронавируÑ\", можете да предупредите оÑтаналите потребители."</item> <item>"Ðко Ви е предоÑтавен ТÐРкод за положителен резултат, може да го използвате, за да региÑтрирате теÑта."</item> <item>"Ðко не разполагате Ñ Ð¢ÐРкод, по телефона може да заÑвите да Ви бъде предоÑтавен такъв."</item> </string-array> @@ -920,25 +958,25 @@ <!-- Dispatcher --> <!-- XHED: Page headline for dispatcher menu --> - <string name="submission_dispatcher_headline">"Избор"</string> + <string name="submission_dispatcher_headline">"Извличане на резултат от теÑÑ‚"</string> <!-- XHED: Page subheadline for dispatcher menu --> - <string name="submission_dispatcher_subheadline">"С каква Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ñ€Ð°Ð·Ð¿Ð¾Ð»Ð°Ð³Ð°Ñ‚Ðµ?"</string> + <string name="submission_dispatcher_subheadline">"Получете резултата от Ð’Ð°ÑˆÐ¸Ñ Ñ‚ÐµÑÑ‚ чрез приложението и предупредете оÑтаналите. По този начин предпазвате Ñебе Ñи и помагате да Ñе Ñпре разпроÑтранението на коронавируÑа."</string> <!-- XHED: Page subheadline for dispatcher options asking if they have already been tested: QR and TAN --> - <string name="submission_dispatcher_needs_testing_subheadline">""</string> + <string name="submission_dispatcher_needs_testing_subheadline">"Правили ли Ñте Ñи теÑÑ‚?"</string> <!-- XHED: Page subheadline for dispatcher options asking if they already have a positive test: tele-TAN --> - <string name="submission_dispatcher_already_positive_subheadline">""</string> + <string name="submission_dispatcher_already_positive_subheadline">"Положителен ли е ВашиÑÑ‚ резултат от теÑта за коронавируÑ?"</string> <!-- YTXT: Dispatcher text for QR code option --> - <string name="submission_dispatcher_card_qr">"Документ Ñ QR код"</string> + <string name="submission_dispatcher_card_qr">"ТеÑÑ‚ Ñ QR код"</string> <!-- YTXT: Body text for QR code dispatcher option --> <string name="submission_dispatcher_qr_card_text">"РегиÑтрирайте теÑта Ñи, като Ñканирате QR кода на документа."</string> <!-- YTXT: Dispatcher text for TAN code option --> - <string name="submission_dispatcher_card_tan_code">"ТÐРкод"</string> + <string name="submission_dispatcher_card_tan_code">"Въвеждане на ТÐРкод"</string> <!-- YTXT: Body text for TAN code dispatcher option --> - <string name="submission_dispatcher_tan_code_card_text">"РегиÑтрирайте теÑта Ñи, като въведете ТÐРкода ръчно."</string> + <string name="submission_dispatcher_tan_code_card_text">"Имате TAN код? Въведете го, за да предупредите оÑтаналите. "</string> <!-- YTXT: Dispatcher text for TELE-TAN option --> - <string name="submission_dispatcher_card_tan_tele">"ЗаÑвка за ТÐРкод"</string> + <string name="submission_dispatcher_card_tan_tele">"Ð’Ñе още нÑмате TAN код?"</string> <!-- YTXT: Body text for TELE_TAN dispatcher option --> - <string name="submission_dispatcher_tan_tele_card_text">"МолÑ, обадете ни Ñе, ако Ви е поÑтавена диагноза COVID-19."</string> + <string name="submission_dispatcher_tan_tele_card_text">"Позвънете ни, за да получите TAN код."</string> <!-- XACT: Dispatcher Tan page title --> <string name="submission_dispatcher_accessibility_title">"С каква Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ñ€Ð°Ð·Ð¿Ð¾Ð»Ð°Ð³Ð°Ñ‚Ðµ?"</string> @@ -956,6 +994,25 @@ <!-- XHED: Title for the interop country list--> <string name="submission_interoperability_list_title">"Ð’ момента в международното региÑтриране на излаганиÑта на риÑк от заразÑване учаÑтват Ñледните държави:"</string> + <!-- Submission Positive Other Warning No Consent --> + <!-- YTXT: Body text for the positive result additional warning page--> + <string name="submission_positive_other_warning_no_consent_body_first_part">"Тъй като теÑÑ‚ÑŠÑ‚ Ви за ÐºÐ¾Ñ€Ð¾Ð½Ð°Ð²Ð¸Ñ€ÑƒÑ Ðµ положителен, можете да предупредите оÑтаналите чрез приложението."</string> + <!-- YTXT: Body text for the positive result additional warning page--> + <string name="submission_positive_other_warning_no_consent_body_second_part">"ФункциÑта за предупреждаване работи в нÑколко държави. Към момента това Ñа:"</string> + + + <!-- Test result positive and no consent given --> + <!-- XHED: Title for test result positive and no consent given--> + <string name="submission_test_result_positive_no_consent_subtitle">"МолÑ, помогнете на вÑички наÑ!"</string> + <!-- XTXT: First bullet point when test result is positive and consent is requested for key sharing--> + <string name="submission_test_result_positive_no_consent_text_1"><b>"Споделете резултата от Ð’Ð°ÑˆÐ¸Ñ Ñ‚ÐµÑÑ‚ и помогнете на другите да Ñе предпазÑÑ‚ от заразÑване."</b></string> + <!-- XTXT: Second bullet point when test result is positive and consent is requested for key sharing--> + <string name="submission_test_result_positive_no_consent_text_2">"Вашата ÑамоличноÑÑ‚ нÑма да бъде разкрита. Другите потребители нÑма да знаÑÑ‚ кой е Ñподелил резултатите Ñи от теÑта."</string> + <!-- XTXT: Third bullet point when test result is positive and consent is requested for key sharing--> + <string name="submission_test_result_positive_no_consent_text_3">"МолÑ, Ñледвайте инÑтрукциите на Ð’Ð°ÑˆÐ¸Ñ Ð»ÐµÐºÐ°Ñ€ и Ñи оÑтанете вкъщи, за да не заразÑвате други хора."</string> + <!-- XBUT: Button for giving consent for key sharing --> + <string name="submission_test_result_positive_no_consent_button_warn_others">"Предупредете другите"</string> + <!-- Submission Country Selector --> <!-- XHED: Page title for the submission country selection page --> <string name="submission_positive_country_selection_title">"ÐŸÑ€ÐµÐ´ÑƒÐ¿Ñ€ÐµÐ¶Ð´ÐµÐ½Ð¸Ñ Ð·Ð° цÑла Европа"</string> @@ -995,13 +1052,29 @@ <!-- XACT: submission finished - illustration description, explanation image --> <string name="submission_done_illustration_description">"Имали ли Ñте един или повече от Ñледните Ñимптоми през поÑледните нÑколко дни?"</string> + <!-- Submission Done No Consent--> + <!-- XHED: Page title for completed submission page --> + <string name="submission_done_no_consent_title">"Благодарим Ви!"</string> + <!-- YTXT: Page subtitle for completed submission page --> + <string name="submission_done_no_consent_subtitle">"Благодарим Ви, че помагате да Ñе Ñпре разпроÑтранението на коронавируÑа."</string> + <!-- YTXT: Page body for submission no consent page --> + <string name="submission_done_no_consent_body_title">"Другите потребители ще бъдат предупредени."</string> + <!-- YTXT: Page body for submission no consent page --> + <string name="submission_done_no_consent_body">"Сега можете да помогнете за подобрÑване на точноÑтта на предупреждениÑта. За тази цел, в Ñледващата Ñтъпка ни кажете кога развихте първите Ñимптоми. Можете да отмените Ñтъпката във вÑеки един момент."</string> + <!-- XBUT: submission continue with symptom recording button --> + <string name="submission_done_no_consent_continue_with_symptom_recording">"Въведете Ñимптоми"</string> + <!-- XBUT: submission continue break flow button--> + <string name="submission_done_no_consent_break_flow">"Изход"</string> + <!-- XACT: submission finished - illustration description, explanation image --> + <string name="submission_done_no_consent_illustration_description">"ÐÑколко души гледат Ñмартфоните Ñи."</string> + <!-- Submission Symptoms --> <!-- XHED: Page title for symptom screens --> <string name="submission_symptom_title">"Симптоми"</string> <!-- XTXT: headline text for initial symptom screen --> - <string name="submission_symptom_initial_headline">"Имали ли Ñте един или повече от Ñледните Ñимптоми?"</string> + <string name="submission_symptom_initial_headline">"Имали ли Ñте един или повече от Ñледните Ñимптоми през поÑледните нÑколко дни?"</string> <!-- YTXT: explanation text for initial symptom screen --> - <string name="submission_symptom_initial_explanation">"Можете да поÑочвате дали и кога Ñте проÑвили Ñимпотми на COVID-19, за да позволите на приложението да оцени по-точно риÑка от заразÑване за оÑтаналите потребители. Ðко не желаете да предоÑтавите такава информациÑ, проÑто изберете \"Без отговор\"."</string> + <string name="submission_symptom_initial_explanation">"Може да поÑочите дали и кога Ñте проÑвили Ñимптоми на коронавируÑ, за да позволите на приложението да оцени по-точно риÑка от заразÑване за оÑтаналите потребители. Тази Ñтъпка не е задължителна. Ðко не желаете да предоÑтавите такава информациÑ, проÑто изберете \"Без отговор\"."</string> <!-- YTXT: Bullet points for symptoms --> <string-array name="submission_symptom_symptom_bullets"> <item>"Повишена температура или треÑка"</item> @@ -1058,9 +1131,9 @@ <!-- XHED: Page title for calendar page in submission symptom flow --> <string name="submission_symptom_calendar_title">"Ðачало на Ñимптомите"</string> <!-- XHED: Page headline for calendar page in symptom submission flow --> - <string name="submission_symptom_calendar_headline">"Кога Ñе поÑвиха за първи път тези Ñимптоми? "</string> + <string name="submission_symptom_calendar_headline">"Кога забелÑзахте Ñимптомите за първи път?"</string> <!-- YTXT: Body text for calendar page in symptom submission flow--> - <string name="submission_symptom_calendar_body">"Изберете точната дата от календара или, ако не можете да Ñи Ñ Ñпомните, нÑÐºÐ¾Ñ Ð¾Ñ‚ другите опции."</string> + <string name="submission_symptom_calendar_body">"МолÑ, поÑочете датата възможно най-точно."</string> <!-- XBUT: symptom calendar screen less than 7 days button --> <string name="submission_symptom_less_seven">"През поÑледните 7 дни"</string> <!-- XBUT: symptom calendar screen 1-2 weeks button --> @@ -1090,7 +1163,7 @@ <!-- YTXT: Body text for submission status: fetching --> <string name="submission_status_card_body_fetching">"Резултатът Ви Ñе актуализира"</string> <!-- YTXT: Body text for submission status: unregistered --> - <string name="submission_status_card_body_unregistered">"Помогнете за прекъÑването на веригата на заразÑване, като уведомите оÑтаналите потребители."</string> + <string name="submission_status_card_body_unregistered">"Пазете Ñе и помогнете и на другите да Ñе предпазÑÑ‚."</string> <!-- YTXT: Body text for submission status: pending --> <string name="submission_status_card_body_pending">"Резултатът от Ð’Ð°ÑˆÐ¸Ñ Ñ‚ÐµÑÑ‚ вÑе още не е определен."</string> <!-- YTXT: Body text for submission status: invalid --> @@ -1102,7 +1175,7 @@ <!-- YTXT: Body text for submission status fetch failed --> <string name="submission_status_card_body_failed">"ВашиÑÑ‚ теÑÑ‚ е направен преди повече от 21 дни и вече не е валиден. МолÑ, изтрийте го, за да можете да добавите друг Ñлед това."</string> <!-- XBUT: submission status card unregistered button --> - <string name="submission_status_card_button_unregistered">"Ðаучете повече и помогнете"</string> + <string name="submission_status_card_button_unregistered">"Следващи Ñтъпки"</string> <!-- XBUT: submission status card show results button --> <string name="submission_status_card_button_show_results">"Показване на теÑÑ‚"</string> <!-- XBUT: submission status card fetch failed button --> @@ -1140,7 +1213,51 @@ </string-array> <!-- XBUT Symptoms exact date button --> - <string name="symptoms_calendar_exact_date_button">"Точна дата"</string> + <string name="symptoms_calendar_exact_date_button">"Дата"</string> + + <!-- Submission consent custom view --> + <!-- XHED: Title for consent given --> + <string name="submission_consent_view_consent_given">"СъглаÑие\n“Предупредете другите†е дадено"</string> + <!-- XHED: Title for consent NOT given --> + <string name="submission_consent_view_consent_not_given">"СъглаÑие\n“Предупредете другите†не е дадено"</string> + + <!-- Submission test result available --> + <!-- XHED: Page title for test results available step --> + <string name="submission_test_result_available_title">"Резултатът от теÑта Ви е готов"</string> + <!-- XACT: Test result available illustration description --> + <string name="submission_test_result_available_illustration_description">"Жена държи Ñмартфон в ръката Ñи. Той изпраща Ñигнал към друг Ñмартфон."</string> + <!-- YTXT: Text for consent given --> + <string name="submission_test_result_available_text_consent_given">"Благодарим Ви, че Ñе ÑъглаÑихте да Ñподелите резултата от Ð’Ð°ÑˆÐ¸Ñ Ñ‚ÐµÑÑ‚ и така да помогнете, като предупредите оÑтаналите. \n\n"<b>"Ð’ Ñледващата Ñтъпка, молÑ, Ñподелете резултата от теÑта Ñи, като натиÑнете \"СподелÑнеâ€."</b></string> + <!-- XHED: Close screen popup title for consent given --> + <string name="submission_test_result_available_close_dialog_title_consent_given">"Желаете ли отмÑна?"</string> + <!-- XTXT: Close screen popup text for consent given --> + <string name="submission_test_result_available_close_dialog_body_consent_given">"Въведените от Ð’Ð°Ñ Ð´Ð°Ð½Ð½Ð¸ нÑма да бъдат запазени."</string> + <!-- YTXT: Text for consent NOT given --> + <string name="submission_test_result_available_text_consent_not_given">"Избрали Ñте да не ÑподелÑте резултатите от теÑта Ñи. ОÑтаналите нÑма да бъдат предупредени. \n\nÐ’ Ñледващата Ñтъпка можете да промените решението Ñи и да Ñподелите резултата от теÑта Ñи, за да помогнете да Ñе Ñпре разпроÑтранението на коронавируÑа и да предпазите оÑтаналите."</string> + <!-- XHED: Close screen popup title for consent NOT given --> + <string name="submission_test_result_available_close_dialog_title_consent_not_given">"Важно:\nÐа път Ñте да отмените този процеÑ.\nÐ’Ñе още не Ñте предупредили оÑтаналите. МолÑ, завършете процеÑа, за да помогнете на оÑтаналите да Ñе предпазÑÑ‚."</string> + <!-- XTXT: Close screen popup text for consent NOT given --> + <string name="submission_test_result_available_close_dialog_body_consent_not_given">"Потвърждавате ли, че желаете да отмените процеÑа?"</string> + <!-- XBUT: Close screen popup cancel button --> + <string name="submission_test_result_available_close_dialog_cancel_button">"Отказ"</string> + <!-- XBUT: Close screen popup continue button --> + <string name="submission_test_result_available_close_dialog_continue_button">"Ðапред"</string> + + <!-- Submission your consent screen --> + <!-- XHED: Your consent screen title --> + <string name="submission_your_consent_title">"Вашето ÑъглаÑие"</string> + <!-- XTXT: Your consent screen switch label - next to a switch --> + <string name="submission_your_consent_switch_subtitle">"Предупредете другите"</string> + <!-- XTXT: Your consent screen switch status on --> + <string name="submission_your_consent_switch_status_on">"Ðктивно"</string> + <!-- XTXT: Your consent screen switch status off --> + <string name="submission_your_consent_switch_status_off">"СпрÑно"</string> + <!-- XTXT: Your consent screen about agreement --> + <string name="submission_your_consent_about_agreement">"Дадохте Ñледното ÑъглаÑие:"</string> + <!-- XHED: Your consent screen agreement title --> + <string name="submission_your_consent_agreement_title"><b>"СъглаÑие"</b></string> + <!-- XTXT: Your consent screen detailed information --> + <string name="submission_your_consent_agreement_details">"Подробна Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° обработването на данни и Вашето ÑъглаÑие"</string> <!-- #################################### Button Tooltips for Accessibility @@ -1215,8 +1332,6 @@ <!-- NOTR --> <string name="test_api_button_show_qr_code">"Show QR Code"</string> <!-- NOTR --> - <string name="test_api_button_submit_keys">"Submit keys to Server"</string> - <!-- NOTR --> <string name="test_api_button_scan_qr_code">"Scan Exposure Key"</string> <!-- NOTR --> <string name="test_api_switch_last_three_hours_from_server">"Last 3 Hours Mode"</string> @@ -1309,7 +1424,7 @@ <!-- XTXT: First section after the header of the interoperability information/configuration view --> <string name="interoperability_configuration_first_section">"ÐÑколко държави обединиха уÑилиÑ, за да можете да получавате международни Ð¿Ñ€ÐµÐ´ÑƒÐ¿Ñ€ÐµÐ¶Ð´ÐµÐ½Ð¸Ñ Ñ‡Ñ€ÐµÐ· ÑъвмеÑтен Ñървър за обмен на данни. Така при определÑнето на риÑка от заразÑване Ñе вземат предвид и контактите Ви Ñ Ð¿Ð¾Ñ‚Ñ€ÐµÐ±Ð¸Ñ‚ÐµÐ»Ð¸ на официалните Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð·Ð° борба Ñ ÐºÐ¾Ñ€Ð¾Ð½Ð°Ð²Ð¸Ñ€ÑƒÑа и в други държави."</string> <!-- XTXT: Second section after the header of the interoperability information/configuration view --> - <string name="interoperability_configuration_second_section">"За целта приложението Ð¸Ð·Ñ‚ÐµÐ³Ð»Ñ Ð¸ вÑеки ден актуализира ÑпиÑъка ÑÑŠÑ Ñлучайните идентификатори на потребителите, които Ñа избрали да ги ÑподелÑÑ‚ чрез ÑобÑтвените Ñи приложениÑ. ПоÑле този ÑпиÑък Ñе ÑравнÑва ÑÑŠÑ Ñлучайните ИД, запиÑани от вашето уÑтройÑтво. Ежедневната Ð°ÐºÑ‚ÑƒÐ°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð½Ð° ÑпиÑъка обикновено е безплатна за Ð’Ð°Ñ â€“ използваните от приложението данни не Ñе такÑуват и за Ñ‚ÑÑ… не Ñе начиÑлÑват такÑи за роуминг в други държави от ЕС."</string> + <string name="interoperability_configuration_second_section">"За тази цел приложението Ð¸Ð·Ñ‚ÐµÐ³Ð»Ñ ÑпиÑък на вÑички Ñподелени в приложението Ñлучайни идентификатори на потребители, който Ñе актуализира ежедневно. След това този ÑпиÑък Ñе ÑравнÑва ÑÑŠÑ Ñлучайните идентификатори, запиÑани от Ð’Ð°ÑˆÐ¸Ñ Ñмартфон Ñ Android. ИзтеглÑнето на ÑпиÑъците обикновено е безплатно за ВаÑ. Това означава, че мобилните оператори не такÑуват използваните от приложението данни в този контекÑÑ‚ и не начиÑлÑват за Ñ‚ÑÑ… такÑи за роуминг в други държави от ЕС. За повече подробноÑти Ñе обърнете към ÑÐ²Ð¾Ñ Ð¼Ð¾Ð±Ð¸Ð»ÐµÐ½ оператор."</string> <!-- XHED: Header right above the country list in the interoperability information/configuration view --> <string name="interoperability_configuration_list_title">"Ð’ момента в международното региÑтриране на излаганиÑта на риÑк от заразÑване учаÑтват Ñледните държави:"</string> <!-- XTXT: Text right under the country list in the interoperability information/configuration view --> @@ -1320,9 +1435,9 @@ <!-- YMSG: Onboarding tracing step first section in interoperability after the title --> <string name="interoperability_onboarding_first_section">"ÐÑколко държави обединиха уÑилиÑ, за да направÑÑ‚ възможни международните предупреждениÑ. С други думи, вече могат да Ñе вземат под внимание потенциалните ви контакти Ñ Ð¿Ð¾Ñ‚Ñ€ÐµÐ±Ð¸Ñ‚ÐµÐ»Ð¸ на официалните Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð·Ð° проÑледÑване на разпроÑтранението на коронавируÑа във вÑички учаÑтващи държави."</string> <!-- YMSG: Onboarding tracing step second section in interoperability after the title --> - <string name="interoperability_onboarding_second_section">"Когато потребителÑÑ‚ изпрати Ñвоите Ñлучайни ИД към Ñървъра за обмен на данни, ÑъвмеÑтно поддържан от учаÑтващите държави, потребителите на официалните Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð·Ð° борба Ñ ÐºÐ¾Ñ€Ð¾Ð½Ð°Ð²Ð¸Ñ€ÑƒÑа във вÑÑка една от Ñ‚ÑÑ… получават необходимите предупреждениÑ."</string> + <string name="interoperability_onboarding_second_section">"Когато нÑкой потребител изпрати ÑÐ²Ð¾Ñ Ð¿Ð¾Ð»Ð¾Ð¶Ð¸Ñ‚ÐµÐ»ÐµÐ½ резултат от теÑта (по-конкретно: Ñвоите Ñлучайни идентификатори), за да предупреди оÑтаналите, към Ñървъра за обмен на данни, ÑъвмеÑтно поддържан от учаÑтващите държави, вÑички потребители на официалните Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð·Ð° борба Ñ ÐºÐ¾Ñ€Ð¾Ð½Ð°Ð²Ð¸Ñ€ÑƒÑа във вÑÑка една от Ñ‚ÑÑ… получават необходимите предупреждениÑ."</string> <!-- YMSG: Onboarding tracing step third section in interoperability after the title. --> - <string name="interoperability_onboarding_randomid_download_free">"Ежедневното изтеглÑне на ÑпиÑъка ÑÑŠÑ Ñлучайни идентификатори обикновено е безплатно за ВаÑ. Това означава, че мобилните оператори не такÑуват използваните от приложението данни и не начиÑлÑват за Ñ‚ÑÑ… такÑи за роуминг в други държави от ЕС. За повече подробноÑти Ñе обърнете към ÑÐ²Ð¾Ñ Ð¼Ð¾Ð±Ð¸Ð»ÐµÐ½ оператор."</string> + <string name="interoperability_onboarding_randomid_download_free">"Ежедневното изтеглÑне на ÑпиÑъци ÑÑŠÑ Ñлучайни идентификатори, предоÑтавени от потребителите, Ñподелили за положителен резултат от теÑта Ñи, обикновено е безплатно за ВаÑ. Това означава, че мобилните оператори не такÑуват използваните от приложението данни и не начиÑлÑват за Ñ‚ÑÑ… такÑи за роуминг в други държави от ЕС. За повече подробноÑти Ñе обърнете към ÑÐ²Ð¾Ñ Ð¼Ð¾Ð±Ð¸Ð»ÐµÐ½ оператор."</string> <!-- XTXT: Small header above the country list in the onboarding screen for interoperability. --> <string name="interoperability_onboarding_list_title">"Ð’ момента в обмена учаÑтват Ñледните държави:"</string> @@ -1337,9 +1452,9 @@ <!-- XTXT: Description of the interoperability extension of the app. Below interoperability_onboarding_delta_title --> <string name="interoperability_onboarding_delta_subtitle">"Функциите на приложението Corona-Warn-App бÑха разширени. Много държави Ñе обединиха, за да направÑÑ‚ възможни международните Ð¿Ñ€ÐµÐ´ÑƒÐ¿Ñ€ÐµÐ¶Ð´ÐµÐ½Ð¸Ñ Ð¿Ð¾ÑредÑтвом ÑъвмеÑтно управлÑван Ñървър за обмен на данни. При изчиÑлÑването на риÑка от заразÑване вече могат да бъдат взети предвид и контактите Ñ Ð¿Ð¾Ñ‚Ñ€ÐµÐ±Ð¸Ñ‚ÐµÐ»Ð¸ на официалните Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð·Ð° проÑледÑване на коронавируÑа от други държави."</string> <!-- YMSG: Onboarding tracing step third section in interoperability after the title. --> - <string name="interoperability_onboarding_delta_randomid">"За тази цел приложението Ð¸Ð·Ñ‚ÐµÐ³Ð»Ñ ÑпиÑък на вÑички Ñподелени в приложението Ñлучайни идентификатори на потребители, който Ñе актуализира ежедневно. След това този ÑпиÑък Ñе ÑравнÑва ÑÑŠÑ Ñлучайните идентификатори, запиÑани на Вашето уÑтройÑтво."</string> + <string name="interoperability_onboarding_delta_randomid">"За тази цел приложението Ð¸Ð·Ñ‚ÐµÐ³Ð»Ñ ÐµÐ¶ÐµÐ´Ð½ÐµÐ²Ð½Ð¾ актуализиран ÑпиÑък на Ñлучайните идентификатори на вÑички потребители, Ñподелили резултатите от теÑта Ñи чрез ÑобÑтвеното Ñи приложение, за да предупредÑÑ‚ оÑтаналите. След това този ÑпиÑък Ñе ÑравнÑва ÑÑŠÑ Ñлучайните идентификатори, запиÑани на Ð’Ð°ÑˆÐ¸Ñ Ñмартфон Ñ Android."</string> <!-- YMSG: Onboarding tracing step third section in interoperability after the title. --> - <string name="interoperability_onboarding_delta_free_download">"Ежедневното изтеглÑне на ÑпиÑъка ÑÑŠÑ Ñлучайни идентификатори обикновено е безплатно за ВаÑ. Това означава, че мобилните оператори не такÑуват използваните от приложението данни и не начиÑлÑват за Ñ‚ÑÑ… такÑи за роуминг в други държави от ЕС. За повече подробноÑти Ñе обърнете към ÑÐ²Ð¾Ñ Ð¼Ð¾Ð±Ð¸Ð»ÐµÐ½ оператор."</string> + <string name="interoperability_onboarding_delta_free_download">"ИзтеглÑнето на ÑпиÑъците обикновено е безплатно за ВаÑ. Това означава, че мобилните оператори не такÑуват използваните от приложението данни и не начиÑлÑват за Ñ‚ÑÑ… такÑи за роуминг в други държави от ЕС. За повече подробноÑти Ñе обърнете към ÑÐ²Ð¾Ñ Ð¼Ð¾Ð±Ð¸Ð»ÐµÐ½ оператор."</string> <!-- XACT: interoperability (eu) - illustraction description, explanation image --> <string name="interoperability_eu_illustration_description">"Ръка държи Ñмартфон на фона на Европа и знамето на ЕС."</string> @@ -1356,4 +1471,15 @@ <!-- XBUT: Title for the interoperability onboarding Settings-Button if no network is available --> <string name="interoperability_onboarding_list_button_title_no_network">"Към наÑтройките на уÑтройÑтвото"</string> -</resources> + <!-- XHED: Title for the dialog on test result positive no consent screen --> + <string name="submission_test_result_positive_no_consent_dialog_title">"Ðе иÑкате ли да изпратите предупреждение?"</string> + <!-- XTXT: Message for the dialog on test result positive no consent screen --> + <string name="submission_test_result_positive_no_consent_dialog_message">"Ðко иÑкате да предупредите оÑтаналите, Ñ‚Ñ€Ñбва да Ñподелите резултата от Ð’Ð°ÑˆÐ¸Ñ Ñ‚ÐµÑÑ‚."</string> + <!-- XBUT: Positive button for the dialog on test result positive no consent screen --> + <string name="submission_test_result_positive_no_consent_dialog_positive_button">"Предупреди другите"</string> + <!-- XBUT: Negative button for the dialog on test result positive no consent screen --> + <string name="submission_test_result_positive_no_consent_dialog_negative_button">"Ðе предупреждавай другите"</string> + <!-- XBUT: Abort button for test result positive no consent screen --> + <string name="submission_test_result_positive_no_consent_button_abort">"Отказ"</string> + +</resources> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/values-de/strings.xml b/Corona-Warn-App/src/main/res/values-de/strings.xml index 8df83f128147beae689611178a7e29e9e07aa638..39bae4e366f1e9e188f4c782bc72b2f9e632af6b 100644 --- a/Corona-Warn-App/src/main/res/values-de/strings.xml +++ b/Corona-Warn-App/src/main/res/values-de/strings.xml @@ -104,6 +104,10 @@ <string name="notification_headline_share_positive_result">"Helfen Sie mit!"</string> <!-- XTXT: Notification body - Reminder to share a positive test result--> <string name="notification_body_share_positive_result">"Bitte warnen Sie andere und teilen Sie Ihr Testergebnis."</string> + <!-- XHED: Notification title - test result is ready --> + <string name="notification_headline_test_result_ready">"Ihr Testergebnis"</string> + <!-- XTXT: Notification body - test result is ready --> + <string name="notification_body_test_result_ready">"Es gibt wichtige Neuigkeiten. Bitte öffnen Sie Ihre Corona-Warn-App."</string> <!-- #################################### App Auto Update @@ -1033,7 +1037,7 @@ <!-- XHED: Page title for completed submission page --> <string name="submission_done_title">"Vielen Dank!"</string> <!-- YTXT: Body text for completed submission page --> - <string name="submission_done_body">"Sie haben einen wichtigen Beitrag geleistet! Dank Ihrer Mithilfe können andere gewarnt werden und entsprechend reagieren."</string> + <string name="submission_done_body">"Dank Ihrer Mithilfe können andere gewarnt werden und entsprechend reagieren."</string> <!-- XHED: Page subtitle for completed submission page --> <string name="submission_done_subtitle">"Bitte beachten Sie:"</string> <!-- YTXT: text after submission: contagious --> @@ -1334,8 +1338,6 @@ <!-- NOTR --> <string name="test_api_button_show_qr_code">"Show QR Code"</string> <!-- NOTR --> - <string name="test_api_button_submit_keys">"Submit keys to Server"</string> - <!-- NOTR --> <string name="test_api_button_scan_qr_code">"Scan Exposure Key"</string> <!-- NOTR --> <string name="test_api_switch_last_three_hours_from_server">"Last 3 Hours Mode"</string> diff --git a/Corona-Warn-App/src/main/res/values-en/strings.xml b/Corona-Warn-App/src/main/res/values-en/strings.xml index a128b4af64dfc870cd5afcfc0b98d73d37af2ebe..6df7fcaaec8518146eaaf64b0ad2125a84633f1d 100644 --- a/Corona-Warn-App/src/main/res/values-en/strings.xml +++ b/Corona-Warn-App/src/main/res/values-en/strings.xml @@ -162,7 +162,7 @@ <string name="risk_card_low_risk_no_encounters_body">"No exposure up to now"</string> <!-- XTXT: risk card - Low risk state - Days with low risk encounters --> <plurals name="risk_card_low_risk_encounter_days_body"> - <item quantity="one">"Exposures with low risk on %1$d day"</item> + <item quantity="one">"Exposures with low risk on one day"</item> <item quantity="other">"Exposures with low risk on %1$d days"</item> <item quantity="zero">"Exposures with low risk on %1$d days"</item> <item quantity="two">"Exposures with low risk on %1$d days"</item> @@ -174,7 +174,7 @@ <string name="risk_card_high_risk_no_encounters_body">"No exposure up to now"</string> <!-- XTXT: risk card - High risk state - Days with high risk encounters --> <plurals name="risk_card_high_risk_encounter_days_body"> - <item quantity="one">"Exposures on %1$d day with increased risk"</item> + <item quantity="one">"Exposures on one day with increased risk"</item> <item quantity="other">"Exposures on %1$d days with increased risk"</item> <item quantity="zero">"Exposures on %1$d days with increased risk"</item> <item quantity="two">"Exposures on %1$d days with increased risk"</item> @@ -242,7 +242,7 @@ <!-- XHED: App overview subtitle for risk explanation --> <string name="main_overview_subtitle_risk">"Risk of Infection"</string> <!-- YTXT: App overview body text about risk levels --> - <string name="main_overview_body_risk">"If you have had contact within the last 14 days with a person who was diagnosed with COVID-19, the app calculates your personal risk of infection. It does this by measuring duration and proximity of the exposure."</string> + <string name="main_overview_body_risk">"If you have had contact within the last 14 days with a person who was diagnosed with coronavirus, the app calculates your personal risk of infection. It does this by measuring duration and proximity of the exposure."</string> <!-- XHED: App overview subtitle for risk level list --> <string name="main_overview_subtitle_risk_levels">"The following risk status can be shown:"</string> <!-- XTXT: App overview increased risk level --> @@ -254,7 +254,7 @@ <!-- XHED: App overview subtitle for test procedure explanation --> <string name="main_overview_headline_test">"Notifying Other Users"</string> <!-- YTXT: App overview body text about rest procedure --> - <string name="main_overview_body_test">"Another central feature is registering your test and retrieving the result. If you are diagnosed with COVID-19, you can notify others and break the chain of infection."</string> + <string name="main_overview_body_test">"Another central feature is registering your test and retrieving the result. If you are diagnosed with coronavirus, you can notify others and break the chain of infection."</string> <!-- XHED: App overview headline for glossary --> <string name="main_overview_headline_glossary">"Definition of Terms:"</string> <!-- XHED: App overview subtitle for glossary key storage --> @@ -276,7 +276,7 @@ <!-- XHED: App overview subtitle for glossary keys --> <string name="main_overview_subtitle_glossary_keys">"Random ID"</string> <!-- YTXT: App overview body for glossary keys --> - <string name="main_overview_body_glossary_keys">"Random IDs are combinations of digits and letters generated randomly. They are exchanged between smartphones in close proximity. Random IDs cannot be traced to a specific person and are automatically deleted after 14 days. Persons diagnosed with COVID-19 can opt to share their random IDs of up to the last 14 days with other app users."</string> + <string name="main_overview_body_glossary_keys">"Random IDs are combinations of digits and letters generated randomly. They are exchanged between smartphones in close proximity. Random IDs cannot be traced to a specific person and are automatically deleted after 14 days. Persons diagnosed with coronavirus can opt to share their random IDs of up to the last 14 days with other app users."</string> <!-- XACT: main (overview) - illustraction description, explanation image --> <string name="main_overview_illustration_description">"A smartphone displays various content, numbered 1 to 3."</string> <!-- XACT: App main page title --> @@ -293,11 +293,11 @@ <!-- XHED: risk details - subtitle for additional info in case of encounter with low risk --> <string name="risk_details_additional_info_subtitle">"Why your risk of infection is low"</string> <!-- XHED: risk details - text for additional info in case of encounter with low risk --> - <string name="risk_details_additional_info_text">"You encountered a person who was later diagnosed with COVID-19. Nevertheless, based on your exposure logging data, your risk of infection is low. The risk is low if your encounter was brief or occurred at a distance. You do not need to worry and there is no specific need for action. We recommend that you adhere to the prevailing rules regarding distancing and hygiene."</string> + <string name="risk_details_additional_info_text">"You encountered a person who was later diagnosed with coronavirus. Nevertheless, based on your exposure logging data, your risk of infection is low. The risk is low if your encounter was brief or occurred at a distance. You do not need to worry and there is no specific need for action. We recommend that you adhere to the prevailing rules regarding distancing and hygiene."</string> <!-- XHED: risk details - headline, how a user should act --> <string name="risk_details_headline_behavior">"Guidelines"</string> <!-- XHED: risk details - multiline headline, bold, how to act correct --> - <string name="risk_details_subtitle_behavior">"This is what you should do"</string> + <string name="risk_details_subtitle_behavior">"This is what you should do:"</string> <!-- XMSG: risk details - go/stay home, something like a bullet point --> <string name="risk_details_behavior_body_stay_home">"If possible, please go home and stay at home."</string> <!-- XMSG: risk details - get in touch with the corresponding people, something like a bullet point --> @@ -327,23 +327,23 @@ <!-- XHED: risk details - infection period logged information body, below behaviors --> <string name="risk_details_information_body_period_logged_assessment">"Exposure logging covers the past 14 days. During this time, the logging feature on your smartphone was active for %1$s days. The app automatically deletes older logs, as these are no longer relevant for infection prevention."</string> <!-- XHED: risk details - how your risk level was calculated, below behaviors --> - <string name="risk_details_subtitle_infection_risk_past">"This is how your risk was calculated"</string> + <string name="risk_details_subtitle_infection_risk_past">"This is how your risk was calculated."</string> <!-- XHED: risk details - how your risk level will be calculated, below behaviors --> - <string name="risk_details_subtitle_infection_risk">"This is how your risk is calculated"</string> + <string name="risk_details_subtitle_infection_risk">"This is how your risk is calculated."</string> <!-- XMSG: risk details - risk calculation wasn't possible for 24h, below behaviors --> <string name="risk_details_information_body_outdated_risk">"Your exposure logging could not be updated for more than 24 hours."</string> <!-- YTXT: risk details - low risk explanation text --> - <string name="risk_details_information_body_low_risk">"You have a low risk of infection because no exposure to people later diagnosed with COVID-19 was logged, or because your encounters were only for a short time and at a greater distance."</string> + <string name="risk_details_information_body_low_risk">"You have a low risk of infection because no exposure to people later diagnosed with coronavirus was logged, or because your encounters were only for a short time and at a greater distance."</string> <!-- YTXT: risk details - low risk explanation text with encounter with low risk --> - <string name="risk_details_information_body_low_risk_with_encounter">"The risk of infection is calculated locally on your smartphone, using exposure logging data. The calculation also takes into account distance and duration of any exposure to persons diagnosed with COVID-19, as well as their potential infectiousness. Your risk of infection cannot be seen by or passed on to anyone else."</string> + <string name="risk_details_information_body_low_risk_with_encounter">"The risk of infection is calculated locally on your smartphone, using exposure logging data. The calculation also takes into account distance and duration of any exposure to persons diagnosed with coronavirus, as well as their potential infectiousness. Your risk of infection cannot be seen by or passed on to anyone else."</string> <!-- YTXT: risk details - increased risk explanation text with variable for day(s) since last contact --> <plurals name="risk_details_information_body_increased_risk"> - <item quantity="one">"You have an increased risk of infection because you were last exposed %1$s days ago over a longer period of time and at close proximity to at least one person diagnosed with COVID-19."</item> - <item quantity="other">"You have an increased risk of infection because you were last exposed %1$s days ago over a longer period of time and at close proximity to at least one person diagnosed with COVID-19."</item> - <item quantity="zero">"You have an increased risk of infection because you were last exposed %1$s days ago over a longer period of time and at close proximity to at least one person diagnosed with COVID-19."</item> - <item quantity="two">"You have an increased risk of infection because you were last exposed %1$s days ago over a longer period of time and at close proximity to at least one person diagnosed with COVID-19."</item> - <item quantity="few">"You have an increased risk of infection because you were last exposed %1$s days ago over a longer period of time and at close proximity to at least one person diagnosed with COVID-19."</item> - <item quantity="many">"You have an increased risk of infection because you were last exposed %1$s days ago over a longer period of time and at close proximity to at least one person diagnosed with COVID-19."</item> + <item quantity="one">"You have an increased risk of infection because you were last exposed %1$s days ago over a longer period of time and at close proximity to at least one person diagnosed with coronavirus."</item> + <item quantity="other">"You have an increased risk of infection because you were last exposed %1$s days ago over a longer period of time and at close proximity to at least one person diagnosed with coronavirus."</item> + <item quantity="zero">"You have an increased risk of infection because you were last exposed %1$s days ago over a longer period of time and at close proximity to at least one person diagnosed with coronavirus."</item> + <item quantity="two">"You have an increased risk of infection because you were last exposed %1$s days ago over a longer period of time and at close proximity to at least one person diagnosed with coronavirus."</item> + <item quantity="few">"You have an increased risk of infection because you were last exposed %1$s days ago over a longer period of time and at close proximity to at least one person diagnosed with coronavirus."</item> + <item quantity="many">"You have an increased risk of infection because you were last exposed %1$s days ago over a longer period of time and at close proximity to at least one person diagnosed with coronavirus."</item> </plurals> <!-- YTXT: risk details - risk calculation explanation --> <string name="risk_details_information_body_notice">"Your risk of infection is calculated from the exposure logging data (duration and proximity) locally on your smartphone. Your risk of infection cannot be seen by, or passed on to, anyone else."</string> @@ -404,7 +404,7 @@ <!-- XHED: onboarding(together) - two/three line headline under an illustration --> <string name="onboarding_subtitle">"More protection for you and for us all. By using the Corona-Warn-App we can break infection chains much quicker."</string> <!-- YTXT: onboarding(together) - inform about the app --> - <string name="onboarding_body">"Turn your smartphone into a coronavirus warning system. Get an overview of your risk status and find out whether you\'ve had close contact with anyone diagnosed with COVID-19 in the last 14 days."</string> + <string name="onboarding_body">"Turn your smartphone into a coronavirus warning system. Get an overview of your risk status and find out whether you\'ve had close contact with anyone diagnosed with coronavirus in the last 14 days."</string> <!-- YTXT: onboarding(together) - explain application --> <string name="onboarding_body_emphasized">"The app logs encounters between individuals by exchanging encrypted, random IDs between their smartphones, whereby no personal data whatsoever is accessed."</string> <!-- XACT: onboarding(together) - illustraction description, header image --> @@ -421,9 +421,9 @@ <!-- XHED: onboarding(tracing) - how to enable tracing --> <string name="onboarding_tracing_headline">"How to Enable Exposure Logging"</string> <!-- XHED: onboarding(tracing) - two/three line headline under an illustration --> - <string name="onboarding_tracing_subtitle">"To identify whether you are at risk of infection, you must activate the exposure logging feature."</string> + <string name="onboarding_tracing_subtitle">"To identify whether you are at risk of infection, you must activate exposure logging."</string> <!-- YTXT: onboarding(tracing) - explain tracing --> - <string name="onboarding_tracing_body">"Exposure logging works by your smartphone receiving, via Bluetooth, encrypted random IDs of other users and passing your own random IDs to their smartphones. Exposure logging can be deactivated at any time. "</string> + <string name="onboarding_tracing_body">"Exposure logging works by your Android smartphone receiving, via Bluetooth, encrypted random IDs of other users and passing your own random IDs to their smartphones. Exposure logging can be deactivated at any time. "</string> <!-- YTXT: onboarding(tracing) - explain tracing --> <string name="onboarding_tracing_body_emphasized">"The encrypted random IDs only pass information about date, duration, and proximity (calculated from signal strength) to other people. Individuals cannot be identified based on the random IDs."</string> <!-- YTXT: onboarding(tracing) - easy language explain tracing link--> @@ -471,9 +471,9 @@ <!-- XBUT: onboarding(tracing) - button enable tracing --> <string name="onboarding_tracing_location_button">"Open Device Settings"</string> <!-- XACT: Onboarding (test) page title --> - <string name="onboarding_test_accessibility_title">"Onboarding page 5 of 6: If You Are Diagnosed with COVID-19"</string> + <string name="onboarding_test_accessibility_title">"Onboarding page 5 of 6: If You Are Diagnosed with Coronavirus"</string> <!-- XHED: onboarding(test) - about positive tests --> - <string name="onboarding_test_headline">"If you are diagnosed with COVID-19…"</string> + <string name="onboarding_test_headline">"If you are diagnosed with coronavirus…"</string> <!-- XHED: onboarding(test) - two/three line headline under an illustration --> <string name="onboarding_test_subtitle">"… please report this in the Corona-Warn-App. Sharing your test results is voluntary and secure. Please do this for the sake of everyone\'s health."</string> <!-- YTXT: onboarding(test) - explain test --> @@ -496,7 +496,7 @@ ###################################### --> <!-- XACT: onboarding(sixteen) title --> - <string name="sixteen_title_text">"Age Limit: 16 and Up"</string> + <string name="sixteen_title_text">"Age 16 Warning"</string> <!-- XACT: onboarding(sixteen) title --> <string name="sixteen_description_text">"The use of this app is intended for persons who are at least 16 years of age and who reside in Germany."</string> @@ -525,7 +525,7 @@ <!-- XTXT: settings(tracing) - shows status under header in home, inactive location --> <string name="settings_tracing_body_inactive_location">"Location services deactivated"</string> <!-- YTXT: settings(tracing) - explains tracings --> - <string name="settings_tracing_body_text">"You need to enable the exposure logging feature so that the app can determine whether you are at risk after encountering an infected app user. The exposure logging feature works transnationally, meaning any possible exposure involving users is also detected by other official coronavirus apps.\n\nThe exposure logging feature works by your smartphone receiving encrypted random IDs from other users via Bluetooth and passing your own random IDs to their smartphones. Every day, the app downloads a list containing the random IDs – along with any voluntary information about the onset of symptoms – of all users who have tested positive for the virus and voluntarily shared this information via their app. This list is then compared with the random IDs of other users that have been recorded by your smartphone, in order to calculate the likelihood that you have also been infected and to warn you if necessary. You can use the toggle switch to disable exposure logging at any time.\n\nThe app never collects personal data such as your name, address or location, nor is this information passed on to other users. It is not possible to use random IDs to draw conclusions about individual persons."</string> + <string name="settings_tracing_body_text">"You need to enable the exposure logging feature so that the app can determine whether you are at risk after encountering an infected app user. The exposure logging feature works transnationally, meaning any possible exposure involving users is also detected by other official coronavirus apps.\n\nThe exposure logging feature works by your Android smartphone receiving encrypted random IDs from other users via Bluetooth and passing your own random IDs to their smartphones. Every day, the app downloads a list containing the random IDs – along with any voluntary information about the onset of symptoms – of all users who have tested positive for the virus and voluntarily shared this information (specifically: their random IDs) via their app. This list is then compared with the random IDs of other users you have encountered that have been recorded by your Android smartphone, in order to calculate the likelihood that you have also been infected and to warn you if necessary. You can use the toggle switch to disable exposure logging at any time.\n\nThe app never collects personal data such as your name, address or location, nor is this information passed on to other users. It is not possible to use random IDs to draw conclusions about individual persons."</string> <!-- XTXT: settings(tracing) - status next to switch under title --> <string name="settings_tracing_status_active">"Active"</string> <!-- XTXT: settings(tracing) - status next to switch under title --> @@ -595,7 +595,7 @@ <!-- XTXT: settings(notification) - next to a switch --> <string name="settings_notifications_subtitle_update_risk">"Your risk of infection changed"</string> <!-- XTXT: settings(notification) - next to a switch --> - <string name="settings_notifications_subtitle_update_test">"Status of your COVID-19 test"</string> + <string name="settings_notifications_subtitle_update_test">"Status of your coronavirus test"</string> <!-- XBUT: settings(notification) - go to operating settings --> <string name="settings_notifications_button_open_settings">"Open Device Settings"</string> <!-- XACT: main (overview) - illustraction description, explanation image, displays notificatin status, active --> @@ -604,7 +604,7 @@ <string name="settings_notifications_illustration_description_inactive">"A woman has deactivated notifications for her Corona-Warn-App."</string> <!-- XBUT: settings - go to reset application --> <string name="settings_reset_title">"Reset App"</string> - <!-- XTXT: settings(reset) - explains the user what do expect when he navigates to reset --> + <!-- XTXT: settings(reset) - explains the user what do expect when navigating to reset --> <string name="settings_reset_body_description">"Delete all your data in the app."</string> <!-- XHED: settings(reset) - multiline headline below illustration --> <string name="settings_reset_headline">"Are you sure you want to reset the app?"</string> @@ -660,7 +660,7 @@ <!-- YTXT: Body text for about information page --> <string name="information_about_body_emphasized">"Robert Koch Institute (RKI) is Germany’s federal public health body. The RKI publishes the Corona-Warn-App on behalf of the Federal Government. The app is intended as a digital complement to public health measures already introduced: social distancing, hygiene, and face masks."</string> <!-- YTXT: Body text for about information page --> - <string name="information_about_body">"People who use the app help to trace and break chains of infection. The app saves encounters with other people locally on your device. You are notified if you have encountered people who were later diagnosed with COVID-19. Your identity and privacy are always protected."</string> + <string name="information_about_body">"People who use the app help to trace and break chains of infection. The app saves encounters with other people locally on your device. You are notified if you have encountered people who were later diagnosed with coronavirus. Your identity and privacy are always protected."</string> <!-- XACT: describes illustration --> <string name="information_about_illustration_description">"A group of persons use their smartphones around town."</string> <!-- XHED: Page title for privacy information page, also menu item / button text --> @@ -754,7 +754,7 @@ <!-- XHED: Dialog title for already paired test error: qr --> <string name="submission_error_dialog_web_test_paired_title">"QR code is invalid"</string> <!-- XMSG: Dialog body for already paired test error: qr --> - <string name="submission_error_dialog_web_test_paired_body">"The QR code is invalid or has been registered on another smartphone already. You will receive your test result from the test center or laboratory regardless of the validity of the QR code. If you are diagnosed with COVID-19, you will be notified by the public health authority."</string> + <string name="submission_error_dialog_web_test_paired_body">"The QR code is invalid or has been registered on another smartphone already. You will receive your test result from the test center or laboratory regardless of the validity of the QR code. If you are diagnosed with coronavirus, you will be notified by the public health authority."</string> <!-- XHED: Dialog title for already paired test error: tan --> <string name="submission_error_dialog_web_test_paired_title_tan">"TAN is invalid"</string> <!-- XMSG: Dialog body for already paired test via tan - error: tan --> @@ -784,9 +784,9 @@ <string name="submission_error_dialog_web_tan_redeemed_button_positive">"OK"</string> <!-- XHED: Dialog title for keys submission process cancellation --> - <string name="submission_error_dialog_confirm_cancellation_title">"Do you want to cancel?"</string> + <string name="submission_error_dialog_confirm_cancellation_title">"Do you want to cancel entering your symptoms?"</string> <!-- XMSG: Dialog body for keys submission process cancellation --> - <string name="submission_error_dialog_confirm_cancellation_body">"Your entries will not be saved."</string> + <string name="submission_error_dialog_confirm_cancellation_body">"If you provide information about your symptoms, you can warn others more exactly."</string> <!-- XBUT: Positive button for keys submission process cancellation --> <string name="submission_error_dialog_confirm_cancellation_button_positive">"Yes"</string> <!-- XBUT: Negative button for keys submission process cancellation --> @@ -814,7 +814,7 @@ <!-- XHED: Dialog headline for invalid QR code --> <string name="submission_qr_code_scan_invalid_dialog_headline">"QR code is invalid"</string> <!-- YTXT: Dialog Body text for invalid QR code --> - <string name="submission_qr_code_scan_invalid_dialog_body">"The QR code is invalid or has been registered on another smartphone already. You will receive your test result from the test center or laboratory regardless of the validity of the QR code. If you are diagnosed with COVID-19, the public health authority will be notified through the legally prescribed channel and will contact you."</string> + <string name="submission_qr_code_scan_invalid_dialog_body">"The QR code is invalid or has been registered on another smartphone already. You will receive your test result from the test center or laboratory regardless of the validity of the QR code. If you are diagnosed with coronavirus, the public health authority will be notified through the legally prescribed channel and will contact you."</string> <!-- XBUT: Dialog(Invalid QR code) - positive button (right) --> <string name="submission_qr_code_scan_invalid_dialog_button_positive">"Please try again."</string> <!-- XBUT: Dialog(Invalid QR code) - negative button (left) --> @@ -825,6 +825,34 @@ <!-- YTXT: instruction text for QR code scanning --> <string name="submission_qr_code_scan_body">"Position the QR code in the frame."</string> + <!-- QR Code Consent Screen --> + <!-- XHED: Page headline for Submission consent --> + <string name="submission_consent_main_headline">"Your Consent"</string> + <!-- YTXT: Body for Submissionconsent --> + <string name="submission_consent_main_headline_body">"Your consent is needed before you can retrieve your test result and warn others."</string> + <!-- XHED: Page subheadline for consent call test result --> + <string name="submission_consent_call_test_result">"Retrieve Test Result"</string> + <!-- YTXT: Body for Submission Consent call test result body --> + <string name="submission_consent_call_test_result_body">"In the next step, scan the QR code on your test and retrieve your test result."</string> + <!-- YTXT: Body sub text 1 for Submission Consent call test result --> + <string name="submission_consent_call_test_result_scan_your_test_only">"Only scan your own test."</string> + <!-- YTXT: Body sub text 2 for Submission Consent call test result --> + <string name="submission_consent_call_test_result_scan_test_only_once">"Your test can only be scanned once. The app cannot manage multiple tests at the same time."</string> + <!-- XHED: Page subheadline for consent help by warning others --> + <string name="submission_consent_help_by_warning_others_headline">"Please help others you have encountered by warning them!"</string> + <!-- YTXT: Body for consent help by warning others --> + <string name="submission_consent_help_by_warning_others_body">"If you have been diagnosed with coronavirus, you can warn others through the app. The warning function works in several countries. The following countries are currently participating:"</string> + <!-- YTXT: Page bottom text for consent screen --> + <string name="submission_consent_main_bottom_body">"Detailed Information on Data Processing and Your Consent"</string> + <!-- YTXT: Body for consent main section first point --> + <string name="submission_consent_main_first_point">"Your consent is voluntary."</string> + <!-- YTXT: Body for consent main section second point --> + <string name="submission_consent_main_second_point">"You can retrieve your test result even if you do not choose to share it. But if you share your test result, you will help to protect others against infection."</string> + <!-- YTXT: Body for consent main section third point --> + <string name="submission_consent_main_third_point">"Your identity will remain secret. Other users will not know who shared their test results."</string> + <!-- YTXT: Body for consent main section fourth point --> + <string name="submission_consent_main_fourth_point">"You must be at least 16 years old to grant your consent."</string> + <!-- Submission Test Result --> <!-- XHED: Page headline for test result --> <string name="submission_test_result_headline">"Test Result"</string> @@ -835,9 +863,9 @@ <!-- YTXT: Body text for for results next steps --> <string name="submission_test_result_steps_added_body">"Your test has been stored in the Corona-Warn-App."</string> <!-- XHED: Page headline for pending test result next steps --> - <string name="submission_test_result_pending_steps_waiting_heading">"Test result is not yet available"</string> + <string name="submission_test_result_pending_steps_waiting_heading">"Your test result is not available yet."</string> <!-- YTXT: Body text for next steps section of waiting test result page --> - <string name="submission_test_result_pending_steps_waiting_body">"Please be patient, as the evaluation may take several days.\n\nYou will also receive your test result outside of the app. The public health authorities will notify you, should your test be positive.\n\nIn the event of a positive test result, please call the number shown under \"Request TAN\" to register your result in the app and warn others."</string> + <string name="submission_test_result_pending_steps_waiting_body">"As soon as your test result becomes available, it will be displayed in the app."</string> <!-- XBUT: test result pending : refresh button --> <string name="submission_test_result_pending_refresh_button">"Update"</string> <!-- XBUT: test result pending : remove the test button --> @@ -845,7 +873,7 @@ <!-- XHED: Page headline for negative test result next steps --> <string name="submission_test_result_negative_steps_negative_heading">"Your Test Result"</string> <!-- YTXT: Body text for next steps section of test negative result --> - <string name="submission_test_result_negative_steps_negative_body">"The laboratory result indicates no verification that you have coronavirus SARS-CoV-2.\n\nPlease delete the test from the Corona-Warn-App, so that you can save a new test code here if necessary."</string> + <string name="submission_test_result_negative_steps_negative_body">"The laboratory result indicates no verification that you have the SARS-CoV-2 coronavirus.\n\nPlease delete the test from the Corona-Warn-App, so that you can save a new test code here if necessary."</string> <!-- XBUT: negative test result : remove the test button --> <string name="submission_test_result_negative_remove_test_button">"Delete Test"</string> <!-- XHED: Page headline for other warnings screen --> @@ -873,7 +901,7 @@ <!-- XHED: Dialog title for test removal --> <string name="submission_test_result_dialog_remove_test_title">"The test can only be scanned once."</string> <!-- YTXT: Dialog text for test removal --> - <string name="submission_test_result_dialog_remove_test_message">"If you remove the test, you can no longer retrieve your test result. You will receive your test result from the test center or laboratory regardless of the validity of the QR code. If you are diagnosed with COVID-19, the public health authority will be notified through the legally prescribed channel and will contact you."</string> + <string name="submission_test_result_dialog_remove_test_message">"If you remove the test, you can no longer retrieve your test result. You will receive your test result from the test center or laboratory regardless of the validity of the QR code. If you are diagnosed with coronavirus, the public health authority will be notified through the legally prescribed channel and will contact you."</string> <!-- XBUT: Positive button for test removal --> <string name="submission_test_result_dialog_remove_test_button_positive">"Remove"</string> <!-- XBUT: Negative button for test removal --> @@ -882,6 +910,16 @@ <string name="submission_test_result_card_positive_title">"SARS-CoV-2 positive"</string> <!-- YTXT: Body text for test result card positive --> <string name="submission_test_result_card_positive_body">"You have been diagnosed with the SARS-CoV-2 virus."</string> + <!-- XHED: Page headline for test result with consent given --> + <string name="submission_test_result_consent_given_heading">"Your Test Result"</string> + <!-- XHED: Subtitle text for test result card with consent given --> + <string name="submission_test_result_consent_given_subtitle">"Thank you for helping to stop the spread of coronavirus."</string> + <!-- YTXT: body text for test result card with consent given --> + <string name="submission_test_result_consent_given_body"><b>"Others you have had contact with will now be warned."</b>" "<br/><br/>"You can now help to improve the accuracy of the warnings. To do so, in the next step, tell us when you first developed symptoms. You can cancel this step at any time."</string> + <!-- XBUT: button text for the 'break up' button option on test result consent given page --> + <string name="submission_test_result_consent_given_breakup_button">"Exit"</string> + + <!-- Submission Tan --> <!-- XHED: Page title for TAN submission pge --> @@ -903,7 +941,7 @@ <!-- XHED: Page headline for menu the at start of the submission process --> <string name="submission_intro_headline">"This is how the Corona-Warn-App works"</string> <!-- YTXT: submission introduction text --> - <string name="submission_intro_text">"For the app to work well, we are relying on the support of people who were diagnosed with COVID-19.\n\nSince only encrypted random IDs are exchanged, you will remain anonymous. You can now proceed as follows:"</string> + <string name="submission_intro_text">"For the app to work well, we are relying on the support of people who were diagnosed with coronavirus.\n\nSince only encrypted random IDs are exchanged, you will remain anonymous. You can now proceed as follows:"</string> <!-- XBUT: Submission introduction next button--> <string name="submission_intro_button_next">"Next"</string> <!-- XACT: Submission intro - illustration description, explanation image --> @@ -911,7 +949,7 @@ <!-- YTXT: submission introduction bullet points --> <string-array name="submission_intro_bullet_points"> <item>"If there is a QR code in your test document, you can scan this and register the test. As soon as the result is available, you can view it in the app."</item> - <item>"If you have been diagnosed with COVID-19, you can warn others."</item> + <item>"If you have been diagnosed with coronavirus, you can warn others."</item> <item>"If you were given a TAN for a positive diagnosis, you can use this to register the test."</item> <item>"If you do not have a TAN, you can request one by telephone."</item> </string-array> @@ -920,25 +958,25 @@ <!-- Dispatcher --> <!-- XHED: Page headline for dispatcher menu --> - <string name="submission_dispatcher_headline">"Selection"</string> + <string name="submission_dispatcher_headline">"Retrieve Test Result"</string> <!-- XHED: Page subheadline for dispatcher menu --> - <string name="submission_dispatcher_subheadline">"What information do you have?"</string> + <string name="submission_dispatcher_subheadline">"Retrieve your test result through the app and then warn others. You’ll protect yourself and help to stop the spread of coronavirus."</string> <!-- XHED: Page subheadline for dispatcher options asking if they have already been tested: QR and TAN --> - <string name="submission_dispatcher_needs_testing_subheadline">""</string> + <string name="submission_dispatcher_needs_testing_subheadline">"Have you been tested?"</string> <!-- XHED: Page subheadline for dispatcher options asking if they already have a positive test: tele-TAN --> - <string name="submission_dispatcher_already_positive_subheadline">""</string> + <string name="submission_dispatcher_already_positive_subheadline">"Did you test positive for coronavirus?"</string> <!-- YTXT: Dispatcher text for QR code option --> - <string name="submission_dispatcher_card_qr">"Document with QR code"</string> + <string name="submission_dispatcher_card_qr">"Test with QR Code"</string> <!-- YTXT: Body text for QR code dispatcher option --> <string name="submission_dispatcher_qr_card_text">"Register your test by scanning the QR code of your test document."</string> <!-- YTXT: Dispatcher text for TAN code option --> - <string name="submission_dispatcher_card_tan_code">"TAN"</string> + <string name="submission_dispatcher_card_tan_code">"TAN Entry"</string> <!-- YTXT: Body text for TAN code dispatcher option --> - <string name="submission_dispatcher_tan_code_card_text">"Register your test by entering your TAN manually."</string> + <string name="submission_dispatcher_tan_code_card_text">"Do you have a TAN? Continue to enter your TAN, so you can warn others. "</string> <!-- YTXT: Dispatcher text for TELE-TAN option --> - <string name="submission_dispatcher_card_tan_tele">"Request TAN"</string> + <string name="submission_dispatcher_card_tan_tele">"No TAN yet?"</string> <!-- YTXT: Body text for TELE_TAN dispatcher option --> - <string name="submission_dispatcher_tan_tele_card_text">"Please call us if you have been diagnosed with COVID-19."</string> + <string name="submission_dispatcher_tan_tele_card_text">"Call us and get a TAN."</string> <!-- XACT: Dispatcher Tan page title --> <string name="submission_dispatcher_accessibility_title">"What information do you have?"</string> @@ -956,6 +994,25 @@ <!-- XHED: Title for the interop country list--> <string name="submission_interoperability_list_title">"The following countries currently participate in transnational exposure logging:"</string> + <!-- Submission Positive Other Warning No Consent --> + <!-- YTXT: Body text for the positive result additional warning page--> + <string name="submission_positive_other_warning_no_consent_body_first_part">"Because you tested positive for coronavirus, you can now warn others through the app."</string> + <!-- YTXT: Body text for the positive result additional warning page--> + <string name="submission_positive_other_warning_no_consent_body_second_part">"The warning function works in several countries. The following countries are currently participating:"</string> + + + <!-- Test result positive and no consent given --> + <!-- XHED: Title for test result positive and no consent given--> + <string name="submission_test_result_positive_no_consent_subtitle">"Please help all of us!"</string> + <!-- XTXT: First bullet point when test result is positive and consent is requested for key sharing--> + <string name="submission_test_result_positive_no_consent_text_1"><b>"Share your test result and help protect others against infection."</b></string> + <!-- XTXT: Second bullet point when test result is positive and consent is requested for key sharing--> + <string name="submission_test_result_positive_no_consent_text_2">"Your identity will remain secret. Other users will not know who shared their test results."</string> + <!-- XTXT: Third bullet point when test result is positive and consent is requested for key sharing--> + <string name="submission_test_result_positive_no_consent_text_3">"Please be sure to follow the instructions from your public health authority and stay home, so you don’t infect others."</string> + <!-- XBUT: Button for giving consent for key sharing --> + <string name="submission_test_result_positive_no_consent_button_warn_others">"Warn Others"</string> + <!-- Submission Country Selector --> <!-- XHED: Page title for the submission country selection page --> <string name="submission_positive_country_selection_title">"Europe-wide warnings"</string> @@ -995,13 +1052,29 @@ <!-- XACT: submission finished - illustration description, explanation image --> <string name="submission_done_illustration_description">"Have you experienced one or more of the following symptoms in the past few days?"</string> + <!-- Submission Done No Consent--> + <!-- XHED: Page title for completed submission page --> + <string name="submission_done_no_consent_title">"Thank you"</string> + <!-- YTXT: Page subtitle for completed submission page --> + <string name="submission_done_no_consent_subtitle">"Thank you for helping to stop the spread of coronavirus."</string> + <!-- YTXT: Page body for submission no consent page --> + <string name="submission_done_no_consent_body_title">"Others will now be warned."</string> + <!-- YTXT: Page body for submission no consent page --> + <string name="submission_done_no_consent_body">"You can now help to improve the accuracy of the warnings. To do so, in the next step, tell us when you first developed symptoms. You can cancel this step at any time."</string> + <!-- XBUT: submission continue with symptom recording button --> + <string name="submission_done_no_consent_continue_with_symptom_recording">"Enter Symptoms"</string> + <!-- XBUT: submission continue break flow button--> + <string name="submission_done_no_consent_break_flow">"Exit"</string> + <!-- XACT: submission finished - illustration description, explanation image --> + <string name="submission_done_no_consent_illustration_description">"Several people are looking at their smartphones."</string> + <!-- Submission Symptoms --> <!-- XHED: Page title for symptom screens --> <string name="submission_symptom_title">"Symptoms"</string> <!-- XTXT: headline text for initial symptom screen --> - <string name="submission_symptom_initial_headline">"Have you experienced one or more of the following symptoms?"</string> + <string name="submission_symptom_initial_headline">"Have you experienced one or more of the following symptoms in the last few days?"</string> <!-- YTXT: explanation text for initial symptom screen --> - <string name="submission_symptom_initial_explanation">"You can indicate whether and when you noticed any corona symptoms, to allow the App to calculate more accurately the risk of infection to other app users. If you do not want to provide that information, just select \"no answer\"."</string> + <string name="submission_symptom_initial_explanation">"You can indicate whether and when you noticed any corona symptoms, to allow the App to calculate more accurately the risk of infection to other app users. This step is voluntary. If you do not want to provide information about your symptoms, select “No answerâ€."</string> <!-- YTXT: Bullet points for symptoms --> <string-array name="submission_symptom_symptom_bullets"> <item>"Increased temperature or fever"</item> @@ -1058,9 +1131,9 @@ <!-- XHED: Page title for calendar page in submission symptom flow --> <string name="submission_symptom_calendar_title">"Start of Symptoms"</string> <!-- XHED: Page headline for calendar page in symptom submission flow --> - <string name="submission_symptom_calendar_headline">"When did you first start to experience these symptoms? "</string> + <string name="submission_symptom_calendar_headline">"When did you first notice the symptoms?"</string> <!-- YTXT: Body text for calendar page in symptom submission flow--> - <string name="submission_symptom_calendar_body">"Select the exact date in the calendar or, if you cannot remember the exact date, choose one of the other options."</string> + <string name="submission_symptom_calendar_body">"Please specify the date as accurately as possible."</string> <!-- XBUT: symptom calendar screen less than 7 days button --> <string name="submission_symptom_less_seven">"In the last 7 days"</string> <!-- XBUT: symptom calendar screen 1-2 weeks button --> @@ -1072,13 +1145,13 @@ <!-- Submission Status Card --> <!-- XHED: Page title for the various submission status: fetching --> - <string name="submission_status_card_title_fetching">"Data being retrieved...."</string> + <string name="submission_status_card_title_fetching">"Data being retrieved..."</string> <!-- XHED: Page title for the various submission status: unregistered --> <string name="submission_status_card_title_unregistered">"Have you been tested?"</string> <!-- XHED: Page title for the various submission status: pending --> - <string name="submission_status_card_title_pending">"Your result is not yet available"</string> + <string name="submission_status_card_title_pending">"Your test result is not available yet"</string> <!-- XHED: Page title for the various submission status: available --> - <string name="submission_status_card_title_available">"Your result is available"</string> + <string name="submission_status_card_title_available">"Your test result is available"</string> <!-- XHED: Page title for the various submission status: positive --> <string name="submission_status_card_title_positive">"Positive Diagnosis"</string> <!-- XHED: Page title for the various submission status fetch failed --> @@ -1090,7 +1163,7 @@ <!-- YTXT: Body text for submission status: fetching --> <string name="submission_status_card_body_fetching">"You result is being updated"</string> <!-- YTXT: Body text for submission status: unregistered --> - <string name="submission_status_card_body_unregistered">"Help to break the infection chain by notifying others."</string> + <string name="submission_status_card_body_unregistered">"Help protect yourself and others."</string> <!-- YTXT: Body text for submission status: pending --> <string name="submission_status_card_body_pending">"The evaluation of your test is not yet done."</string> <!-- YTXT: Body text for submission status: invalid --> @@ -1102,7 +1175,7 @@ <!-- YTXT: Body text for submission status fetch failed --> <string name="submission_status_card_body_failed">"Your test is more than 21 days old and is therefore no longer relevant. Please delete the test. You can then add another."</string> <!-- XBUT: submission status card unregistered button --> - <string name="submission_status_card_button_unregistered">"Learn More and Help"</string> + <string name="submission_status_card_button_unregistered">"Next Steps"</string> <!-- XBUT: submission status card show results button --> <string name="submission_status_card_button_show_results">"Display Test"</string> <!-- XBUT: submission status card fetch failed button --> @@ -1140,7 +1213,51 @@ </string-array> <!-- XBUT Symptoms exact date button --> - <string name="symptoms_calendar_exact_date_button">"Exact date"</string> + <string name="symptoms_calendar_exact_date_button">"Date"</string> + + <!-- Submission consent custom view --> + <!-- XHED: Title for consent given --> + <string name="submission_consent_view_consent_given">"Consent\n“Warn others†granted"</string> + <!-- XHED: Title for consent NOT given --> + <string name="submission_consent_view_consent_not_given">"Consent\n“Warn others†not granted"</string> + + <!-- Submission test result available --> + <!-- XHED: Page title for test results available step --> + <string name="submission_test_result_available_title">"Your Test Result Is Available"</string> + <!-- XACT: Test result available illustration description --> + <string name="submission_test_result_available_illustration_description">"A woman holds her smartphone in her hand. It is sending a signal to another smartphone."</string> + <!-- YTXT: Text for consent given --> + <string name="submission_test_result_available_text_consent_given">"Thank you for agreeing to share your test result and helping to warn others as a result. \n\n"<b>"In the next step, please share your test result by tapping “Shareâ€."</b></string> + <!-- XHED: Close screen popup title for consent given --> + <string name="submission_test_result_available_close_dialog_title_consent_given">"Do you want to cancel?"</string> + <!-- XTXT: Close screen popup text for consent given --> + <string name="submission_test_result_available_close_dialog_body_consent_given">"Your entries will not be saved."</string> + <!-- YTXT: Text for consent NOT given --> + <string name="submission_test_result_available_text_consent_not_given">"You have chosen to not share your test results. Others will not be warned. \n\nIn the next step, you have the opportunity to change your mind and share your test result after all, to help stop the spread of coronavirus and protect others."</string> + <!-- XHED: Close screen popup title for consent NOT given --> + <string name="submission_test_result_available_close_dialog_title_consent_not_given">"Important:\nYou are about to cancel this process.\nYou have not warned others yet. Please complete the process and help to protect others."</string> + <!-- XTXT: Close screen popup text for consent NOT given --> + <string name="submission_test_result_available_close_dialog_body_consent_not_given">"Do you really want to cancel the process?"</string> + <!-- XBUT: Close screen popup cancel button --> + <string name="submission_test_result_available_close_dialog_cancel_button">"Cancel"</string> + <!-- XBUT: Close screen popup continue button --> + <string name="submission_test_result_available_close_dialog_continue_button">"Continue"</string> + + <!-- Submission your consent screen --> + <!-- XHED: Your consent screen title --> + <string name="submission_your_consent_title">"Your Consent"</string> + <!-- XTXT: Your consent screen switch label - next to a switch --> + <string name="submission_your_consent_switch_subtitle">"Warn Others"</string> + <!-- XTXT: Your consent screen switch status on --> + <string name="submission_your_consent_switch_status_on">"Active"</string> + <!-- XTXT: Your consent screen switch status off --> + <string name="submission_your_consent_switch_status_off">"Stopped"</string> + <!-- XTXT: Your consent screen about agreement --> + <string name="submission_your_consent_about_agreement">"You have granted the following consent:"</string> + <!-- XHED: Your consent screen agreement title --> + <string name="submission_your_consent_agreement_title"><b>"Consent"</b></string> + <!-- XTXT: Your consent screen detailed information --> + <string name="submission_your_consent_agreement_details">"Detailed Information on Data Processing and Your Consent"</string> <!-- #################################### Button Tooltips for Accessibility @@ -1215,8 +1332,6 @@ <!-- NOTR --> <string name="test_api_button_show_qr_code">"Show QR Code"</string> <!-- NOTR --> - <string name="test_api_button_submit_keys">"Submit keys to Server"</string> - <!-- NOTR --> <string name="test_api_button_scan_qr_code">"Scan Exposure Key"</string> <!-- NOTR --> <string name="test_api_switch_last_three_hours_from_server">"Last 3 Hours Mode"</string> @@ -1309,7 +1424,7 @@ <!-- XTXT: First section after the header of the interoperability information/configuration view --> <string name="interoperability_configuration_first_section">"Several countries are working together to enable transnational alerts via a joint exchange server. For example, contacts with users of an official coronavirus app from other participating countries can also be taken into account for exposure logging."</string> <!-- XTXT: Second section after the header of the interoperability information/configuration view --> - <string name="interoperability_configuration_second_section">"To do this, the app downloads a list, which is updated daily, of the random IDs of all users who have shared their random IDs via their own app. This list is then compared with the random IDs recorded by your smartphone. The daily download of the list with the random IDs is usually free of charge for you – you will not be charged for the data used by the app in this context, will roaming charges apply for this in other EU countries."</string> + <string name="interoperability_configuration_second_section">"To do this, the app downloads a list, which is updated daily, of the random IDs of all users who have shared their test results to warn others via their own app. This list is then compared with the random IDs recorded by your Android smartphone. The list downloads are usually free of charge for you. Specifically, this means that mobile network operators do not charge you for the data used by the app in this context, nor do they apply roaming charges for this in other EU countries. Please contact your mobile network operator for more information."</string> <!-- XHED: Header right above the country list in the interoperability information/configuration view --> <string name="interoperability_configuration_list_title">"The following countries currently participate in transnational exposure logging:"</string> <!-- XTXT: Text right under the country list in the interoperability information/configuration view --> @@ -1320,9 +1435,9 @@ <!-- YMSG: Onboarding tracing step first section in interoperability after the title --> <string name="interoperability_onboarding_first_section">"Several countries have teamed up to enable transnational warnings. In other words, your potential exposure to users of the official corona apps in all participating countries can now be taken into account."</string> <!-- YMSG: Onboarding tracing step second section in interoperability after the title --> - <string name="interoperability_onboarding_second_section">"When a user submits their random IDs to the exchange server jointly operated by the participating countries, users of the official corona apps in all these countries can be warned of potential exposure."</string> + <string name="interoperability_onboarding_second_section">"When a user submits their positive test result (more specifically: their random IDs) to warn others through the exchange server jointly operated by the participating countries, all users of the official corona apps in all these countries can be warned of their potential exposure."</string> <!-- YMSG: Onboarding tracing step third section in interoperability after the title. --> - <string name="interoperability_onboarding_randomid_download_free">"The daily download of the list with the random IDs is usually free of charge for you. Specifically, this means that mobile network operators do not charge you for the data used by the app in this context, nor do they apply roaming charges for this in other EU countries. Please contact your mobile network operator for more information."</string> + <string name="interoperability_onboarding_randomid_download_free">"The daily downloads of lists of random IDs from users who have shared positive test results are usually free of charge for you. Specifically, this means that mobile network operators do not charge you for the data used by the app in this context, nor do they apply roaming charges for this in other EU countries. Please contact your mobile network operator for more information."</string> <!-- XTXT: Small header above the country list in the onboarding screen for interoperability. --> <string name="interoperability_onboarding_list_title">"The following countries currently participate:"</string> @@ -1337,9 +1452,9 @@ <!-- XTXT: Description of the interoperability extension of the app. Below interoperability_onboarding_delta_title --> <string name="interoperability_onboarding_delta_subtitle">"The features of the Corona-Warn-App have been enhanced. Many countries have joined up to enable international warnings, based on a jointly-operated exchange server. Exposure to users of official corona apps in other participating countries can now be taken into account when calculating your exposure risk."</string> <!-- YMSG: Onboarding tracing step third section in interoperability after the title. --> - <string name="interoperability_onboarding_delta_randomid">"To do this, the app downloads a list, which is updated daily, of the random IDs of all users who have shared their random IDs via their own app. This list is then compared with the random IDs recorded by your device."</string> + <string name="interoperability_onboarding_delta_randomid">"To do this, the app downloads a list, which is updated daily, of the random IDs of all users who have shared their test results to warn others via their own app. This list is then compared with the random IDs recorded by your Android smartphone."</string> <!-- YMSG: Onboarding tracing step third section in interoperability after the title. --> - <string name="interoperability_onboarding_delta_free_download">"The daily download of the list with the random IDs is usually free of charge for you. Specifically, this means that mobile network operators do not charge you for the data used by the app in this context, nor do they apply roaming charges for this in other EU countries. Please contact your mobile network operator for more information."</string> + <string name="interoperability_onboarding_delta_free_download">"The list downloads are usually free of charge for you. Specifically, this means that mobile network operators do not charge you for the data used by the app in this context, nor do they apply roaming charges for this in other EU countries. Please contact your mobile network operator for more information."</string> <!-- XACT: interoperability (eu) - illustraction description, explanation image --> <string name="interoperability_eu_illustration_description">"A hand holds a smartphone. Europe and the European flag are illustrated in the background."</string> @@ -1356,4 +1471,15 @@ <!-- XBUT: Title for the interoperability onboarding Settings-Button if no network is available --> <string name="interoperability_onboarding_list_button_title_no_network">"Open Device Settings"</string> -</resources> + <!-- XHED: Title for the dialog on test result positive no consent screen --> + <string name="submission_test_result_positive_no_consent_dialog_title">"Don’t you want to send a warning?"</string> + <!-- XTXT: Message for the dialog on test result positive no consent screen --> + <string name="submission_test_result_positive_no_consent_dialog_message">"You have to share your test result if you want to warn others."</string> + <!-- XBUT: Positive button for the dialog on test result positive no consent screen --> + <string name="submission_test_result_positive_no_consent_dialog_positive_button">"Warn others"</string> + <!-- XBUT: Negative button for the dialog on test result positive no consent screen --> + <string name="submission_test_result_positive_no_consent_dialog_negative_button">"Do not warn others"</string> + <!-- XBUT: Abort button for test result positive no consent screen --> + <string name="submission_test_result_positive_no_consent_button_abort">"Cancel"</string> + +</resources> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/values-pl/strings.xml b/Corona-Warn-App/src/main/res/values-pl/strings.xml index ef18e2c574040ff1b6ca17f5e68193dd03d0598c..ef490af341f9384344a40282f2626aab75451227 100644 --- a/Corona-Warn-App/src/main/res/values-pl/strings.xml +++ b/Corona-Warn-App/src/main/res/values-pl/strings.xml @@ -162,7 +162,7 @@ <string name="risk_card_low_risk_no_encounters_body">"Brak narażenia do tej pory"</string> <!-- XTXT: risk card - Low risk state - Days with low risk encounters --> <plurals name="risk_card_low_risk_encounter_days_body"> - <item quantity="one">"Narażenia z niskim ryzykiem w ciÄ…gu %1$d dni"</item> + <item quantity="one">"Narażenia z niskim ryzykiem w ciÄ…gu jednego dnia"</item> <item quantity="other">"Narażenia z niskim ryzykiem w ciÄ…gu %1$d dnia"</item> <item quantity="zero">"Narażenia z niskim ryzykiem w ciÄ…gu %1$d dni"</item> <item quantity="two">"Narażenia z niskim ryzykiem w ciÄ…gu %1$d dni"</item> @@ -174,7 +174,7 @@ <string name="risk_card_high_risk_no_encounters_body">"Brak narażenia do tej pory"</string> <!-- XTXT: risk card - High risk state - Days with high risk encounters --> <plurals name="risk_card_high_risk_encounter_days_body"> - <item quantity="one">"Narażenia w ciÄ…gu %1$d dnia z podwyższonym ryzykiem"</item> + <item quantity="one">"Narażenia w ciÄ…gu jednego dnia z podwyższonym ryzykiem"</item> <item quantity="other">"Narażenia w ciÄ…gu %1$d dnia z podwyższonym ryzykiem"</item> <item quantity="zero">"Narażenia w ciÄ…gu %1$d dni z podwyższonym ryzykiem"</item> <item quantity="two">"Narażenia w ciÄ…gu %1$d dni z podwyższonym ryzykiem"</item> @@ -242,7 +242,7 @@ <!-- XHED: App overview subtitle for risk explanation --> <string name="main_overview_subtitle_risk">"Ryzyko zakażenia"</string> <!-- YTXT: App overview body text about risk levels --> - <string name="main_overview_body_risk">"JeÅ›li w ciÄ…gu ostatnich 14 dni miaÅ‚eÅ›(-aÅ›) kontakt z osobÄ…, u której zdiagnozowano COVID-19, aplikacja oblicza Twoje osobiste ryzyko zakażenia poprzez pomiar czasu trwania i bliskoÅ›ci kontaktu."</string> + <string name="main_overview_body_risk">"JeÅ›li w ciÄ…gu ostatnich 14 dni miaÅ‚eÅ›(-aÅ›) kontakt z osobÄ…, u której zdiagnozowano koronawirusa, aplikacja oblicza Twoje osobiste ryzyko zakażenia poprzez pomiar czasu trwania i bliskoÅ›ci kontaktu."</string> <!-- XHED: App overview subtitle for risk level list --> <string name="main_overview_subtitle_risk_levels">"Może wyÅ›wietlić siÄ™ nastÄ™pujÄ…cy status ryzyka:"</string> <!-- XTXT: App overview increased risk level --> @@ -254,7 +254,7 @@ <!-- XHED: App overview subtitle for test procedure explanation --> <string name="main_overview_headline_test">"Powiadamianie innych użytkowników"</string> <!-- YTXT: App overview body text about rest procedure --> - <string name="main_overview_body_test">"InnÄ… kluczowÄ… funkcjÄ… jest rejestracja testu i pobranie wyniku. W przypadku zdiagnozowania u Ciebie COVID-19 bÄ™dziesz mieć możliwość powiadomienia innych i przerwania Å‚aÅ„cucha zakażeÅ„."</string> + <string name="main_overview_body_test">"InnÄ… kluczowÄ… funkcjÄ… jest rejestracja testu i pobranie wyniku. W przypadku zdiagnozowania u Ciebie koronawirusa bÄ™dziesz mieć możliwość powiadomienia innych i przerwania Å‚aÅ„cucha zakażeÅ„."</string> <!-- XHED: App overview headline for glossary --> <string name="main_overview_headline_glossary">"Definicja terminów:"</string> <!-- XHED: App overview subtitle for glossary key storage --> @@ -276,7 +276,7 @@ <!-- XHED: App overview subtitle for glossary keys --> <string name="main_overview_subtitle_glossary_keys">"Identyfikator losowy"</string> <!-- YTXT: App overview body for glossary keys --> - <string name="main_overview_body_glossary_keys">"Losowe identyfikatory sÄ… kombinacjÄ… cyfr i liter generowanych losowo. SÄ… one wymieniane pomiÄ™dzy smartfonami znajdujÄ…cymi siÄ™ w bliskiej odlegÅ‚oÅ›ci od siebie. Losowych identyfikatorów nie można przypisać do konkretnej osoby. SÄ… one automatycznie usuwane po 14 dniach. Osoby, u których zdiagnozowano COVID-19, mogÄ… zdecydować siÄ™ na udostÄ™pnienie swoich losowych identyfikatorów z ostatnich 14 dni innym użytkownikom aplikacji."</string> + <string name="main_overview_body_glossary_keys">"Losowe identyfikatory sÄ… kombinacjÄ… cyfr i liter generowanych losowo. SÄ… one wymieniane pomiÄ™dzy smartfonami znajdujÄ…cymi siÄ™ w bliskiej odlegÅ‚oÅ›ci od siebie. Losowych identyfikatorów nie można przypisać do konkretnej osoby. SÄ… one automatycznie usuwane po 14 dniach. Osoby, u których zdiagnozowano koronawirusa, mogÄ… zdecydować siÄ™ na udostÄ™pnienie swoich losowych identyfikatorów z ostatnich 14 dni innym użytkownikom aplikacji."</string> <!-- XACT: main (overview) - illustraction description, explanation image --> <string name="main_overview_illustration_description">"Smartfon wyÅ›wietla różne treÅ›ci oznaczone numerami od 1 do 3."</string> <!-- XACT: App main page title --> @@ -293,11 +293,11 @@ <!-- XHED: risk details - subtitle for additional info in case of encounter with low risk --> <string name="risk_details_additional_info_subtitle">"Dlaczego Twoje ryzyko zakażenia jest niskie"</string> <!-- XHED: risk details - text for additional info in case of encounter with low risk --> - <string name="risk_details_additional_info_text">"ByÅ‚eÅ›(-aÅ›) narażony(-a) na kontakt z osobÄ…, u której zdiagnozowano COVID-19. Jednak na podstawie Twoich danych rejestrowania narażenia Twoje ryzyko zakażenia jest niskie. Ryzyko jest niskie, jeÅ›li Twój kontakt trwaÅ‚ krótko lub zachowany zostaÅ‚ dystans. Nie musisz siÄ™ martwić i podejmować żadnych dziaÅ‚aÅ„. Zalecamy przestrzeganie obowiÄ…zujÄ…cych reguÅ‚ dotyczÄ…cych dystansu i higieny."</string> + <string name="risk_details_additional_info_text">"ByÅ‚eÅ›(-aÅ›) narażony(-a) na kontakt z osobÄ…, u której zdiagnozowano koronawirusa. Jednak Twoje ryzyko zakażenia obliczone na podstawie Twoich danych rejestrowania narażenia jest niskie. Ryzyko jest niskie, jeÅ›li Twój kontakt trwaÅ‚ krótko lub zachowany zostaÅ‚ dystans. Nie musisz siÄ™ martwić i podejmować żadnych dziaÅ‚aÅ„. Zalecamy przestrzeganie obowiÄ…zujÄ…cych reguÅ‚ dotyczÄ…cych zachowania dystansu i higieny."</string> <!-- XHED: risk details - headline, how a user should act --> <string name="risk_details_headline_behavior">"Wytyczne"</string> <!-- XHED: risk details - multiline headline, bold, how to act correct --> - <string name="risk_details_subtitle_behavior">"Zalecenia"</string> + <string name="risk_details_subtitle_behavior">"Zalecenia:"</string> <!-- XMSG: risk details - go/stay home, something like a bullet point --> <string name="risk_details_behavior_body_stay_home">"JeÅ›li to możliwe, idź do domu i w nim pozostaÅ„."</string> <!-- XMSG: risk details - get in touch with the corresponding people, something like a bullet point --> @@ -327,23 +327,23 @@ <!-- XHED: risk details - infection period logged information body, below behaviors --> <string name="risk_details_information_body_period_logged_assessment">"Rejestrowanie narażenia obejmuje ostatnie 14 dni. W tym czasie funkcja rejestrowania w Twoim smartfonie byÅ‚a aktywna przez %1$s dni. Aplikacja automatycznie usuwa starsze dzienniki, ponieważ nie sÄ… one już istotne dla zapobiegania zakażeniom."</string> <!-- XHED: risk details - how your risk level was calculated, below behaviors --> - <string name="risk_details_subtitle_infection_risk_past">"Sposób, w jaki obliczono Twoje ryzyko"</string> + <string name="risk_details_subtitle_infection_risk_past">"Sposób, w jaki obliczono Twoje ryzyko."</string> <!-- XHED: risk details - how your risk level will be calculated, below behaviors --> - <string name="risk_details_subtitle_infection_risk">"Sposób, w jaki obliczane jest Twoje ryzyko"</string> + <string name="risk_details_subtitle_infection_risk">"Sposób, w jaki obliczane jest Twoje ryzyko."</string> <!-- XMSG: risk details - risk calculation wasn't possible for 24h, below behaviors --> <string name="risk_details_information_body_outdated_risk">"Rejestrowanie narażenia nie mogÅ‚o zostać zaktualizowane przez okres dÅ‚uższy niż 24 godziny."</string> <!-- YTXT: risk details - low risk explanation text --> - <string name="risk_details_information_body_low_risk">"Masz niskie ryzyko zakażenia, ponieważ nie zarejestrowano narażenia na kontakt z osobami, u których później zdiagnozowano COVID-19, lub ponieważ Twoje kontakty trwaÅ‚y krótko przy zachowaniu odpowiednio dużej odlegÅ‚oÅ›ci."</string> + <string name="risk_details_information_body_low_risk">"Masz niskie ryzyko zakażenia, ponieważ nie zarejestrowano narażenia na kontakt z osobami, u których później zdiagnozowano koronawirusa, lub ponieważ Twoje kontakty trwaÅ‚y krótko przy zachowaniu odpowiednio dużej odlegÅ‚oÅ›ci."</string> <!-- YTXT: risk details - low risk explanation text with encounter with low risk --> - <string name="risk_details_information_body_low_risk_with_encounter">"Ryzyko zakażenia jest obliczane lokalnie na Twoim smartfonie na podstawie danych rejestrowania narażenia. Ta kalkulacja uwzglÄ™dnia również dystans i czas trwania narażenia na kontakt z osobami, u których zdiagnozowano COVID-19, a także potencjalnÄ… podatność na zakażenie. Twoje ryzyko zakażenia nie jest widoczne dla nikogo ani nikomu przekazywane."</string> + <string name="risk_details_information_body_low_risk_with_encounter">"Ryzyko zakażenia jest obliczane lokalnie na Twoim smartfonie na podstawie danych rejestrowania narażenia. Ta kalkulacja uwzglÄ™dnia również dystans i czas trwania narażenia na kontakt z osobami, u których zdiagnozowano koronawirusa, a także ich potencjalnÄ… zakaźność. Twoje ryzyko zakażenia nie jest widoczne dla nikogo ani nikomu przekazywane."</string> <!-- YTXT: risk details - increased risk explanation text with variable for day(s) since last contact --> <plurals name="risk_details_information_body_increased_risk"> - <item quantity="one">"Masz podwyższone ryzyko zakażenia, ponieważ %1$s dni temu byÅ‚eÅ›(-aÅ›) narażony(-a) na dÅ‚uższy, bliski kontakt z co najmniej jednÄ… osobÄ…, u której zdiagnozowano COVID-19."</item> - <item quantity="other">"Masz podwyższone ryzyko zakażenia, ponieważ %1$s dni temu byÅ‚eÅ›(-aÅ›) narażony(-a) na dÅ‚uższy, bliski kontakt z co najmniej jednÄ… osobÄ…, u której zdiagnozowano COVID-19."</item> - <item quantity="zero">"Masz podwyższone ryzyko zakażenia, ponieważ %1$s dni temu byÅ‚eÅ›(-aÅ›) narażony(-a) na dÅ‚uższy, bliski kontakt z co najmniej jednÄ… osobÄ…, u której zdiagnozowano COVID-19."</item> - <item quantity="two">"Masz podwyższone ryzyko zakażenia, ponieważ %1$s dni temu byÅ‚eÅ›(-aÅ›) narażony(-a) na dÅ‚uższy, bliski kontakt z co najmniej jednÄ… osobÄ…, u której zdiagnozowano COVID-19."</item> - <item quantity="few">"Masz podwyższone ryzyko zakażenia, ponieważ %1$s dni temu byÅ‚eÅ›(-aÅ›) narażony(-a) na dÅ‚uższy, bliski kontakt z co najmniej jednÄ… osobÄ…, u której zdiagnozowano COVID-19."</item> - <item quantity="many">"Masz podwyższone ryzyko zakażenia, ponieważ %1$s dni temu byÅ‚eÅ›(-aÅ›) narażony(-a) na dÅ‚uższy, bliski kontakt z co najmniej jednÄ… osobÄ…, u której zdiagnozowano COVID-19."</item> + <item quantity="one">"Masz podwyższone ryzyko zakażenia, ponieważ %1$s dzieÅ„ temu byÅ‚eÅ›(-aÅ›) narażony(-a) na dÅ‚uższy, bliski kontakt z co najmniej jednÄ… osobÄ…, u której zdiagnozowano koronawirusa."</item> + <item quantity="other">"Masz podwyższone ryzyko zakażenia, ponieważ %1$s dnia temu byÅ‚eÅ›(-aÅ›) narażony(-a) na dÅ‚uższy, bliski kontakt z co najmniej jednÄ… osobÄ…, u której zdiagnozowano koronawirusa."</item> + <item quantity="zero">"Masz podwyższone ryzyko zakażenia, ponieważ %1$s dni temu byÅ‚eÅ›(-aÅ›) narażony(-a) na dÅ‚uższy, bliski kontakt z co najmniej jednÄ… osobÄ…, u której zdiagnozowano koronawirusa."</item> + <item quantity="two">"Masz podwyższone ryzyko zakażenia, ponieważ %1$s dni temu byÅ‚eÅ›(-aÅ›) narażony(-a) na dÅ‚uższy, bliski kontakt z co najmniej jednÄ… osobÄ…, u której zdiagnozowano koronawirusa."</item> + <item quantity="few">"Masz podwyższone ryzyko zakażenia, ponieważ %1$s dni temu byÅ‚eÅ›(-aÅ›) narażony(-a) na dÅ‚uższy, bliski kontakt z co najmniej jednÄ… osobÄ…, u której zdiagnozowano koronawirusa."</item> + <item quantity="many">"Masz podwyższone ryzyko zakażenia, ponieważ %1$s dni temu byÅ‚eÅ›(-aÅ›) narażony(-a) na dÅ‚uższy, bliski kontakt z co najmniej jednÄ… osobÄ…, u której zdiagnozowano koronawirusa."</item> </plurals> <!-- YTXT: risk details - risk calculation explanation --> <string name="risk_details_information_body_notice">"Ryzyko zakażenia jest obliczane na podstawie danych rejestrowania narażenia (czas trwania i bliskość kontaktu) lokalnie w smartfonie. Twoje ryzyko zakażenia nie jest widoczne dla nikogo ani nikomu przekazywane."</string> @@ -404,7 +404,7 @@ <!-- XHED: onboarding(together) - two/three line headline under an illustration --> <string name="onboarding_subtitle">"WiÄ™ksza ochrona dla Ciebie i dla nas wszystkich. KorzystajÄ…c z aplikacji Corona-Warn-App, możemy znacznie szybciej przerwać Å‚aÅ„cuchy zakażeÅ„."</string> <!-- YTXT: onboarding(together) - inform about the app --> - <string name="onboarding_body">"ZmieÅ„ swój smartfon w system ostrzegania przed koronawirusem. Zapoznaj siÄ™ ze swoim statusem ryzyka i dowiedz siÄ™, czy miaÅ‚eÅ›(-aÅ›) bliski kontakt z osobÄ…, u której w ciÄ…gu ostatnich 14 dni zdiagnozowano COVID-19."</string> + <string name="onboarding_body">"ZmieÅ„ swój smartfon w system ostrzegania przed koronawirusem. Zapoznaj siÄ™ ze swoim statusem ryzyka i dowiedz siÄ™, czy miaÅ‚eÅ›(-aÅ›) bliski kontakt z osobÄ…, u której w ciÄ…gu ostatnich 14 dni zdiagnozowano koronawirusa."</string> <!-- YTXT: onboarding(together) - explain application --> <string name="onboarding_body_emphasized">"Aplikacja rejestruje kontakty miÄ™dzy osobami poprzez wymianÄ™ zaszyfrowanych, losowych identyfikatorów miÄ™dzy ich smartfonami bez uzyskiwania dostÄ™pu do danych osobowych."</string> <!-- XACT: onboarding(together) - illustraction description, header image --> @@ -423,7 +423,7 @@ <!-- XHED: onboarding(tracing) - two/three line headline under an illustration --> <string name="onboarding_tracing_subtitle">"Aby ustalić wystÄ™powanie ryzyka zakażenia, musisz aktywować funkcjÄ™ rejestrowania narażenia."</string> <!-- YTXT: onboarding(tracing) - explain tracing --> - <string name="onboarding_tracing_body">"DziaÅ‚anie funkcji rejestrowania narażenia polega na odbieraniu przez Twój smartfon za pomocÄ… Bluetooth zaszyfrowanych, losowych identyfikatorów innych użytkowników i przekazywaniu Twoich wÅ‚asnych, losowych identyfikatorów do ich smartfonów. Rejestrowanie narażenia można wyÅ‚Ä…czyć w dowolnym momencie. "</string> + <string name="onboarding_tracing_body">"DziaÅ‚anie funkcji rejestrowania narażenia polega na odbieraniu przez Twój smartfon z systemem Android za pomocÄ… Bluetooth zaszyfrowanych, losowych identyfikatorów innych użytkowników i przekazywaniu Twoich wÅ‚asnych, losowych identyfikatorów do ich smartfonów. Rejestrowanie narażenia można wyÅ‚Ä…czyć w dowolnym momencie. "</string> <!-- YTXT: onboarding(tracing) - explain tracing --> <string name="onboarding_tracing_body_emphasized">"Zaszyfrowane losowe identyfikatory przekazujÄ… innym osobom jedynie informacje o dacie kontaktu, czasie trwania i odlegÅ‚oÅ›ci (obliczonej na podstawie mocy sygnaÅ‚u) od innych użytkowników aplikacji. Ustalenie tożsamoÅ›ci osób na podstawie losowych identyfikatorów nie jest możliwe."</string> <!-- YTXT: onboarding(tracing) - easy language explain tracing link--> @@ -471,9 +471,9 @@ <!-- XBUT: onboarding(tracing) - button enable tracing --> <string name="onboarding_tracing_location_button">"Otwórz ustawienia urzÄ…dzenia"</string> <!-- XACT: Onboarding (test) page title --> - <string name="onboarding_test_accessibility_title">"Strona wprowadzenia 5 z 6: JeÅ›li zdiagnozowano u Ciebie COVID-19"</string> + <string name="onboarding_test_accessibility_title">"Strona wprowadzenia 5 z 6: JeÅ›li zdiagnozowano u Ciebie koronawirusa"</string> <!-- XHED: onboarding(test) - about positive tests --> - <string name="onboarding_test_headline">"JeÅ›li zdiagnozowano u Ciebie COVID-19..."</string> + <string name="onboarding_test_headline">"JeÅ›li zdiagnozowano u Ciebie koronawirusa..."</string> <!-- XHED: onboarding(test) - two/three line headline under an illustration --> <string name="onboarding_test_subtitle">"… zgÅ‚oÅ› ten fakt w Corona-Warn-App. UdostÄ™pnianie wyników testu jest dobrowolne i bezpieczne. Zrób to ze wzglÄ™du na zdrowie innych osób."</string> <!-- YTXT: onboarding(test) - explain test --> @@ -496,7 +496,7 @@ ###################################### --> <!-- XACT: onboarding(sixteen) title --> - <string name="sixteen_title_text">"Limit wieku: 16 i wiÄ™cej"</string> + <string name="sixteen_title_text">"Ostrzeżenie dot. wieku (16 lat)"</string> <!-- XACT: onboarding(sixteen) title --> <string name="sixteen_description_text">"Ta aplikacja jest przeznaczona dla osób, które ukoÅ„czyÅ‚y 16 lat i mieszkajÄ… w Niemczech."</string> @@ -525,7 +525,7 @@ <!-- XTXT: settings(tracing) - shows status under header in home, inactive location --> <string name="settings_tracing_body_inactive_location">"UsÅ‚ugi lokalizacji dezaktywowane"</string> <!-- YTXT: settings(tracing) - explains tracings --> - <string name="settings_tracing_body_text">"Musisz wÅ‚Ä…czyć funkcjÄ™ rejestrowania narażenia, aby aplikacja mogÅ‚a ustalić, czy dotyczy CiÄ™ ryzyko zakażenia po kontakcie z zainfekowanym użytkownikiem aplikacji. Funkcja rejestrowania narażenia dziaÅ‚a w skali miÄ™dzynarodowej, co oznacza, że potencjalne narażenie użytkowników jest wykrywane również przez inne oficjalne aplikacje koronawirusowe.\n\nDziaÅ‚anie funkcji rejestrowania narażenia polega na odbieraniu przez Twój smartfon za pomocÄ… Bluetooth zaszyfrowanych, losowych identyfikatorów innych użytkowników i przekazywaniu Twoich wÅ‚asnych, losowych identyfikatorów do ich smartfonów. Codziennie aplikacja pobiera listÄ™ losowych identyfikatorów – wraz z wszelkimi opcjonalnie podawanymi informacjami o wystÄ…pieniu objawów – wszystkich użytkowników, którzy mieli pozytywny wynik testu na koronawirusa i dobrowolnie udostÄ™pnili tÄ™ informacjÄ™ poprzez aplikacjÄ™. Lista jest nastÄ™pnie porównywana z losowymi identyfikatorami innych użytkowników, które zarejestrowaÅ‚ Twój smartfon, w celu obliczenia prawdopodobieÅ„stwa Twojego zakażenia i ostrzeżenia CiÄ™ w razie potrzeby. FunkcjÄ™ tÄ™ można wyÅ‚Ä…czyć w dowolnym momencie.\n\nAplikacja nigdy nie gromadzi danych osobowych, takich jak imiÄ™ i nazwisko, adres czy lokalizacja. Takie informacje nie sÄ… też przekazywane innym użytkownikom. Nie jest możliwe wykorzystanie losowych identyfikatorów w celu ustalenia tożsamoÅ›ci poszczególnych osób."</string> + <string name="settings_tracing_body_text">"Musisz wÅ‚Ä…czyć funkcjÄ™ rejestrowania narażenia, aby aplikacja mogÅ‚a ustalić, czy dotyczy CiÄ™ ryzyko zakażenia po kontakcie z zainfekowanym użytkownikiem aplikacji. Funkcja rejestrowania narażenia dziaÅ‚a w skali miÄ™dzynarodowej, co oznacza, że potencjalne narażenie użytkowników jest wykrywane również przez inne oficjalne aplikacje koronawirusowe.\n\nDziaÅ‚anie funkcji rejestrowania narażenia polega na odbieraniu przez Twój smartfon z systemem Android za pomocÄ… Bluetooth zaszyfrowanych, losowych identyfikatorów innych użytkowników i przekazywaniu Twoich wÅ‚asnych, losowych identyfikatorów do ich smartfonów. Codziennie aplikacja pobiera listÄ™ losowych identyfikatorów – wraz z wszelkimi opcjonalnie podawanymi informacjami o wystÄ…pieniu objawów – wszystkich użytkowników, którzy mieli pozytywny wynik testu na obecność koronawirusa i dobrowolnie udostÄ™pnili tÄ™ informacjÄ™ (a dokÅ‚adnie swoje losowe identyfikatory) poprzez swojÄ… aplikacjÄ™. Lista ta jest nastÄ™pnie porównywana z zarejestrowanymi przez Twój smartfon z systemem Android losowymi identyfikatorami innych użytkowników, z którymi miaÅ‚eÅ›(-aÅ›) kontakt, w celu obliczenia prawdopodobieÅ„stwa Twojego zakażenia i ostrzeżenia CiÄ™ w razie potrzeby. FunkcjÄ™ rejestrowania narażenia można wyÅ‚Ä…czyć w dowolnym momencie.\n\nAplikacja nigdy nie gromadzi danych osobowych, takich jak imiÄ™ i nazwisko, adres czy lokalizacja. Takie informacje nie sÄ… też przekazywane innym użytkownikom. Nie jest możliwe wykorzystanie losowych identyfikatorów do ustalenia tożsamoÅ›ci poszczególnych osób."</string> <!-- XTXT: settings(tracing) - status next to switch under title --> <string name="settings_tracing_status_active">"Aktywne"</string> <!-- XTXT: settings(tracing) - status next to switch under title --> @@ -553,7 +553,7 @@ <!--XHED : settings(tracing) - headline on card about the current status and what to do --> <string name="settings_tracing_status_connection_headline">"Otwórz poÅ‚Ä…czenie z Internetem"</string> <!-- XTXT: settings(tracing) - explains user what to do on card if connection is disabled --> - <string name="settings_tracing_status_connection_body">"Rejestrowanie narażenia wymaga poÅ‚Ä…czenia z Internetem w celu obliczenia narażeÅ„. WÅ‚Ä…cz WIFI lub dane mobilne w ustawieniach swojego urzÄ…dzenia."</string> + <string name="settings_tracing_status_connection_body">"Rejestrowanie narażenia wymaga poÅ‚Ä…czenia z Internetem w celu obliczenia narażeÅ„. WÅ‚Ä…cz WIFI lub dane komórkowe w ustawieniach swojego urzÄ…dzenia."</string> <!-- XBUT: settings(tracing) - go to operating system settings button on card --> <string name="settings_tracing_status_connection_button">"Otwórz ustawienia urzÄ…dzenia"</string> <!-- XTXT: settings(tracing) - explains the circle progress indicator to the right with the current value --> @@ -595,7 +595,7 @@ <!-- XTXT: settings(notification) - next to a switch --> <string name="settings_notifications_subtitle_update_risk">"Twoje ryzyko zakażenia zmieniÅ‚o siÄ™"</string> <!-- XTXT: settings(notification) - next to a switch --> - <string name="settings_notifications_subtitle_update_test">"Status Twojego testu na COVID-19"</string> + <string name="settings_notifications_subtitle_update_test">"Status Twojego testu na obecność koronawirusa"</string> <!-- XBUT: settings(notification) - go to operating settings --> <string name="settings_notifications_button_open_settings">"Otwórz ustawienia urzÄ…dzenia"</string> <!-- XACT: main (overview) - illustraction description, explanation image, displays notificatin status, active --> @@ -604,7 +604,7 @@ <string name="settings_notifications_illustration_description_inactive">"Kobieta dezaktywowaÅ‚a powiadomienia dla swojej aplikacji Corona-Warn-App."</string> <!-- XBUT: settings - go to reset application --> <string name="settings_reset_title">"Resetuj aplikacjÄ™"</string> - <!-- XTXT: settings(reset) - explains the user what do expect when he navigates to reset --> + <!-- XTXT: settings(reset) - explains the user what do expect when navigating to reset --> <string name="settings_reset_body_description">"UsuÅ„ wszystkie swoje dane z aplikacji."</string> <!-- XHED: settings(reset) - multiline headline below illustration --> <string name="settings_reset_headline">"Czy na pewno chcesz resetować aplikacjÄ™?"</string> @@ -660,7 +660,7 @@ <!-- YTXT: Body text for about information page --> <string name="information_about_body_emphasized">"Instytut Roberta Kocha (RKI) to niemiecka federalna instytucja zdrowia publicznego. RKI publikuje aplikacjÄ™ Corona-Warn-App w imieniu rzÄ…du federalnego. Aplikacja ta sÅ‚uży jako cyfrowe uzupeÅ‚nienie już wprowadzonych Å›rodków ochrony zdrowia publicznego, takich jak zachowanie dystansu spoÅ‚ecznego, dbanie o higienÄ™ oraz noszenie maseczek."</string> <!-- YTXT: Body text for about information page --> - <string name="information_about_body">"Osoby korzystajÄ…ce z aplikacji pomagajÄ… w Å›ledzeniu i przerwaniu Å‚aÅ„cuchów zakażeÅ„. Aplikacja zapisuje kontakty z innymi osobami lokalnie na Twoim urzÄ…dzeniu. Otrzymasz powiadomienie, jeÅ›li okaże siÄ™, że u osób, z którymi miaÅ‚eÅ›(-aÅ›) kontakt, zdiagnozowano później COVID-19. Twoja tożsamość i prywatność sÄ… zawsze chronione."</string> + <string name="information_about_body">"Osoby korzystajÄ…ce z aplikacji pomagajÄ… w Å›ledzeniu i przerwaniu Å‚aÅ„cuchów zakażeÅ„. Aplikacja zapisuje kontakty z innymi osobami lokalnie na Twoim urzÄ…dzeniu. Otrzymasz powiadomienie, jeÅ›li okaże siÄ™, że u osób, z którymi miaÅ‚eÅ›(-aÅ›) kontakt, zdiagnozowano później koronawirusa. Twoja tożsamość i prywatność sÄ… zawsze chronione."</string> <!-- XACT: describes illustration --> <string name="information_about_illustration_description">"Grupa osób korzysta ze smartfonów na mieÅ›cie."</string> <!-- XHED: Page title for privacy information page, also menu item / button text --> @@ -754,7 +754,7 @@ <!-- XHED: Dialog title for already paired test error: qr --> <string name="submission_error_dialog_web_test_paired_title">"Niepoprawny kod QR"</string> <!-- XMSG: Dialog body for already paired test error: qr --> - <string name="submission_error_dialog_web_test_paired_body">"Kod QR jest niepoprawny lub zostaÅ‚ już zarejestrowany na innym smartfonie. Otrzymasz swój wynik testu z oÅ›rodka wykonujÄ…cego testy lub laboratorium niezależnie od ważnoÅ›ci kodu QR. W przypadku zdiagnozowania u Ciebie COVID-19 otrzymasz powiadomienie z organu ds. zdrowia publicznego."</string> + <string name="submission_error_dialog_web_test_paired_body">"Kod QR jest niepoprawny lub zostaÅ‚ już zarejestrowany na innym smartfonie. Otrzymasz swój wynik testu z oÅ›rodka wykonujÄ…cego testy lub laboratorium niezależnie od ważnoÅ›ci kodu QR. W przypadku zdiagnozowania u koronawirusa otrzymasz powiadomienie z organu ds. zdrowia publicznego."</string> <!-- XHED: Dialog title for already paired test error: tan --> <string name="submission_error_dialog_web_test_paired_title_tan">"TAN jest nieprawidÅ‚owy."</string> <!-- XMSG: Dialog body for already paired test via tan - error: tan --> @@ -784,9 +784,9 @@ <string name="submission_error_dialog_web_tan_redeemed_button_positive">"OK"</string> <!-- XHED: Dialog title for keys submission process cancellation --> - <string name="submission_error_dialog_confirm_cancellation_title">"Czy chcesz anulować?"</string> + <string name="submission_error_dialog_confirm_cancellation_title">"Czy chcesz anulować wprowadzanie objawów?"</string> <!-- XMSG: Dialog body for keys submission process cancellation --> - <string name="submission_error_dialog_confirm_cancellation_body">"Twoje wpisy nie zostanÄ… zapisane."</string> + <string name="submission_error_dialog_confirm_cancellation_body">"Przekazanie informacji o objawach pozwoli Ci na wysyÅ‚anie innym bardziej szczegółowych ostrzeżeÅ„."</string> <!-- XBUT: Positive button for keys submission process cancellation --> <string name="submission_error_dialog_confirm_cancellation_button_positive">"Tak"</string> <!-- XBUT: Negative button for keys submission process cancellation --> @@ -814,7 +814,7 @@ <!-- XHED: Dialog headline for invalid QR code --> <string name="submission_qr_code_scan_invalid_dialog_headline">"Niepoprawny kod QR"</string> <!-- YTXT: Dialog Body text for invalid QR code --> - <string name="submission_qr_code_scan_invalid_dialog_body">"Kod QR jest niepoprawny lub zostaÅ‚ już zarejestrowany na innym smartfonie. Otrzymasz swój wynik testu z oÅ›rodka wykonujÄ…cego testy lub laboratorium niezależnie od ważnoÅ›ci kodu QR. W przypadku zdiagnozowania u Ciebie COVID-19 organ ds. zdrowia publicznego zostanie powiadomiony przez ustanowiony prawnie kanaÅ‚ komunikacyjny i skontaktuje siÄ™ z TobÄ…."</string> + <string name="submission_qr_code_scan_invalid_dialog_body">"Kod QR jest niepoprawny lub zostaÅ‚ już zarejestrowany na innym smartfonie. Otrzymasz swój wynik testu z oÅ›rodka wykonujÄ…cego testy lub laboratorium niezależnie od ważnoÅ›ci kodu QR. W przypadku zdiagnozowania u Ciebie koronawirusa organ ds. zdrowia publicznego zostanie powiadomiony przez ustanowiony prawnie kanaÅ‚ komunikacyjny i skontaktuje siÄ™ z TobÄ…."</string> <!-- XBUT: Dialog(Invalid QR code) - positive button (right) --> <string name="submission_qr_code_scan_invalid_dialog_button_positive">"Spróbuj ponownie."</string> <!-- XBUT: Dialog(Invalid QR code) - negative button (left) --> @@ -825,6 +825,34 @@ <!-- YTXT: instruction text for QR code scanning --> <string name="submission_qr_code_scan_body">"Ustaw kod QR w ramce."</string> + <!-- QR Code Consent Screen --> + <!-- XHED: Page headline for Submission consent --> + <string name="submission_consent_main_headline">"Twoja zgoda"</string> + <!-- YTXT: Body for Submissionconsent --> + <string name="submission_consent_main_headline_body">"Zanim pobierzesz wynik testu i bÄ™dziesz ostrzegać innych musisz wyrazić zgodÄ™."</string> + <!-- XHED: Page subheadline for consent call test result --> + <string name="submission_consent_call_test_result">"Pobierz wynik testu"</string> + <!-- YTXT: Body for Submission Consent call test result body --> + <string name="submission_consent_call_test_result_body">"W nastÄ™pnym kroku zeskanuj kod QR ze swojego testu i pobierz wynik testu."</string> + <!-- YTXT: Body sub text 1 for Submission Consent call test result --> + <string name="submission_consent_call_test_result_scan_your_test_only">"Zeskanuj tylko swój wÅ‚asny test."</string> + <!-- YTXT: Body sub text 2 for Submission Consent call test result --> + <string name="submission_consent_call_test_result_scan_test_only_once">"Test można zeskanować tylko raz. Aplikacja nie może zarzÄ…dzać wieloma testami jednoczeÅ›nie."</string> + <!-- XHED: Page subheadline for consent help by warning others --> + <string name="submission_consent_help_by_warning_others_headline">"Pomóż osobom, z którymi miaÅ‚eÅ›(-aÅ›) kontakt, ostrzegajÄ…c ich!"</string> + <!-- YTXT: Body for consent help by warning others --> + <string name="submission_consent_help_by_warning_others_body">"JeÅ›li zdiagnozowano u Ciebie koronawirusa, możesz ostrzec innych za poÅ›rednictwem aplikacji. Funkcja ostrzegania dziaÅ‚a w kilku krajach. Obecnie sÄ… to nastÄ™pujÄ…ce kraje:"</string> + <!-- YTXT: Page bottom text for consent screen --> + <string name="submission_consent_main_bottom_body">"Szczegółowe informacje na temat przetwarzania danych i Twojej zgodzie"</string> + <!-- YTXT: Body for consent main section first point --> + <string name="submission_consent_main_first_point">"Twoja zgoda jest dobrowolna."</string> + <!-- YTXT: Body for consent main section second point --> + <string name="submission_consent_main_second_point">"Możesz pobrać swój wynik testu, nawet jeÅ›li nie zamierzasz go udostÄ™pniać. JeÅ›li jednak zdecydujesz siÄ™ na jego udostÄ™pnienie, pomożesz chronić innych przed zakażeniem."</string> + <!-- YTXT: Body for consent main section third point --> + <string name="submission_consent_main_third_point">"Twoja tożsamość nie zostanie ujawniona. Inni użytkownicy nie bÄ™dÄ… wiedzieć, kto udostÄ™pniÅ‚ swoje wyniki testów."</string> + <!-- YTXT: Body for consent main section fourth point --> + <string name="submission_consent_main_fourth_point">"Aby wyrazić zgodÄ™, musisz mieć ukoÅ„czone 16 lat."</string> + <!-- Submission Test Result --> <!-- XHED: Page headline for test result --> <string name="submission_test_result_headline">"Wynik testu"</string> @@ -835,9 +863,9 @@ <!-- YTXT: Body text for for results next steps --> <string name="submission_test_result_steps_added_body">"Twój test zostaÅ‚ zapisany w Corona-Warn-App."</string> <!-- XHED: Page headline for pending test result next steps --> - <string name="submission_test_result_pending_steps_waiting_heading">"Wynik testu nie jest jeszcze dostÄ™pny"</string> + <string name="submission_test_result_pending_steps_waiting_heading">"Twój wynik testu nie jest jeszcze dostÄ™pny."</string> <!-- YTXT: Body text for next steps section of waiting test result page --> - <string name="submission_test_result_pending_steps_waiting_body">"Prosimy o cierpliwość. Ustalenie wyniku może potrwać kilka dni.\n\nWynik testu otrzymasz również poza aplikacjÄ…. Organ ds. zdrowia publicznego powiadomi CiÄ™, jeÅ›li wynik testu bÄ™dzie pozytywny.\n\nW przypadku pozytywnego wyniku testu zadzwoÅ„ na numer podany w sekcji „PoproÅ› o TANâ€, aby zarejestrować swój wynik w aplikacji i ostrzec innych."</string> + <string name="submission_test_result_pending_steps_waiting_body">"Wynik testu zostanie wyÅ›wietlony w aplikacji, jak tylko bÄ™dzie dostÄ™pny."</string> <!-- XBUT: test result pending : refresh button --> <string name="submission_test_result_pending_refresh_button">"Aktualizuj"</string> <!-- XBUT: test result pending : remove the test button --> @@ -873,7 +901,7 @@ <!-- XHED: Dialog title for test removal --> <string name="submission_test_result_dialog_remove_test_title">"Test można zeskanować tylko raz."</string> <!-- YTXT: Dialog text for test removal --> - <string name="submission_test_result_dialog_remove_test_message">"JeÅ›li usuniesz test, nie bÄ™dziesz mieć możliwoÅ›ci pobrania wyniku swojego testu. Otrzymasz swój wynik testu z oÅ›rodka wykonujÄ…cego testy lub laboratorium niezależnie od ważnoÅ›ci kodu QR. W przypadku zdiagnozowania u Ciebie COVID-19 organ ds. zdrowia publicznego zostanie powiadomiony przez ustanowiony prawnie kanaÅ‚ komunikacyjny i skontaktuje siÄ™ z TobÄ…."</string> + <string name="submission_test_result_dialog_remove_test_message">"JeÅ›li usuniesz test, nie bÄ™dziesz mieć możliwoÅ›ci pobrania wyniku swojego testu. Otrzymasz swój wynik testu z oÅ›rodka wykonujÄ…cego testy lub laboratorium niezależnie od ważnoÅ›ci kodu QR. W przypadku zdiagnozowania u Ciebie koronawirusa organ ds. zdrowia publicznego zostanie powiadomiony przez ustanowiony prawnie kanaÅ‚ komunikacyjny i skontaktuje siÄ™ z TobÄ…."</string> <!-- XBUT: Positive button for test removal --> <string name="submission_test_result_dialog_remove_test_button_positive">"UsuÅ„"</string> <!-- XBUT: Negative button for test removal --> @@ -882,6 +910,16 @@ <string name="submission_test_result_card_positive_title">"Zakażenie SARS-CoV-2"</string> <!-- YTXT: Body text for test result card positive --> <string name="submission_test_result_card_positive_body">"Zdiagnozowano u Ciebie wirusa SARS-CoV-2."</string> + <!-- XHED: Page headline for test result with consent given --> + <string name="submission_test_result_consent_given_heading">"Twój wynik testu"</string> + <!-- XHED: Subtitle text for test result card with consent given --> + <string name="submission_test_result_consent_given_subtitle">"DziÄ™kujemy za pomoc w powstrzymywaniu rozprzestrzeniania siÄ™ koronawirusa."</string> + <!-- YTXT: body text for test result card with consent given --> + <string name="submission_test_result_consent_given_body"><b>"Inne osoby, z którymi miaÅ‚eÅ›(-a) kontakt, zostanÄ… teraz ostrzeżone."</b>" "<br/><br/>" Możesz teraz pomóc zwiÄ™kszyć dokÅ‚adność ostrzeżeÅ„. Aby to zrobić, w nastÄ™pnym kroku powiedz nam, kiedy wystÄ…piÅ‚y u Ciebie pierwsze objawy. Możesz anulować ten krok w dowolnym momencie."</string> + <!-- XBUT: button text for the 'break up' button option on test result consent given page --> + <string name="submission_test_result_consent_given_breakup_button">"ZakoÅ„cz"</string> + + <!-- Submission Tan --> <!-- XHED: Page title for TAN submission pge --> @@ -903,7 +941,7 @@ <!-- XHED: Page headline for menu the at start of the submission process --> <string name="submission_intro_headline">"Sposób dziaÅ‚ania Corona-Warn-App"</string> <!-- YTXT: submission introduction text --> - <string name="submission_intro_text">"Skuteczność dziaÅ‚ania aplikacji zależy od pomocy osób, u których zdiagnozowano COVID-19.\n\nZawsze zachowujesz anonimowość, ponieważ wymienianie sÄ… tylko zaszyfrowane, losowe identyfikatory. Możesz teraz postÄ…pić w poniższy sposób:"</string> + <string name="submission_intro_text">"Skuteczność dziaÅ‚ania aplikacji zależy od pomocy osób, u których zdiagnozowano koronawirusa.\n\nZawsze zachowujesz anonimowość, ponieważ wymienianie sÄ… tylko zaszyfrowane, losowe identyfikatory. Możesz teraz postÄ…pić w poniższy sposób:"</string> <!-- XBUT: Submission introduction next button--> <string name="submission_intro_button_next">"Dalej"</string> <!-- XACT: Submission intro - illustration description, explanation image --> @@ -911,7 +949,7 @@ <!-- YTXT: submission introduction bullet points --> <string-array name="submission_intro_bullet_points"> <item>"Jeżeli w Twoim dokumencie testu znajduje siÄ™ kod QR, możesz go zeskanować i zarejestrować test. Jak tylko wynik bÄ™dzie dostÄ™pny, bÄ™dziesz mieć możliwość sprawdzenia go w aplikacji."</item> - <item>"JeÅ›li zdiagnozowano u Ciebie COVID-19, możesz ostrzec inne osoby."</item> + <item>"JeÅ›li zdiagnozowano u Ciebie koronawirusa, możesz ostrzec inne osoby."</item> <item>"Jeżeli otrzymaÅ‚eÅ›(-aÅ›) numer TAN dla diagnozy zakażenia, możesz użyć go do zarejestrowania testu."</item> <item>"JeÅ›li nie masz numeru TAN, możesz poprosić o niego telefonicznie."</item> </string-array> @@ -920,25 +958,25 @@ <!-- Dispatcher --> <!-- XHED: Page headline for dispatcher menu --> - <string name="submission_dispatcher_headline">"Wybór"</string> + <string name="submission_dispatcher_headline">"Pobierz wynik testu"</string> <!-- XHED: Page subheadline for dispatcher menu --> - <string name="submission_dispatcher_subheadline">"Jakie informacje posiadasz?"</string> + <string name="submission_dispatcher_subheadline">"Pobierz wynik testu za poÅ›rednictwem aplikacji, a nastÄ™pnie ostrzeż innych. Zadbasz o swoje bezpieczeÅ„stwo i pomożesz powstrzymać rozprzestrzenianie siÄ™ koronawirusa."</string> <!-- XHED: Page subheadline for dispatcher options asking if they have already been tested: QR and TAN --> - <string name="submission_dispatcher_needs_testing_subheadline">""</string> + <string name="submission_dispatcher_needs_testing_subheadline">"Czy wykonano Ci test?"</string> <!-- XHED: Page subheadline for dispatcher options asking if they already have a positive test: tele-TAN --> - <string name="submission_dispatcher_already_positive_subheadline">""</string> + <string name="submission_dispatcher_already_positive_subheadline">"Czy Twój wynik testu na obecność koronawirusa byÅ‚ pozytywny?"</string> <!-- YTXT: Dispatcher text for QR code option --> - <string name="submission_dispatcher_card_qr">"Dokument z kodem QR"</string> + <string name="submission_dispatcher_card_qr">"Test z kodem QR"</string> <!-- YTXT: Body text for QR code dispatcher option --> <string name="submission_dispatcher_qr_card_text">"Zarejestruj test poprzez zeskanowanie kodu QR dokumentu testu."</string> <!-- YTXT: Dispatcher text for TAN code option --> - <string name="submission_dispatcher_card_tan_code">"TAN"</string> + <string name="submission_dispatcher_card_tan_code">"Wpis TAN"</string> <!-- YTXT: Body text for TAN code dispatcher option --> - <string name="submission_dispatcher_tan_code_card_text">"Zarejestruj test poprzez rÄ™czne wprowadzenie swojego numeru TAN."</string> + <string name="submission_dispatcher_tan_code_card_text">"Czy masz numer TAN? Wprowadź go, aby ostrzegać innych. "</string> <!-- YTXT: Dispatcher text for TELE-TAN option --> - <string name="submission_dispatcher_card_tan_tele">"PoproÅ› o TAN"</string> + <string name="submission_dispatcher_card_tan_tele">"Nie masz jeszcze numeru TAN?"</string> <!-- YTXT: Body text for TELE_TAN dispatcher option --> - <string name="submission_dispatcher_tan_tele_card_text">"ZadzwoÅ„ do nas, jeÅ›li zdiagnozowano u Ciebie COVID-19."</string> + <string name="submission_dispatcher_tan_tele_card_text">"ZadzwoÅ„ i odbierz numer TAN."</string> <!-- XACT: Dispatcher Tan page title --> <string name="submission_dispatcher_accessibility_title">"Jakie informacje posiadasz?"</string> @@ -956,6 +994,25 @@ <!-- XHED: Title for the interop country list--> <string name="submission_interoperability_list_title">"NastÄ™pujÄ…ce kraje uczestniczÄ… obecnie w miÄ™dzynarodowym rejestrowaniu narażenia:"</string> + <!-- Submission Positive Other Warning No Consent --> + <!-- YTXT: Body text for the positive result additional warning page--> + <string name="submission_positive_other_warning_no_consent_body_first_part">"Ze wzglÄ™du na pozytywny wynik testu na obecność koronawirusa możesz teraz ostrzegać innych za poÅ›rednictwem aplikacji."</string> + <!-- YTXT: Body text for the positive result additional warning page--> + <string name="submission_positive_other_warning_no_consent_body_second_part">"Funkcja ostrzegania dziaÅ‚a w kilku krajach. Obecnie sÄ… to nastÄ™pujÄ…ce kraje:"</string> + + + <!-- Test result positive and no consent given --> + <!-- XHED: Title for test result positive and no consent given--> + <string name="submission_test_result_positive_no_consent_subtitle">"Pomóż nam wszystkim!"</string> + <!-- XTXT: First bullet point when test result is positive and consent is requested for key sharing--> + <string name="submission_test_result_positive_no_consent_text_1"><b>"UdostÄ™pnij swój wynik testu i pomóż chronić innych przed infekcjÄ…."</b></string> + <!-- XTXT: Second bullet point when test result is positive and consent is requested for key sharing--> + <string name="submission_test_result_positive_no_consent_text_2">"Twoja tożsamość nie zostanie ujawniona. Inni użytkownicy nie bÄ™dÄ… wiedzieć, kto udostÄ™pniÅ‚ swoje wyniki testów."</string> + <!-- XTXT: Third bullet point when test result is positive and consent is requested for key sharing--> + <string name="submission_test_result_positive_no_consent_text_3">"PostÄ™puj zgodnie z poleceniami organu ds. zdrowia publicznego i zostaÅ„ w domu, aby nie zarażać innych."</string> + <!-- XBUT: Button for giving consent for key sharing --> + <string name="submission_test_result_positive_no_consent_button_warn_others">"Ostrzegaj innych"</string> + <!-- Submission Country Selector --> <!-- XHED: Page title for the submission country selection page --> <string name="submission_positive_country_selection_title">"Ostrzeżenia obejmujÄ…ce caÅ‚Ä… EuropÄ™"</string> @@ -995,13 +1052,29 @@ <!-- XACT: submission finished - illustration description, explanation image --> <string name="submission_done_illustration_description">"Czy w ciÄ…gu ostatnich kilku dni wystÄ…piÅ‚ u Ciebie jeden lub kilka z wymienionych poniżej objawów?"</string> + <!-- Submission Done No Consent--> + <!-- XHED: Page title for completed submission page --> + <string name="submission_done_no_consent_title">"DziÄ™kujemy"</string> + <!-- YTXT: Page subtitle for completed submission page --> + <string name="submission_done_no_consent_subtitle">"DziÄ™kujemy za pomoc w powstrzymywaniu rozprzestrzeniania siÄ™ koronawirusa."</string> + <!-- YTXT: Page body for submission no consent page --> + <string name="submission_done_no_consent_body_title">"Inne osoby zostanÄ… teraz ostrzeżone."</string> + <!-- YTXT: Page body for submission no consent page --> + <string name="submission_done_no_consent_body">"Możesz teraz pomóc zwiÄ™kszyć dokÅ‚adność ostrzeżeÅ„. Aby to zrobić, w nastÄ™pnym kroku powiedz nam, kiedy wystÄ…piÅ‚y u Ciebie pierwsze objawy. Możesz anulować ten krok w dowolnym momencie."</string> + <!-- XBUT: submission continue with symptom recording button --> + <string name="submission_done_no_consent_continue_with_symptom_recording">"Wprowadź objawy"</string> + <!-- XBUT: submission continue break flow button--> + <string name="submission_done_no_consent_break_flow">"ZakoÅ„cz"</string> + <!-- XACT: submission finished - illustration description, explanation image --> + <string name="submission_done_no_consent_illustration_description">"Kilka osób patrzy na ekrany swoich smartfonów."</string> + <!-- Submission Symptoms --> <!-- XHED: Page title for symptom screens --> <string name="submission_symptom_title">"Objawy"</string> <!-- XTXT: headline text for initial symptom screen --> - <string name="submission_symptom_initial_headline">"Czy wystÄ…piÅ‚ u Ciebie jeden lub kilka z wymienionych poniżej objawów?"</string> + <string name="submission_symptom_initial_headline">"Czy w ciÄ…gu ostatnich kilku dni wystÄ…piÅ‚ u Ciebie jeden lub kilka z wymienionych poniżej objawów?"</string> <!-- YTXT: explanation text for initial symptom screen --> - <string name="submission_symptom_initial_explanation">"Możesz podać, czy i kiedy zauważyÅ‚eÅ›(-Å‚aÅ›) objawy koronawirusa, aby umożliwić aplikacji dokÅ‚adniejsze obliczenie ryzyka zakażenia innych użytkowników aplikacji. JeÅ›li nie chcesz podawać tych informacji, wybierz „brak odpowiedziâ€."</string> + <string name="submission_symptom_initial_explanation">"Możesz podać, czy i kiedy zauważyÅ‚eÅ›(-Å‚aÅ›) objawy koronawirusa, aby umożliwić aplikacji dokÅ‚adniejsze obliczenie ryzyka zakażenia innych użytkowników aplikacji. Ten krok jest dobrowolny. JeÅ›li nie chcesz podawać informacji o objawach, wybierz opcjÄ™ „Brak odpowiedziâ€."</string> <!-- YTXT: Bullet points for symptoms --> <string-array name="submission_symptom_symptom_bullets"> <item>"Podwyższona temperatura lub gorÄ…czka"</item> @@ -1058,9 +1131,9 @@ <!-- XHED: Page title for calendar page in submission symptom flow --> <string name="submission_symptom_calendar_title">"PoczÄ…tek wystÄ…pienia objawów"</string> <!-- XHED: Page headline for calendar page in symptom submission flow --> - <string name="submission_symptom_calendar_headline">"Kiedy zaczÄ…Å‚eÅ›(-ęłaÅ›) odczuwać te objawy? "</string> + <string name="submission_symptom_calendar_headline">"Kiedy po raz pierwszy zauważyÅ‚eÅ›(-aÅ›) objawy?"</string> <!-- YTXT: Body text for calendar page in symptom submission flow--> - <string name="submission_symptom_calendar_body">"Wybierz dokÅ‚adnÄ… datÄ™ w kalendarzu lub, jeÅ›li nie pamiÄ™tasz dokÅ‚adnej daty, wybierz jednÄ… z innych opcji."</string> + <string name="submission_symptom_calendar_body">"Podaj jak najdokÅ‚adniejszÄ… datÄ™."</string> <!-- XBUT: symptom calendar screen less than 7 days button --> <string name="submission_symptom_less_seven">"W ciÄ…gu ostatnich 7 dni"</string> <!-- XBUT: symptom calendar screen 1-2 weeks button --> @@ -1078,7 +1151,7 @@ <!-- XHED: Page title for the various submission status: pending --> <string name="submission_status_card_title_pending">"Twój wynik testu nie jest jeszcze dostÄ™pny"</string> <!-- XHED: Page title for the various submission status: available --> - <string name="submission_status_card_title_available">"Twój wynik jest dostÄ™pny"</string> + <string name="submission_status_card_title_available">"Twój wynik testu jest dostÄ™pny"</string> <!-- XHED: Page title for the various submission status: positive --> <string name="submission_status_card_title_positive">"Diagnoza zakażenia"</string> <!-- XHED: Page title for the various submission status fetch failed --> @@ -1090,7 +1163,7 @@ <!-- YTXT: Body text for submission status: fetching --> <string name="submission_status_card_body_fetching">"Twój wynik jest aktualizowany"</string> <!-- YTXT: Body text for submission status: unregistered --> - <string name="submission_status_card_body_unregistered">"Pomóż przerwać Å‚aÅ„cuch zakażeÅ„, powiadamiajÄ…c innych."</string> + <string name="submission_status_card_body_unregistered">"Pomóż chronić siebie i innych."</string> <!-- YTXT: Body text for submission status: pending --> <string name="submission_status_card_body_pending">"Ustalanie wyniku Twojego testu jeszcze siÄ™ nie zakoÅ„czyÅ‚o."</string> <!-- YTXT: Body text for submission status: invalid --> @@ -1100,9 +1173,9 @@ <!-- YTXT: Body text for submission status: negative --> <string name="submission_status_card_body_negative">"Nie zdiagnozowano u Ciebie zakażenia wirusem SARS-CoV-2."</string> <!-- YTXT: Body text for submission status fetch failed --> - <string name="submission_status_card_body_failed">"Twój test ma wiÄ™cej niż 21 dni i straciÅ‚ ważność. UsuÅ„ tekst. BÄ™dziesz mieć wówczas możliwość dodania kolejnego."</string> + <string name="submission_status_card_body_failed">"Twój test ma wiÄ™cej niż 21 dni i straciÅ‚ ważność. UsuÅ„ test. BÄ™dziesz mieć wówczas możliwość dodania kolejnego."</string> <!-- XBUT: submission status card unregistered button --> - <string name="submission_status_card_button_unregistered">"WiÄ™cej informacji i pomoc"</string> + <string name="submission_status_card_button_unregistered">"NastÄ™pne kroki"</string> <!-- XBUT: submission status card show results button --> <string name="submission_status_card_button_show_results">"WyÅ›wietl test"</string> <!-- XBUT: submission status card fetch failed button --> @@ -1140,7 +1213,51 @@ </string-array> <!-- XBUT Symptoms exact date button --> - <string name="symptoms_calendar_exact_date_button">"DokÅ‚adna data"</string> + <string name="symptoms_calendar_exact_date_button">"Data"</string> + + <!-- Submission consent custom view --> + <!-- XHED: Title for consent given --> + <string name="submission_consent_view_consent_given">"Zgoda\nna „Ostrzeganie innych†udzielona"</string> + <!-- XHED: Title for consent NOT given --> + <string name="submission_consent_view_consent_not_given">"Brak zgody\nna „Ostrzeganie innychâ€"</string> + + <!-- Submission test result available --> + <!-- XHED: Page title for test results available step --> + <string name="submission_test_result_available_title">"Twój wynik testu jest dostÄ™pny"</string> + <!-- XACT: Test result available illustration description --> + <string name="submission_test_result_available_illustration_description">"Kobieta trzyma w dÅ‚oni smartfon, który wysyÅ‚a sygnaÅ‚ do innego smartfona."</string> + <!-- YTXT: Text for consent given --> + <string name="submission_test_result_available_text_consent_given">"DziÄ™kujemy za wyrażenie zgody na udostÄ™pnienie wyniku testu i pomoc w ostrzeganiu innych osób. \n\n"<b>"W nastÄ™pnym kroku udostÄ™pnij wynik testu, klikajÄ…c opcjÄ™ „UdostÄ™pnijâ€."</b></string> + <!-- XHED: Close screen popup title for consent given --> + <string name="submission_test_result_available_close_dialog_title_consent_given">"Czy chcesz anulować?"</string> + <!-- XTXT: Close screen popup text for consent given --> + <string name="submission_test_result_available_close_dialog_body_consent_given">"Twoje wpisy nie zostanÄ… zapisane."</string> + <!-- YTXT: Text for consent NOT given --> + <string name="submission_test_result_available_text_consent_not_given">"ZdecydowaÅ‚eÅ›(-aÅ›) siÄ™ nie udostÄ™pniać wyników testu. Inne osoby nie zostanÄ… ostrzeżone. \n\nW kolejnym kroku możesz zmienić zdanie i udostÄ™pnić wynik testu, aby powstrzymać rozprzestrzenianie siÄ™ koronawirusa i uchronić inne osoby przed zakażeniem."</string> + <!-- XHED: Close screen popup title for consent NOT given --> + <string name="submission_test_result_available_close_dialog_title_consent_not_given">"Ważne:\nTen proces zostanie anulowany.\nNie ostrzegÅ‚eÅ›(-aÅ›) jeszcze innych osób. UkoÅ„cz proces i pomóż chronić innych."</string> + <!-- XTXT: Close screen popup text for consent NOT given --> + <string name="submission_test_result_available_close_dialog_body_consent_not_given">"Czy na pewno chcesz anulować ten proces?"</string> + <!-- XBUT: Close screen popup cancel button --> + <string name="submission_test_result_available_close_dialog_cancel_button">"Anuluj"</string> + <!-- XBUT: Close screen popup continue button --> + <string name="submission_test_result_available_close_dialog_continue_button">"Kontynuuj"</string> + + <!-- Submission your consent screen --> + <!-- XHED: Your consent screen title --> + <string name="submission_your_consent_title">"Twoja zgoda"</string> + <!-- XTXT: Your consent screen switch label - next to a switch --> + <string name="submission_your_consent_switch_subtitle">"Ostrzegaj innych"</string> + <!-- XTXT: Your consent screen switch status on --> + <string name="submission_your_consent_switch_status_on">"Aktywne"</string> + <!-- XTXT: Your consent screen switch status off --> + <string name="submission_your_consent_switch_status_off">"Zatrzymane"</string> + <!-- XTXT: Your consent screen about agreement --> + <string name="submission_your_consent_about_agreement">"UdzieliÅ‚eÅ›(-aÅ›) nastÄ™pujÄ…cej zgody:"</string> + <!-- XHED: Your consent screen agreement title --> + <string name="submission_your_consent_agreement_title"><b>"Zgoda"</b></string> + <!-- XTXT: Your consent screen detailed information --> + <string name="submission_your_consent_agreement_details">"Szczegółowe informacje na temat przetwarzania danych i Twojej zgodzie"</string> <!-- #################################### Button Tooltips for Accessibility @@ -1215,8 +1332,6 @@ <!-- NOTR --> <string name="test_api_button_show_qr_code">"Show QR Code"</string> <!-- NOTR --> - <string name="test_api_button_submit_keys">"Submit keys to Server"</string> - <!-- NOTR --> <string name="test_api_button_scan_qr_code">"Scan Exposure Key"</string> <!-- NOTR --> <string name="test_api_switch_last_three_hours_from_server">"Last 3 Hours Mode"</string> @@ -1307,9 +1422,9 @@ <!-- XHED: Header of interoperability information/configuration view --> <string name="interoperability_configuration_title">"Rejestrowanie narażenia w różnych krajach"</string> <!-- XTXT: First section after the header of the interoperability information/configuration view --> - <string name="interoperability_configuration_first_section">"Wiele krajów współpracuje ze sobÄ… w celu aktywacji transgranicznych alertów wysyÅ‚anych poprzez wspólny serwer wymiany danych. Na przykÅ‚ad przy rejestrowaniu narażenia można wziąć pod uwagÄ™ również kontakty z użytkownikami oficjalnych aplikacji koronawirusowyych z innych uczestniczÄ…cych krajów."</string> + <string name="interoperability_configuration_first_section">"Kilka krajów współpracuje ze sobÄ… w zakresie aktywacji transgranicznych alertów wysyÅ‚anych poprzez wspólny serwer wymiany danych. Podczas rejestrowania narażenia można na przykÅ‚ad uwzglÄ™dniać również kontakty z użytkownikami oficjalnej aplikacji koronawirusowej z innych uczestniczÄ…cych krajów."</string> <!-- XTXT: Second section after the header of the interoperability information/configuration view --> - <string name="interoperability_configuration_second_section">"W tym celu aplikacja pobiera listÄ™, która jest aktualizowana codziennie, z losowymi identyfikatorami wszystkich użytkowników, którzy udostÄ™pnili swoje losowe identyfikatory poprzez wÅ‚asnÄ… aplikacjÄ™. Lista jest nastÄ™pnie porównywana z losowymi identyfikatorami zarejestrowanymi przez Twój smartfon. Codzienne pobieranie listy z losowymi identyfikatorami jest z reguÅ‚y bezpÅ‚atne – za dane używane przez aplikacjÄ™ w tym kontekÅ›cie nie bÄ™dÄ… pobierane opÅ‚aty roamingowe w innych krajach UE."</string> + <string name="interoperability_configuration_second_section">"W tym celu aplikacja pobiera aktualizowanÄ… codziennie listÄ™ losowych identyfikatorów wszystkich użytkowników, którzy udostÄ™pnili swoje wyniki testów za poÅ›rednictwem swojej aplikacji, aby ostrzegać innych. Lista ta jest nastÄ™pnie porównywana z losowymi identyfikatorami zarejestrowanymi przez Twój smartfon z systemem Android. Pobieranie listy jest zazwyczaj bezpÅ‚atne. Oznacza to, że operatorzy sieci komórkowych nie pobierajÄ… opÅ‚at za transmisjÄ™ danych używanych przez aplikacjÄ™ w tym celu ani też nie naliczajÄ… opÅ‚at roamingowych z tego tytuÅ‚u w innych krajach UE. Aby uzyskać wiÄ™cej informacji, skontaktuj siÄ™ ze swoim operatorem sieci komórkowej."</string> <!-- XHED: Header right above the country list in the interoperability information/configuration view --> <string name="interoperability_configuration_list_title">"NastÄ™pujÄ…ce kraje uczestniczÄ… obecnie w miÄ™dzynarodowym rejestrowaniu narażenia:"</string> <!-- XTXT: Text right under the country list in the interoperability information/configuration view --> @@ -1318,11 +1433,11 @@ <!-- XHED: Sub header introducing interoperability in the tracing step of onboarding --> <string name="interoperability_onboarding_title">"Rejestrowanie narażenia\nw różnych krajach"</string> <!-- YMSG: Onboarding tracing step first section in interoperability after the title --> - <string name="interoperability_onboarding_first_section">"Wiele krajów współpracuje w zakresie aktywowania miÄ™dzynarodowych ostrzeżeÅ„. Innymi sÅ‚owy, można teraz okreÅ›lić Twoje potencjalne narażenie wobec użytkowników oficjalnych aplikacji koronawirusowych we wszystkich uczestniczÄ…cych krajach."</string> + <string name="interoperability_onboarding_first_section">"Kilka krajów podjęło współpracÄ™ w zakresie aktywowania miÄ™dzynarodowych ostrzeżeÅ„. W rezultacie można teraz analizować potencjalne narażenie na kontakt z użytkownikami oficjalnych aplikacji koronawirusowych we wszystkich uczestniczÄ…cych krajach."</string> <!-- YMSG: Onboarding tracing step second section in interoperability after the title --> - <string name="interoperability_onboarding_second_section">"Gdy użytkownik przeÅ›le swój losowy identyfikator do serwera wymiany danych obsÅ‚ugiwanego wspólnie przez kraje uczestniczÄ…ce, o potencjalnym narażeniu mogÄ… zostać ostrzeżeni użytkownicy oficjalnych aplikacji koronawirusowych we wszystkich tych krajach."</string> + <string name="interoperability_onboarding_second_section">"Gdy użytkownik przeÅ›le swój pozytywny wynik testu (a dokÅ‚adniej losowy identyfikator) poprzez serwer wymiany danych obsÅ‚ugiwany wspólnie przez kraje uczestniczÄ…ce, aby ostrzec inne osoby, o potencjalnym narażeniu zostanÄ… ostrzeżeni użytkownicy oficjalnych aplikacji koronawirusowych we wszystkich tych krajach."</string> <!-- YMSG: Onboarding tracing step third section in interoperability after the title. --> - <string name="interoperability_onboarding_randomid_download_free">"Codzienne pobieranie listy z losowymi identyfikatorami jest z reguÅ‚y bezpÅ‚atne. Oznacza to, że operatorzy sieci mobilnych nie bÄ™dÄ… pobierać opÅ‚at za transmisjÄ™ danych używanych przez aplikacjÄ™ w tym kontekÅ›cie ani też nie bÄ™dÄ… naliczane opÅ‚aty roamingowe z tego tytuÅ‚u w innych krajach UE. Aby uzyskać wiÄ™cej informacji, skontaktuj siÄ™ ze swoim operatorem sieci mobilnej."</string> + <string name="interoperability_onboarding_randomid_download_free">"Codzienne pobieranie list losowych identyfikatorów użytkowników, którzy udostÄ™pnili pozytywne wyniki testów, jest z reguÅ‚y bezpÅ‚atne. Oznacza to, że operatorzy sieci komórkowych nie pobierajÄ… opÅ‚at za transmisjÄ™ danych używanych przez aplikacjÄ™ w tym celu ani też nie naliczajÄ… opÅ‚at roamingowych z tego tytuÅ‚u w innych krajach UE. Aby uzyskać wiÄ™cej informacji, skontaktuj siÄ™ ze swoim operatorem sieci komórkowej."</string> <!-- XTXT: Small header above the country list in the onboarding screen for interoperability. --> <string name="interoperability_onboarding_list_title">"Obecnie uczestniczÄ… nastÄ™pujÄ…ce kraje:"</string> @@ -1335,11 +1450,11 @@ <!-- XHED: Header of the delta onboarding screen for interoperability. If the user opens the app for the first time after the interoperability update --> <string name="interoperability_onboarding_delta_title">"Rejestrowanie narażenia\nw różnych krajach"</string> <!-- XTXT: Description of the interoperability extension of the app. Below interoperability_onboarding_delta_title --> - <string name="interoperability_onboarding_delta_subtitle">"Funkcje aplikacji Corona-Warn-App zostaÅ‚y rozszerzone. Wiele krajów poÅ‚Ä…czyÅ‚o siÅ‚y w celu aktywacji miÄ™dzynarodowych ostrzeżeÅ„, na podstawie wspólnie obsÅ‚ugiwanego serwera wymiany. Podczas oceny swojego ryzyka narażenia możesz teraz uwzglÄ™dnić narażenie na kontakt z użytkownikami oficjalnych aplikacji koronawirusowych w innych krajach uczestniczÄ…cych."</string> + <string name="interoperability_onboarding_delta_subtitle">"Funkcje aplikacji Corona-Warn-App zostaÅ‚y rozszerzone. Wiele krajów poÅ‚Ä…czyÅ‚o siÅ‚y w celu aktywacji miÄ™dzynarodowych ostrzeżeÅ„ przy wykorzystaniu wspólnie obsÅ‚ugiwanego serwera wymiany danych. Podczas oceny ryzyka narażenia można teraz uwzglÄ™dniać narażenie na kontakt z użytkownikami oficjalnych aplikacji koronawirusowych w innych krajach uczestniczÄ…cych."</string> <!-- YMSG: Onboarding tracing step third section in interoperability after the title. --> - <string name="interoperability_onboarding_delta_randomid">"W tym celu aplikacja pobiera aktualizowanÄ… codziennie listÄ™ losowych identyfikatorów wszystkich użytkowników, którzy udostÄ™pnili je za poÅ›rednictwem swojej aplikacji. Ta lista jest nastÄ™pnie porównywana z losowymi identyfikatorami zarejestrowanymi przez Twoje urzÄ…dzenie."</string> + <string name="interoperability_onboarding_delta_randomid">"W tym celu aplikacja pobiera aktualizowanÄ… codziennie listÄ™ losowych identyfikatorów wszystkich użytkowników, którzy udostÄ™pnili swoje wyniki testów za poÅ›rednictwem wÅ‚asnej aplikacji, aby ostrzegać innych. Lista ta jest nastÄ™pnie porównywana z losowymi identyfikatorami zarejestrowanymi przez Twój smartfonem z systemem Android."</string> <!-- YMSG: Onboarding tracing step third section in interoperability after the title. --> - <string name="interoperability_onboarding_delta_free_download">"Codzienne pobieranie listy z losowymi identyfikatorami jest z reguÅ‚y bezpÅ‚atne. Oznacza to, że operatorzy sieci mobilnych nie bÄ™dÄ… pobierać opÅ‚at za transmisjÄ™ danych używanych przez aplikacjÄ™ w tym kontekÅ›cie ani też nie bÄ™dÄ… naliczane opÅ‚aty roamingowe z tego tytuÅ‚u w innych krajach UE. Aby uzyskać wiÄ™cej informacji, skontaktuj siÄ™ ze swoim operatorem sieci mobilnej."</string> + <string name="interoperability_onboarding_delta_free_download">"Pobieranie listy jest z reguÅ‚y bezpÅ‚atne. Oznacza to, że operatorzy sieci komórkowych nie pobierajÄ… opÅ‚at za transmisjÄ™ danych używanych przez aplikacjÄ™ w tym celu ani też nie naliczajÄ… opÅ‚at roamingowych z tego tytuÅ‚u w innych krajach UE. Aby uzyskać wiÄ™cej informacji, skontaktuj siÄ™ ze swoim operatorem sieci komórkowej."</string> <!-- XACT: interoperability (eu) - illustraction description, explanation image --> <string name="interoperability_eu_illustration_description">"RÄ™ka trzyma smartfon. Europa i flaga europejska sÄ… przedstawione w tle."</string> @@ -1356,4 +1471,15 @@ <!-- XBUT: Title for the interoperability onboarding Settings-Button if no network is available --> <string name="interoperability_onboarding_list_button_title_no_network">"Otwórz ustawienia urzÄ…dzenia"</string> -</resources> + <!-- XHED: Title for the dialog on test result positive no consent screen --> + <string name="submission_test_result_positive_no_consent_dialog_title">"Nie chcesz wysÅ‚ać ostrzeżenia?"</string> + <!-- XTXT: Message for the dialog on test result positive no consent screen --> + <string name="submission_test_result_positive_no_consent_dialog_message">"Aby ostrzec inne osoby, musisz udostÄ™pnić swój wynik testu."</string> + <!-- XBUT: Positive button for the dialog on test result positive no consent screen --> + <string name="submission_test_result_positive_no_consent_dialog_positive_button">"Ostrzegaj innych"</string> + <!-- XBUT: Negative button for the dialog on test result positive no consent screen --> + <string name="submission_test_result_positive_no_consent_dialog_negative_button">"Nie ostrzegaj innych"</string> + <!-- XBUT: Abort button for test result positive no consent screen --> + <string name="submission_test_result_positive_no_consent_button_abort">"Anuluj"</string> + +</resources> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/values-ro/strings.xml b/Corona-Warn-App/src/main/res/values-ro/strings.xml index f85f705e22acb6da1c7b576fa9c994c6367f6118..c92d31fefaf4c00edbec89beb92fb2e317d93cb6 100644 --- a/Corona-Warn-App/src/main/res/values-ro/strings.xml +++ b/Corona-Warn-App/src/main/res/values-ro/strings.xml @@ -162,7 +162,7 @@ <string name="risk_card_low_risk_no_encounters_body">"Nicio expunere până acum"</string> <!-- XTXT: risk card - Low risk state - Days with low risk encounters --> <plurals name="risk_card_low_risk_encounter_days_body"> - <item quantity="one">"Expuneri cu risc redus în %1$d zi"</item> + <item quantity="one">"Expuneri cu risc redus într-o zi"</item> <item quantity="other">"Expuneri cu risc redus în %1$d de zile"</item> <item quantity="zero">"Expuneri cu risc redus în %1$d zile"</item> <item quantity="two">"Expuneri cu risc redus în %1$d zile"</item> @@ -174,7 +174,7 @@ <string name="risk_card_high_risk_no_encounters_body">"Nicio expunere până acum"</string> <!-- XTXT: risk card - High risk state - Days with high risk encounters --> <plurals name="risk_card_high_risk_encounter_days_body"> - <item quantity="one">"Expuneri cu risc crescut în %1$d zi"</item> + <item quantity="one">"Expuneri cu risc crescut într-o zi"</item> <item quantity="other">"Expuneri cu risc crescut în %1$d de zile"</item> <item quantity="zero">"Expuneri cu risc crescut în %1$d zile"</item> <item quantity="two">"Expuneri cu risc crescut în %1$d zile"</item> @@ -242,7 +242,7 @@ <!-- XHED: App overview subtitle for risk explanation --> <string name="main_overview_subtitle_risk">"Risc de infectare"</string> <!-- YTXT: App overview body text about risk levels --> - <string name="main_overview_body_risk">"Dacă în ultimele 14 zile aÈ›i intrat în contact cu o persoană care a fost diagnosticată cu COVID-19, aplicaÈ›ia calculează riscul dvs. personal de infectare. Face aceasta măsurând durata È™i proximitatea expunerii."</string> + <string name="main_overview_body_risk">"Dacă în ultimele 14 zile aÈ›i intrat în contact cu o persoană care a fost diagnosticată cu coronavirus, aplicaÈ›ia calculează riscul dvs. personal de infectare. Face aceasta măsurând durata È™i proximitatea expunerii."</string> <!-- XHED: App overview subtitle for risk level list --> <string name="main_overview_subtitle_risk_levels">"Poate fi afiÈ™ată următoarea stare a riscului:"</string> <!-- XTXT: App overview increased risk level --> @@ -254,7 +254,7 @@ <!-- XHED: App overview subtitle for test procedure explanation --> <string name="main_overview_headline_test">"Notificarea altor utilizatori"</string> <!-- YTXT: App overview body text about rest procedure --> - <string name="main_overview_body_test">"O altă caracteristică centrală este înregistrarea testului È™i primirea rezultatului. Dacă sunteÈ›i diagnosticat cu COVID-19, îi puteÈ›i notifica pe ceilalÈ›i È™i puteÈ›i întrerupe lanÈ›ul de infectare."</string> + <string name="main_overview_body_test">"O altă caracteristică centrală este înregistrarea testului È™i primirea rezultatului. Dacă sunteÈ›i diagnosticat cu coronavirus, îi puteÈ›i notifica pe ceilalÈ›i È™i puteÈ›i întrerupe lanÈ›ul de infectare."</string> <!-- XHED: App overview headline for glossary --> <string name="main_overview_headline_glossary">"DefiniÈ›ii ale termenilor:"</string> <!-- XHED: App overview subtitle for glossary key storage --> @@ -276,7 +276,7 @@ <!-- XHED: App overview subtitle for glossary keys --> <string name="main_overview_subtitle_glossary_keys">"ID aleatoriu"</string> <!-- YTXT: App overview body for glossary keys --> - <string name="main_overview_body_glossary_keys">"ID-urile aleatorii sunt combinaÈ›ii de cifre È™i litere generate aleatoriu. Acestea sunt schimbate între smartphone-urile aflate în proximitate strânsă. ID-urile aleatorii nu pot fi asociate cu o persoană anume È™i sunt È™terse automat după 14 zile. Persoanele diagnosticate cu COVID-19 pot opta să trimită ID-urile aleatorii din ultimele 14 zile È™i altor utilizatori ai aplicaÈ›iei."</string> + <string name="main_overview_body_glossary_keys">"ID-urile aleatorii sunt combinaÈ›ii de cifre È™i litere generate aleatoriu. Acestea sunt schimbate între smartphone-urile aflate în proximitate strânsă. ID-urile aleatorii nu pot fi asociate cu o persoană anume È™i sunt È™terse automat după 14 zile. Persoanele diagnosticate cu coronavirus pot opta să trimită ID-urile aleatorii din ultimele 14 zile È™i altor utilizatori ai aplicaÈ›iei."</string> <!-- XACT: main (overview) - illustraction description, explanation image --> <string name="main_overview_illustration_description">"Un smartphone afiÈ™ează conÈ›inut variat, numerotat de la 1 la 3."</string> <!-- XACT: App main page title --> @@ -293,11 +293,11 @@ <!-- XHED: risk details - subtitle for additional info in case of encounter with low risk --> <string name="risk_details_additional_info_subtitle">"De ce riscul dvs. de infectare este redus"</string> <!-- XHED: risk details - text for additional info in case of encounter with low risk --> - <string name="risk_details_additional_info_text">"AÈ›i avut o întâlnire cu o persoană diagnosticată cu COVID-19. TotuÈ™i, pe baza datelor de înregistrare în jurnal a expunerilor, riscul dvs. de infectare este redus. Riscul este redus dacă întâlnirea dvs. a fost de scurtă durată sau s-a păstrat o anumită distanță. Nu este cazul să vă îngrijoraÈ›i È™i nu este nevoie de nicio acÈ›iune specială din partea dvs. Vă recomandăm să respectaÈ›i regulile generale privind distanÈ›area È™i igiena."</string> + <string name="risk_details_additional_info_text">"AÈ›i avut o întâlnire cu o persoană diagnosticată cu coronavirus. TotuÈ™i, pe baza datelor de înregistrare în jurnal a expunerilor, riscul dvs. de infectare este redus. Riscul este redus dacă întâlnirea dvs. a fost de scurtă durată sau s-a păstrat o anumită distanță. Nu este cazul să vă îngrijoraÈ›i È™i nu este nevoie de nicio acÈ›iune specială din partea dvs. Vă recomandăm să respectaÈ›i regulile generale privind distanÈ›area È™i igiena."</string> <!-- XHED: risk details - headline, how a user should act --> <string name="risk_details_headline_behavior">"InstrucÈ›iuni"</string> <!-- XHED: risk details - multiline headline, bold, how to act correct --> - <string name="risk_details_subtitle_behavior">"Iată ce trebuie să faceÈ›i"</string> + <string name="risk_details_subtitle_behavior">"Iată ce trebuie să faceÈ›i:"</string> <!-- XMSG: risk details - go/stay home, something like a bullet point --> <string name="risk_details_behavior_body_stay_home">"Dacă este posibil, mergeÈ›i acasă È™i rămâneÈ›i în casă."</string> <!-- XMSG: risk details - get in touch with the corresponding people, something like a bullet point --> @@ -325,7 +325,7 @@ <!-- XHED: risk details - infection period logged information body, below behaviors --> <string name="risk_details_information_body_period_logged">"Riscul dvs. de infectare poate fi calculat doar pentru perioadele în care a fost activă înregistrarea în jurnal a expunerilor. Prin urmare, caracteristica de înregistrare în jurnal trebuie să rămână permanent activă."</string> <!-- XHED: risk details - infection period logged information body, below behaviors --> - <string name="risk_details_information_body_period_logged_assessment">"ÃŽnregistrarea în jurnal a expunerilor acoperă ultimele 14 zile. ÃŽn această perioadă, caracteristica de înregistrare în jurnal de pe smartphone-ul dvs. a fost activă timp de %1$s (de) zile. AplicaÈ›ia È™terge automat înregistrările mai vechi din jurnal, întrucât acestea nu mai sunt relevante pentru prevenirea infectării."</string> + <string name="risk_details_information_body_period_logged_assessment">"ÃŽnregistrarea în jurnal a expunerilor acoperă ultimele 14 zile. ÃŽn această perioadă, caracteristica de înregistrare în jurnal de pe smartphone-ul dvs. a fost activă timp de %1$s zile. AplicaÈ›ia È™terge automat înregistrările mai vechi din jurnal, întrucât acestea nu mai sunt relevante pentru prevenirea infectării."</string> <!-- XHED: risk details - how your risk level was calculated, below behaviors --> <string name="risk_details_subtitle_infection_risk_past">"Modul în care a fost calculat riscul dvs."</string> <!-- XHED: risk details - how your risk level will be calculated, below behaviors --> @@ -333,17 +333,17 @@ <!-- XMSG: risk details - risk calculation wasn't possible for 24h, below behaviors --> <string name="risk_details_information_body_outdated_risk">"ÃŽnregistrarea în jurnal a expunerilor dvs. nu a putut fi actualizată timp de peste 24 de ore."</string> <!-- YTXT: risk details - low risk explanation text --> - <string name="risk_details_information_body_low_risk">"AveÈ›i un risc redus de infectare deoarece nu a fost înregistrată nicio expunere la persoane diagnosticate ulterior cu COVID-19 sau întâlnirile dvs. au fost limitate la o perioadă scurtă È™i la o distanță mai mare."</string> + <string name="risk_details_information_body_low_risk">"AveÈ›i un risc redus de infectare deoarece nu a fost înregistrată nicio expunere la persoane diagnosticate ulterior cu coronavirus sau întâlnirile dvs. au fost limitate la o perioadă scurtă È™i la o distanță mai mare."</string> <!-- YTXT: risk details - low risk explanation text with encounter with low risk --> - <string name="risk_details_information_body_low_risk_with_encounter">"Riscul de infectare este calculat local pe smartphone-ul dvs., utilizând datele de înregistrare în jurnal a expunerilor. Calculul poate È›ine cont È™i de distanÈ›a È™i durata expunerii la persoane diagnosticate cu COVID-19, precum È™i de potenÈ›iala contagiozitate a acestora. Riscul dvs. de infectare nu poate fi observat sau transmis mai departe niciunei alte persoane."</string> + <string name="risk_details_information_body_low_risk_with_encounter">"Riscul de infectare este calculat local pe smartphone-ul dvs., utilizând datele de înregistrare în jurnal a expunerilor. Calculul poate È›ine cont È™i de distanÈ›a È™i durata expunerii la persoane diagnosticate cu coronavirus, precum È™i de potenÈ›iala contagiozitate a acestora. Riscul dvs. de infectare nu poate fi observat sau transmis mai departe niciunei alte persoane."</string> <!-- YTXT: risk details - increased risk explanation text with variable for day(s) since last contact --> <plurals name="risk_details_information_body_increased_risk"> - <item quantity="one">"AveÈ›i un risc crescut de infectare deoarece aÈ›i fost expus ultima dată acum %1$s zi pe o perioadă mai lungă de timp È™i în strânsă proximitate cu cel puÈ›in o persoană diagnosticată cu COVID-19."</item> - <item quantity="other">"AveÈ›i un risc crescut de infectare deoarece aÈ›i fost expus ultima dată acum %1$s de zile pe o perioadă mai lungă de timp È™i în strânsă proximitate cu cel puÈ›in o persoană diagnosticată cu COVID-19."</item> - <item quantity="zero">"AveÈ›i un risc crescut de infectare deoarece aÈ›i fost expus ultima dată acum %1$s zile pe o perioadă mai lungă de timp È™i în strânsă proximitate cu cel puÈ›in o persoană diagnosticată cu COVID-19."</item> - <item quantity="two">"AveÈ›i un risc crescut de infectare deoarece aÈ›i fost expus ultima dată acum %1$s zile pe o perioadă mai lungă de timp È™i în strânsă proximitate cu cel puÈ›in o persoană diagnosticată cu COVID-19."</item> - <item quantity="few">"AveÈ›i un risc crescut de infectare deoarece aÈ›i fost expus ultima dată acum %1$s zile pe o perioadă mai lungă de timp È™i în strânsă proximitate cu cel puÈ›in o persoană diagnosticată cu COVID-19."</item> - <item quantity="many">"AveÈ›i un risc crescut de infectare deoarece aÈ›i fost expus ultima dată acum %1$s zile pe o perioadă mai lungă de timp È™i în strânsă proximitate cu cel puÈ›in o persoană diagnosticată cu COVID-19."</item> + <item quantity="one">"AveÈ›i un risc crescut de infectare deoarece aÈ›i fost expus ultima dată acum %1$s zi pe o perioadă mai lungă de timp È™i în strânsă proximitate cu cel puÈ›in o persoană diagnosticată cu coronavirus."</item> + <item quantity="other">"AveÈ›i un risc crescut de infectare deoarece aÈ›i fost expus ultima dată acum %1$s de zile pe o perioadă mai lungă de timp È™i în strânsă proximitate cu cel puÈ›in o persoană diagnosticată cu coronavirus."</item> + <item quantity="zero">"AveÈ›i un risc crescut de infectare deoarece aÈ›i fost expus ultima dată acum %1$s zile pe o perioadă mai lungă de timp È™i în strânsă proximitate cu cel puÈ›in o persoană diagnosticată cu coronavirus."</item> + <item quantity="two">"AveÈ›i un risc crescut de infectare deoarece aÈ›i fost expus ultima dată acum %1$s zile pe o perioadă mai lungă de timp È™i în strânsă proximitate cu cel puÈ›in o persoană diagnosticată cu coronavirus."</item> + <item quantity="few">"AveÈ›i un risc crescut de infectare deoarece aÈ›i fost expus ultima dată acum %1$s zile pe o perioadă mai lungă de timp È™i în strânsă proximitate cu cel puÈ›in o persoană diagnosticată cu coronavirus."</item> + <item quantity="many">"AveÈ›i un risc crescut de infectare deoarece aÈ›i fost expus ultima dată acum %1$s zile pe o perioadă mai lungă de timp È™i în strânsă proximitate cu cel puÈ›in o persoană diagnosticată cu coronavirus."</item> </plurals> <!-- YTXT: risk details - risk calculation explanation --> <string name="risk_details_information_body_notice">"Riscul dvs. de infectare este calculat pe baza datelor de înregistrare în jurnal a expunerilor (durata È™i proximitatea) la nivel local pe smartphone-ul dvs. Riscul dvs. de infectare nu poate fi văzut de o altă persoană sau transmis unei alte persoane."</string> @@ -404,7 +404,7 @@ <!-- XHED: onboarding(together) - two/three line headline under an illustration --> <string name="onboarding_subtitle">"Mai multă protecÈ›ie pentru dvs. È™i pentru noi toÈ›i. Utilizând Corona-Warn-App putem întrerupe mai uÈ™or lanÈ›ul de infectare."</string> <!-- YTXT: onboarding(together) - inform about the app --> - <string name="onboarding_body">"TransformaÈ›i-vă smartphone-ul într-un sistem de avertizare împotriva coronavirusului. ObÈ›ineÈ›i un sumar al stării de risc È™i aflaÈ›i dacă aÈ›i intrat în contact strâns cu persoane diagnosticate cu COVID-19 în ultimele 14 zile."</string> + <string name="onboarding_body">"TransformaÈ›i-vă smartphone-ul într-un sistem de avertizare împotriva coronavirusului. ObÈ›ineÈ›i un sumar al stării de risc È™i aflaÈ›i dacă aÈ›i intrat în contact strâns cu persoane diagnosticate cu coronavirus în ultimele 14 zile."</string> <!-- YTXT: onboarding(together) - explain application --> <string name="onboarding_body_emphasized">"AplicaÈ›ia înregistrează în jurnal întâlnirile dintre persoane prin smartphone-urile acestora, care schimbă ID-uri aleatorii criptate, fără a accesa niciun fel de date personale."</string> <!-- XACT: onboarding(together) - illustraction description, header image --> @@ -421,9 +421,9 @@ <!-- XHED: onboarding(tracing) - how to enable tracing --> <string name="onboarding_tracing_headline">"Cum se activează înregistrarea în jurnal a expunerilor"</string> <!-- XHED: onboarding(tracing) - two/three line headline under an illustration --> - <string name="onboarding_tracing_subtitle">"Pentru a identifica dacă sunteÈ›i supus riscului de infectare, trebuie să activaÈ›i caracteristica de înregistrare în jurnal a expunerilor."</string> + <string name="onboarding_tracing_subtitle">"Pentru a identifica dacă sunteÈ›i supus riscului de infectare, trebuie să activaÈ›i înregistrarea în jurnal a expunerilor."</string> <!-- YTXT: onboarding(tracing) - explain tracing --> - <string name="onboarding_tracing_body">"ÃŽnregistrarea în jurnal a expunerilor funcÈ›ionează astfel: smartphone-ul dvs. primeÈ™te prin Bluetooth ID-uri aleatorii criptate ale altor utilizatori È™i transmite propriile dvs. ID-uri aleatorii către smartphone-urile acestora. ÃŽnregistrarea în jurnal a expunerilor poate fi oricând dezactivată. "</string> + <string name="onboarding_tracing_body">"ÃŽnregistrarea în jurnal a expunerilor funcÈ›ionează astfel: smartphone-ul dvs. Android primeÈ™te prin Bluetooth ID-uri aleatorii criptate ale altor utilizatori È™i transmite propriile dvs. ID-uri aleatorii către smartphone-urile acestora. ÃŽnregistrarea în jurnal a expunerilor poate fi oricând dezactivată. "</string> <!-- YTXT: onboarding(tracing) - explain tracing --> <string name="onboarding_tracing_body_emphasized">"ID-urile aleatorii criptate transmit informaÈ›ii doar despre dată, durată È™i proximitatea față de alte persoane (calculată prin intensitatea semnalului). Nu se pot identifica persoane individuale pe baza ID-urilor aleatorii."</string> <!-- YTXT: onboarding(tracing) - easy language explain tracing link--> @@ -471,9 +471,9 @@ <!-- XBUT: onboarding(tracing) - button enable tracing --> <string name="onboarding_tracing_location_button">"DeschideÈ›i configurările dispozitivului"</string> <!-- XACT: Onboarding (test) page title --> - <string name="onboarding_test_accessibility_title">"Pagina de înregistrare 5 din 6: Dacă sunteÈ›i diagnosticat cu COVID-19"</string> + <string name="onboarding_test_accessibility_title">"Pagina de înregistrare 5 din 6: Dacă sunteÈ›i diagnosticat cu coronavirus"</string> <!-- XHED: onboarding(test) - about positive tests --> - <string name="onboarding_test_headline">"Dacă sunteÈ›i diagnosticat cu COVID-19…"</string> + <string name="onboarding_test_headline">"Dacă sunteÈ›i diagnosticat cu coronavirus…"</string> <!-- XHED: onboarding(test) - two/three line headline under an illustration --> <string name="onboarding_test_subtitle">"… vă rugăm să raportaÈ›i acest lucru în Corona-Warn-App. ÃŽmpărtășirea rezultatului testului este voluntară È™i securizată. Vă rugăm să faceÈ›i acest lucru pentru binele celorlalÈ›i."</string> <!-- YTXT: onboarding(test) - explain test --> @@ -496,7 +496,7 @@ ###################################### --> <!-- XACT: onboarding(sixteen) title --> - <string name="sixteen_title_text">"Limita de vârstă: începând cu 16 ani"</string> + <string name="sixteen_title_text">"Avertizare: peste 16 ani"</string> <!-- XACT: onboarding(sixteen) title --> <string name="sixteen_description_text">"Utilizarea acestei aplicaÈ›ii este destinată persoanelor care au vârsta de cel puÈ›in 16 ani È™i care locuiesc în Germania."</string> @@ -525,7 +525,7 @@ <!-- XTXT: settings(tracing) - shows status under header in home, inactive location --> <string name="settings_tracing_body_inactive_location">"Serviciile de localizare au fost dezactivate"</string> <!-- YTXT: settings(tracing) - explains tracings --> - <string name="settings_tracing_body_text">"Trebuie să activaÈ›i caracteristica de înregistrare în jurnal a expunerilor, pentru ca aplicaÈ›ia să poată determina dacă aveÈ›i risc de infectare după ce aÈ›i întâlnit un utilizator al aplicaÈ›iei care este infectat. Caracteristica de înregistrare în jurnal a expunerilor funcÈ›ionează la nivel transnaÈ›ional, ceea ce înseamnă că orice expunere posibilă care îi implică pe utilizatori este detectată È™i de alte aplicaÈ›ii oficiale împotriva coronavirusului.\n\nCaracteristica de înregistrare în jurnal a expunerilor funcÈ›ionează astfel: smartphone-ul dvs. primeÈ™te prin Bluetooth ID-uri aleatorii criptate ale altor utilizatori È™i transmite propriul dvs. ID aleatoriu către smartphone-urile acestora. ÃŽn fiecare zi, aplicaÈ›ia descarcă o listă ce conÈ›ine ID-uri aleatorii – împreună cu orice alte informaÈ›ii voluntare despre debutul simptomelor – ale tuturor utilizatorilor testaÈ›i pozitiv la virus È™i care au împărtășit voluntar aceste informaÈ›ii prin aplicaÈ›ia lor. Apoi, lista este comparată cu ID-urile aleatorii ale altor utilizatori care au fost înregistrate de smartphone-ul dvs., pentru a calcula probabilitatea ca È™i dvs. să fi fost infectat È™i să vă avertizeze dacă este necesar. PuteÈ›i utiliza comutatorul pentru a dezactiva în orice moment înregistrarea în jurnal a expunerilor.\n\nAplicaÈ›ia nu colectează niciodată date personale, precum numele, adresa sau locaÈ›ia dvs., iar aceste informaÈ›ii nu sunt transmise niciodată altor utilizatori. Nu se pot utiliza ID-urile aleatorii pentru a trage concluzii despre persoane individuale."</string> + <string name="settings_tracing_body_text">"Trebuie să activaÈ›i caracteristica de înregistrare în jurnal a expunerilor, pentru ca aplicaÈ›ia să poată determina dacă aveÈ›i risc de infectare după ce aÈ›i întâlnit un utilizator al aplicaÈ›iei care este infectat. Caracteristica de înregistrare în jurnal a expunerilor funcÈ›ionează la nivel transnaÈ›ional, ceea ce înseamnă că orice expunere posibilă care îi implică pe utilizatori este detectată È™i de alte aplicaÈ›ii oficiale împotriva coronavirusului.\n\nCaracteristica de înregistrare în jurnal a expunerilor funcÈ›ionează astfel: smartphone-ul dvs. Android primeÈ™te prin Bluetooth ID-uri aleatorii criptate ale altor utilizatori È™i transmite propriul dvs. ID aleatoriu către smartphone-urile acestora. ÃŽn fiecare zi, aplicaÈ›ia descarcă o listă ce conÈ›ine ID-uri aleatorii – împreună cu orice alte informaÈ›ii voluntare despre debutul simptomelor – ale tuturor utilizatorilor testaÈ›i pozitiv la virus È™i care au împărtășit voluntar aceste informaÈ›ii (mai exact: ID-urile lor aleatorii) prin intermediul aplicaÈ›iei lor. Apoi, lista este comparată cu ID-urile aleatorii ale altor utilizatori cu care v-aÈ›i întâlnit care au fost înregistrate de smartphone-ul dvs. Android, pentru a calcula probabilitatea ca È™i dvs. să fi fost infectat È™i să vă avertizeze dacă este necesar. PuteÈ›i utiliza comutatorul pentru a dezactiva în orice moment înregistrarea în jurnal a expunerilor.\n\nAplicaÈ›ia nu colectează niciodată date personale, precum numele, adresa sau locaÈ›ia dvs., iar aceste informaÈ›ii nu sunt transmise niciodată altor utilizatori. Nu se pot utiliza ID-urile aleatorii pentru a trage concluzii despre persoane individuale."</string> <!-- XTXT: settings(tracing) - status next to switch under title --> <string name="settings_tracing_status_active">"Activ"</string> <!-- XTXT: settings(tracing) - status next to switch under title --> @@ -595,7 +595,7 @@ <!-- XTXT: settings(notification) - next to a switch --> <string name="settings_notifications_subtitle_update_risk">"Riscul dvs. de infectare s-a modificat"</string> <!-- XTXT: settings(notification) - next to a switch --> - <string name="settings_notifications_subtitle_update_test">"Starea testului COVID-19"</string> + <string name="settings_notifications_subtitle_update_test">"Starea testului dvs. coronavirus"</string> <!-- XBUT: settings(notification) - go to operating settings --> <string name="settings_notifications_button_open_settings">"DeschideÈ›i configurările dispozitivului"</string> <!-- XACT: main (overview) - illustraction description, explanation image, displays notificatin status, active --> @@ -604,7 +604,7 @@ <string name="settings_notifications_illustration_description_inactive">"O femeie a dezactivat notificările pentru Corona-Warn-App."</string> <!-- XBUT: settings - go to reset application --> <string name="settings_reset_title">"ResetaÈ›i aplicaÈ›ia"</string> - <!-- XTXT: settings(reset) - explains the user what do expect when he navigates to reset --> + <!-- XTXT: settings(reset) - explains the user what do expect when navigating to reset --> <string name="settings_reset_body_description">"ȘtergeÈ›i toate datele dvs. din aplicaÈ›ie."</string> <!-- XHED: settings(reset) - multiline headline below illustration --> <string name="settings_reset_headline">"Sigur doriÈ›i să resetaÈ›i aplicaÈ›ia?"</string> @@ -660,7 +660,7 @@ <!-- YTXT: Body text for about information page --> <string name="information_about_body_emphasized">"Robert Koch Institute (RKI) este un organism federal de sănătate publică din Germania. RKI a publicat aplicaÈ›ia Corona-Warn în numele Guvernului Federal. AplicaÈ›ia are drept scop să completeze sub formă digitală măsurile de sănătate publică deja introduse: distanÈ›area socială, igiena È™i purtarea măștii."</string> <!-- YTXT: Body text for about information page --> - <string name="information_about_body">"Persoanele care utilizează aplicaÈ›ia ajută la urmărirea È™i întreruperea lanÈ›urilor de infectare. AplicaÈ›ia salvează local, pe dispozitivul dvs., întâlnirile cu alte persoane. SunteÈ›i notificat dacă aÈ›i întâlnit persoane care au fost diagnosticate ulterior cu COVID-19. Identitatea È™i confidenÈ›ialitatea dvs. sunt protejate întotdeauna."</string> + <string name="information_about_body">"Persoanele care utilizează aplicaÈ›ia ajută la urmărirea È™i întreruperea lanÈ›urilor de infectare. AplicaÈ›ia salvează local, pe dispozitivul dvs., întâlnirile cu alte persoane. SunteÈ›i notificat dacă aÈ›i întâlnit persoane care au fost diagnosticate ulterior cu coronavirus. Identitatea È™i confidenÈ›ialitatea dvs. sunt protejate întotdeauna."</string> <!-- XACT: describes illustration --> <string name="information_about_illustration_description">"Un grup de persoane își utilizează smartphone-urile prin oraÈ™."</string> <!-- XHED: Page title for privacy information page, also menu item / button text --> @@ -754,7 +754,7 @@ <!-- XHED: Dialog title for already paired test error: qr --> <string name="submission_error_dialog_web_test_paired_title">"Codul QR este nevalabil"</string> <!-- XMSG: Dialog body for already paired test error: qr --> - <string name="submission_error_dialog_web_test_paired_body">"Codul QR este nevalabil sau a fost deja înregistrat pe un alt smartphone. VeÈ›i primi rezultatul testului dvs. de la centrul sau laboratorul de testare, indiferent de valabilitatea codului QR. Dacă sunteÈ›i diagnosticat cu COVID-19, veÈ›i fi notificat de autoritatea de sănătate publică."</string> + <string name="submission_error_dialog_web_test_paired_body">"Codul QR este nevalabil sau a fost deja înregistrat pe un alt smartphone. VeÈ›i primi rezultatul testului dvs. de la centrul sau laboratorul de testare, indiferent de valabilitatea codului QR. Dacă sunteÈ›i diagnosticat cu coronavirus, veÈ›i fi notificat de autoritatea de sănătate publică."</string> <!-- XHED: Dialog title for already paired test error: tan --> <string name="submission_error_dialog_web_test_paired_title_tan">"TAN-ul este nevalabil"</string> <!-- XMSG: Dialog body for already paired test via tan - error: tan --> @@ -784,9 +784,9 @@ <string name="submission_error_dialog_web_tan_redeemed_button_positive">"OK"</string> <!-- XHED: Dialog title for keys submission process cancellation --> - <string name="submission_error_dialog_confirm_cancellation_title">"DoriÈ›i să anulaÈ›i?"</string> + <string name="submission_error_dialog_confirm_cancellation_title">"DoriÈ›i să anulaÈ›i introducerea simptomelor dvs.?"</string> <!-- XMSG: Dialog body for keys submission process cancellation --> - <string name="submission_error_dialog_confirm_cancellation_body">"Intrările dvs. nu vor fi salvate."</string> + <string name="submission_error_dialog_confirm_cancellation_body">"Dacă furnizaÈ›i informaÈ›ii despre simptomele dvs., îi puteÈ›i avertiza pe ceilalÈ›i într-un mod mai exact."</string> <!-- XBUT: Positive button for keys submission process cancellation --> <string name="submission_error_dialog_confirm_cancellation_button_positive">"Da"</string> <!-- XBUT: Negative button for keys submission process cancellation --> @@ -814,7 +814,7 @@ <!-- XHED: Dialog headline for invalid QR code --> <string name="submission_qr_code_scan_invalid_dialog_headline">"Codul QR este nevalabil"</string> <!-- YTXT: Dialog Body text for invalid QR code --> - <string name="submission_qr_code_scan_invalid_dialog_body">"Codul QR este nevalabil sau a fost deja înregistrat pe un alt smartphone. VeÈ›i primi rezultatul testului dvs. de la centrul sau laboratorul de testare, indiferent de valabilitatea codului QR. Dacă sunteÈ›i diagnosticat cu COVID-19, direcÈ›ia de sănătate publică va fi notificată prin canalul de comunicare prevăzut în mod legal È™i vă va contacta."</string> + <string name="submission_qr_code_scan_invalid_dialog_body">"Codul QR este nevalabil sau a fost deja înregistrat pe un alt smartphone. VeÈ›i primi rezultatul testului dvs. de la centrul sau laboratorul de testare, indiferent de valabilitatea codului QR. Dacă sunteÈ›i diagnosticat cu coronavirus, direcÈ›ia de sănătate publică va fi notificată prin canalul de comunicare prevăzut în mod legal È™i vă va contacta."</string> <!-- XBUT: Dialog(Invalid QR code) - positive button (right) --> <string name="submission_qr_code_scan_invalid_dialog_button_positive">"ReîncercaÈ›i."</string> <!-- XBUT: Dialog(Invalid QR code) - negative button (left) --> @@ -825,6 +825,34 @@ <!-- YTXT: instruction text for QR code scanning --> <string name="submission_qr_code_scan_body">"PoziÈ›ionaÈ›i codul QR în cadru."</string> + <!-- QR Code Consent Screen --> + <!-- XHED: Page headline for Submission consent --> + <string name="submission_consent_main_headline">"Consimțământul dvs."</string> + <!-- YTXT: Body for Submissionconsent --> + <string name="submission_consent_main_headline_body">"Consimțământul dvs. este necesar înainte de a putea regăsi rezultatul testului dvs. È™i a-i avertiza pe ceilalÈ›i."</string> + <!-- XHED: Page subheadline for consent call test result --> + <string name="submission_consent_call_test_result">"Aflarea rezultatului testului"</string> + <!-- YTXT: Body for Submission Consent call test result body --> + <string name="submission_consent_call_test_result_body">"La pasul următor, scanaÈ›i codul QR de pe testul dvs. È™i aflaÈ›i rezultatul testului."</string> + <!-- YTXT: Body sub text 1 for Submission Consent call test result --> + <string name="submission_consent_call_test_result_scan_your_test_only">"ScanaÈ›i doar codul propriului dvs. test."</string> + <!-- YTXT: Body sub text 2 for Submission Consent call test result --> + <string name="submission_consent_call_test_result_scan_test_only_once">"Testul dvs. poate fi scanat o singură dată. AplicaÈ›ia nu poate gestiona mai multe teste simultan."</string> + <!-- XHED: Page subheadline for consent help by warning others --> + <string name="submission_consent_help_by_warning_others_headline">"Vă rugăm să îi ajutaÈ›i pe ceilalÈ›i cu care v-aÈ›i întâlnit, avertizându-i!"</string> + <!-- YTXT: Body for consent help by warning others --> + <string name="submission_consent_help_by_warning_others_body">"Dacă aÈ›i fost diagnosticat cu coronavirus, puteÈ›i să îi avertizaÈ›i pe ceilalÈ›i prin intermediul aplicaÈ›iei. FuncÈ›ia de avertizare funcÈ›ionează în câteva țări. Următoarele țări participă în prezent:"</string> + <!-- YTXT: Page bottom text for consent screen --> + <string name="submission_consent_main_bottom_body">"InformaÈ›ii detaliate privind Prelucrarea datelor È™i Consimțământul dvs."</string> + <!-- YTXT: Body for consent main section first point --> + <string name="submission_consent_main_first_point">"Consimțământul dvs. este voluntar."</string> + <!-- YTXT: Body for consent main section second point --> + <string name="submission_consent_main_second_point">"PuteÈ›i afla rezultatul testului dvs. chiar dacă nu alegeÈ›i să îl partajaÈ›i. Dar dacă partajaÈ›i rezultatul testului dvs., vă vom ajuta să îi protejaÈ›i pe ceilalÈ›i împotriva infecÈ›iei."</string> + <!-- YTXT: Body for consent main section third point --> + <string name="submission_consent_main_third_point">"Identitatea dvs. va rămâne secretă. AlÈ›i utilizatori nu vor È™ti cine a partajat rezultatele testelor respective."</string> + <!-- YTXT: Body for consent main section fourth point --> + <string name="submission_consent_main_fourth_point">"Trebuie să aveÈ›i cel puÈ›in 16 ani pentru a vă acorda consimțământul."</string> + <!-- Submission Test Result --> <!-- XHED: Page headline for test result --> <string name="submission_test_result_headline">"Rezultat test"</string> @@ -835,9 +863,9 @@ <!-- YTXT: Body text for for results next steps --> <string name="submission_test_result_steps_added_body">"Testul dvs. a fost stocat în Corona-Warn-App."</string> <!-- XHED: Page headline for pending test result next steps --> - <string name="submission_test_result_pending_steps_waiting_heading">"Rezultatul testului nu este încă disponibil"</string> + <string name="submission_test_result_pending_steps_waiting_heading">"Rezultatul testului dvs. nu este încă disponibil."</string> <!-- YTXT: Body text for next steps section of waiting test result page --> - <string name="submission_test_result_pending_steps_waiting_body">"Vă rugăm să aveÈ›i răbdare, deoarece evaluarea poate dura câteva zile.\n\nDe asemenea, veÈ›i primi rezultatul testului în afara aplicaÈ›iei. Autoritățile de sănătate publică vă vor anunÈ›a dacă testul dvs. este pozitiv.\n\nÃŽn cazul unui rezultat pozitiv, apelaÈ›i numărul indicat la „Solicitare TAN†pentru a vă înregistra rezultatul în aplicaÈ›ie È™i pentru a-i avertiza pe ceilalÈ›i."</string> + <string name="submission_test_result_pending_steps_waiting_body">"Imediat ce devine disponibil, rezultatul testului dvs. va fi afiÈ™at în aplicaÈ›ie."</string> <!-- XBUT: test result pending : refresh button --> <string name="submission_test_result_pending_refresh_button">"Actualizare"</string> <!-- XBUT: test result pending : remove the test button --> @@ -873,7 +901,7 @@ <!-- XHED: Dialog title for test removal --> <string name="submission_test_result_dialog_remove_test_title">"Testul poate fi scanat o singură dată."</string> <!-- YTXT: Dialog text for test removal --> - <string name="submission_test_result_dialog_remove_test_message">"Dacă eliminaÈ›i testul, nu veÈ›i mai putea afla rezultatul testului. VeÈ›i primi rezultatul testului dvs. de la centrul sau laboratorul de testare, indiferent de valabilitatea codului QR. Dacă sunteÈ›i diagnosticat cu COVID-19, direcÈ›ia de sănătate publică va fi notificată prin canalul de comunicare prevăzut în mod legal È™i vă va contacta."</string> + <string name="submission_test_result_dialog_remove_test_message">"Dacă eliminaÈ›i testul, nu veÈ›i mai putea afla rezultatul testului. VeÈ›i primi rezultatul testului dvs. de la centrul sau laboratorul de testare, indiferent de valabilitatea codului QR. Dacă sunteÈ›i diagnosticat cu coronavirus, direcÈ›ia de sănătate publică va fi notificată prin canalul de comunicare prevăzut în mod legal È™i vă va contacta."</string> <!-- XBUT: Positive button for test removal --> <string name="submission_test_result_dialog_remove_test_button_positive">"Eliminare"</string> <!-- XBUT: Negative button for test removal --> @@ -882,6 +910,16 @@ <string name="submission_test_result_card_positive_title">"Pozitiv la SARS-CoV-2"</string> <!-- YTXT: Body text for test result card positive --> <string name="submission_test_result_card_positive_body">"AÈ›i fost diagnosticat cu virusul SARS-CoV-2."</string> + <!-- XHED: Page headline for test result with consent given --> + <string name="submission_test_result_consent_given_heading">"Rezultatul testului dvs."</string> + <!-- XHED: Subtitle text for test result card with consent given --> + <string name="submission_test_result_consent_given_subtitle">"Vă mulÈ›umim pentru ajutorul dat la oprirea răspândirii coronavirusului."</string> + <!-- YTXT: body text for test result card with consent given --> + <string name="submission_test_result_consent_given_body"><b>"Alte persoane cu care aÈ›i avut contact vor fi acum avertizate."</b>" "<br/><br/>"Acum puteÈ›i ajuta la îmbunătățirea preciziei avertizărilor. Pentru aceasta, la pasul următor, spuneÈ›i-ne când aÈ›i dezvoltat simptome pentru prima dată. PuteÈ›i anula acest pas în orice moment."</string> + <!-- XBUT: button text for the 'break up' button option on test result consent given page --> + <string name="submission_test_result_consent_given_breakup_button">"IeÈ™ire"</string> + + <!-- Submission Tan --> <!-- XHED: Page title for TAN submission pge --> @@ -903,7 +941,7 @@ <!-- XHED: Page headline for menu the at start of the submission process --> <string name="submission_intro_headline">"Modul în care funcÈ›ionează Corona-Warn-App"</string> <!-- YTXT: submission introduction text --> - <string name="submission_intro_text">"Pentru ca aplicaÈ›ia să funcÈ›ioneze bine, ne bazăm pe susÈ›inerea persoanelor care au fost diagnosticate cu COVID-19.\n\nDeoarece sunt schimbate doar ID-uri aleatorii criptate, dvs. veÈ›i rămâne anonim. PuteÈ›i continua astfel:"</string> + <string name="submission_intro_text">"Pentru ca aplicaÈ›ia să funcÈ›ioneze bine, ne bazăm pe susÈ›inerea persoanelor care au fost diagnosticate cu coronavirus.\n\nDeoarece sunt schimbate doar ID-uri aleatorii criptate, dvs. veÈ›i rămâne anonim. PuteÈ›i continua astfel:"</string> <!-- XBUT: Submission introduction next button--> <string name="submission_intro_button_next">"ÃŽnainte"</string> <!-- XACT: Submission intro - illustration description, explanation image --> @@ -911,7 +949,7 @@ <!-- YTXT: submission introduction bullet points --> <string-array name="submission_intro_bullet_points"> <item>"Dacă există un cod QR în documentul dvs. de testare, îl puteÈ›i scana È™i înregistra testul. Imediat ce rezultatul este disponibil, îl puteÈ›i vedea în aplicaÈ›ie."</item> - <item>"Dacă aÈ›i fost diagnosticat cu COVID-19, îi puteÈ›i avertiza pe ceilalÈ›i."</item> + <item>"Dacă aÈ›i fost diagnosticat cu coronavirus, îi puteÈ›i avertiza pe ceilalÈ›i."</item> <item>"Dacă aÈ›i primit un cod TAN pentru un diagnostic pozitiv, îl puteÈ›i utiliza pentru a înregistra testul."</item> <item>"Dacă nu aveÈ›i un cod TAN, îl puteÈ›i solicita telefonic."</item> </string-array> @@ -920,25 +958,25 @@ <!-- Dispatcher --> <!-- XHED: Page headline for dispatcher menu --> - <string name="submission_dispatcher_headline">"SelecÈ›ie"</string> + <string name="submission_dispatcher_headline">"Aflarea rezultatului testului"</string> <!-- XHED: Page subheadline for dispatcher menu --> - <string name="submission_dispatcher_subheadline">"Ce informaÈ›ii aveÈ›i?"</string> + <string name="submission_dispatcher_subheadline">"AflaÈ›i rezultatul testului dvs. prin intermediul aplicaÈ›iei È™i avertizaÈ›i-i pe ceilalÈ›i. Vă veÈ›i proteja È™i veÈ›i opri răspândirea coronavirusului."</string> <!-- XHED: Page subheadline for dispatcher options asking if they have already been tested: QR and TAN --> - <string name="submission_dispatcher_needs_testing_subheadline">""</string> + <string name="submission_dispatcher_needs_testing_subheadline">"AÈ›i fost testat?"</string> <!-- XHED: Page subheadline for dispatcher options asking if they already have a positive test: tele-TAN --> - <string name="submission_dispatcher_already_positive_subheadline">""</string> + <string name="submission_dispatcher_already_positive_subheadline">"AÈ›i fost testat pozitiv la coronavirus?"</string> <!-- YTXT: Dispatcher text for QR code option --> - <string name="submission_dispatcher_card_qr">"Document cu cod QR"</string> + <string name="submission_dispatcher_card_qr">"Testarea cu cod QR"</string> <!-- YTXT: Body text for QR code dispatcher option --> <string name="submission_dispatcher_qr_card_text">"ÃŽnregistraÈ›i-vă testul scanând codul QR al documentului de testare."</string> <!-- YTXT: Dispatcher text for TAN code option --> - <string name="submission_dispatcher_card_tan_code">"TAN"</string> + <string name="submission_dispatcher_card_tan_code">"Intrare TAN"</string> <!-- YTXT: Body text for TAN code dispatcher option --> - <string name="submission_dispatcher_tan_code_card_text">"ÃŽnregistraÈ›i-vă testul introducând manual codul TAN."</string> + <string name="submission_dispatcher_tan_code_card_text">"AveÈ›i un cod TAN? ContinuaÈ›i să introduceÈ›i codul dvs. TAN pentru a-i putea avertiza pe ceilalÈ›i. "</string> <!-- YTXT: Dispatcher text for TELE-TAN option --> - <string name="submission_dispatcher_card_tan_tele">"Solicitare TAN"</string> + <string name="submission_dispatcher_card_tan_tele">"Nu aveÈ›i un cod TAN încă?"</string> <!-- YTXT: Body text for TELE_TAN dispatcher option --> - <string name="submission_dispatcher_tan_tele_card_text">"SunaÈ›i-ne dacă aÈ›i fost diagnosticat cu COVID-19."</string> + <string name="submission_dispatcher_tan_tele_card_text">"SunaÈ›i-ne È™i obÈ›ineÈ›i un cod TAN."</string> <!-- XACT: Dispatcher Tan page title --> <string name="submission_dispatcher_accessibility_title">"Ce informaÈ›ii aveÈ›i?"</string> @@ -956,6 +994,25 @@ <!-- XHED: Title for the interop country list--> <string name="submission_interoperability_list_title">"Următoarele țări participă în prezent la înregistrarea în jurnal a expunerilor la nivel transnaÈ›ional:"</string> + <!-- Submission Positive Other Warning No Consent --> + <!-- YTXT: Body text for the positive result additional warning page--> + <string name="submission_positive_other_warning_no_consent_body_first_part">"Deoarece aÈ›i fost testat pozitiv la coronavirus, acum puteÈ›i să îi avertizaÈ›i pe ceilalÈ›i prin intermediul aplicaÈ›iei."</string> + <!-- YTXT: Body text for the positive result additional warning page--> + <string name="submission_positive_other_warning_no_consent_body_second_part">"FuncÈ›ia de avertizare funcÈ›ionează în câteva țări. Următoarele țări participă în prezent:"</string> + + + <!-- Test result positive and no consent given --> + <!-- XHED: Title for test result positive and no consent given--> + <string name="submission_test_result_positive_no_consent_subtitle">"Să ne ajutăm împreună!"</string> + <!-- XTXT: First bullet point when test result is positive and consent is requested for key sharing--> + <string name="submission_test_result_positive_no_consent_text_1"><b>"PartajaÈ›i rezultatul testului dvs. È™i ajutaÈ›i la protejarea celorlalÈ›i împotriva infecÈ›iei."</b></string> + <!-- XTXT: Second bullet point when test result is positive and consent is requested for key sharing--> + <string name="submission_test_result_positive_no_consent_text_2">"Identitatea dvs. va rămâne secretă. AlÈ›i utilizatori nu vor È™ti cine a partajat rezultatele testelor respective."</string> + <!-- XTXT: Third bullet point when test result is positive and consent is requested for key sharing--> + <string name="submission_test_result_positive_no_consent_text_3">"AsiguraÈ›i-vă că urmaÈ›i instrucÈ›iunile direcÈ›iei dvs. de sănătate publică È™i că staÈ›i acasă, pentru a nu-i infecta pe ceilalÈ›i."</string> + <!-- XBUT: Button for giving consent for key sharing --> + <string name="submission_test_result_positive_no_consent_button_warn_others">"AvertizaÈ›i-i pe ceilalÈ›i"</string> + <!-- Submission Country Selector --> <!-- XHED: Page title for the submission country selection page --> <string name="submission_positive_country_selection_title">"Avertizări la nivel european"</string> @@ -995,13 +1052,29 @@ <!-- XACT: submission finished - illustration description, explanation image --> <string name="submission_done_illustration_description">"AÈ›i resimÈ›it unul sau mai multe dintre următoarele simptome în ultimele zile?"</string> + <!-- Submission Done No Consent--> + <!-- XHED: Page title for completed submission page --> + <string name="submission_done_no_consent_title">"Vă mulÅ£umim"</string> + <!-- YTXT: Page subtitle for completed submission page --> + <string name="submission_done_no_consent_subtitle">"Vă mulÈ›umim pentru ajutorul dat la oprirea răspândirii coronavirusului."</string> + <!-- YTXT: Page body for submission no consent page --> + <string name="submission_done_no_consent_body_title">"CeilalÈ›i nu vor fi avertizaÈ›i."</string> + <!-- YTXT: Page body for submission no consent page --> + <string name="submission_done_no_consent_body">"Acum puteÈ›i ajuta la îmbunătățirea preciziei avertizărilor. Pentru aceasta, la pasul următor, spuneÈ›i-ne când aÈ›i dezvoltat simptome pentru prima dată. PuteÈ›i anula acest pas în orice moment."</string> + <!-- XBUT: submission continue with symptom recording button --> + <string name="submission_done_no_consent_continue_with_symptom_recording">"Introducere simptome"</string> + <!-- XBUT: submission continue break flow button--> + <string name="submission_done_no_consent_break_flow">"IeÈ™ire"</string> + <!-- XACT: submission finished - illustration description, explanation image --> + <string name="submission_done_no_consent_illustration_description">"Câteva persoane se uită la smartphone-urile lor."</string> + <!-- Submission Symptoms --> <!-- XHED: Page title for symptom screens --> <string name="submission_symptom_title">"Simptome"</string> <!-- XTXT: headline text for initial symptom screen --> - <string name="submission_symptom_initial_headline">"AÈ›i resimÈ›it unul sau mai multe dintre următoarele simptome?"</string> + <string name="submission_symptom_initial_headline">"AÈ›i resimÈ›it unul sau mai multe dintre următoarele simptome în ultimele zile?"</string> <!-- YTXT: explanation text for initial symptom screen --> - <string name="submission_symptom_initial_explanation">"PuteÈ›i indica momentul când È™i dacă aÈ›i observat simptomele specifice coronavirusului pentru a-i permite aplicaÈ›iei să calculeze mai exact riscul de infectare al altor utilizatori ai aplicaÈ›iei. Dacă nu doriÈ›i să furnizaÈ›i aceste informaÈ›ii, selectaÈ›i „Nu răspundâ€."</string> + <string name="submission_symptom_initial_explanation">"PuteÈ›i indica momentul când È™i dacă aÈ›i observat simptomele specifice coronavirusului pentru a-i permite aplicaÈ›iei să calculeze mai exact riscul de infectare al altor utilizatori ai aplicaÈ›iei. Acest pas este voluntar. Dacă nu doriÈ›i să furnizaÈ›i informaÈ›ii despre simptomele dvs., selectaÈ›i „Nu răspundâ€."</string> <!-- YTXT: Bullet points for symptoms --> <string-array name="submission_symptom_symptom_bullets"> <item>"Temperatură crescută sau febră"</item> @@ -1058,9 +1131,9 @@ <!-- XHED: Page title for calendar page in submission symptom flow --> <string name="submission_symptom_calendar_title">"ÃŽnceputul simptomelor"</string> <!-- XHED: Page headline for calendar page in symptom submission flow --> - <string name="submission_symptom_calendar_headline">"Când aÈ›i început să resimÈ›iÈ›i aceste simptome? "</string> + <string name="submission_symptom_calendar_headline">"Când aÈ›i observat pentru prima dată simptomele?"</string> <!-- YTXT: Body text for calendar page in symptom submission flow--> - <string name="submission_symptom_calendar_body">"SelectaÈ›i data exactă din calendar sau, în cazul în care nu È›ineÈ›i minte data exactă, alegeÈ›i una dintre celelalte opÈ›iuni:"</string> + <string name="submission_symptom_calendar_body">"SpecificaÈ›i data cât mai exact posibil."</string> <!-- XBUT: symptom calendar screen less than 7 days button --> <string name="submission_symptom_less_seven">"ÃŽn ultimele 7 zile"</string> <!-- XBUT: symptom calendar screen 1-2 weeks button --> @@ -1072,13 +1145,13 @@ <!-- Submission Status Card --> <!-- XHED: Page title for the various submission status: fetching --> - <string name="submission_status_card_title_fetching">"Datele sunt citite...."</string> + <string name="submission_status_card_title_fetching">"Datele sunt citite..."</string> <!-- XHED: Page title for the various submission status: unregistered --> <string name="submission_status_card_title_unregistered">"AÈ›i fost testat?"</string> <!-- XHED: Page title for the various submission status: pending --> - <string name="submission_status_card_title_pending">"Rezultatul dvs. nu este încă disponibil"</string> + <string name="submission_status_card_title_pending">"Rezultatul testului dvs. nu este încă disponibil"</string> <!-- XHED: Page title for the various submission status: available --> - <string name="submission_status_card_title_available">"Rezultatul dvs. este disponibil"</string> + <string name="submission_status_card_title_available">"Rezultatul testului dvs. este disponibil"</string> <!-- XHED: Page title for the various submission status: positive --> <string name="submission_status_card_title_positive">"Diagnostic pozitiv"</string> <!-- XHED: Page title for the various submission status fetch failed --> @@ -1090,7 +1163,7 @@ <!-- YTXT: Body text for submission status: fetching --> <string name="submission_status_card_body_fetching">"Rezultatul dvs. este în curs de actualizare"</string> <!-- YTXT: Body text for submission status: unregistered --> - <string name="submission_status_card_body_unregistered">"AjutaÈ›i la întreruperea lanÈ›ului de infectare prin notificarea altor persoane."</string> + <string name="submission_status_card_body_unregistered">"AjutaÈ›i la protejarea dvs. È™i a celorlalÈ›i."</string> <!-- YTXT: Body text for submission status: pending --> <string name="submission_status_card_body_pending">"Evaluarea testului dvs. nu este încă finalizată."</string> <!-- YTXT: Body text for submission status: invalid --> @@ -1100,9 +1173,9 @@ <!-- YTXT: Body text for submission status: negative --> <string name="submission_status_card_body_negative">"AÈ›i fost diagnosticat negativ la SARS-CoV-2."</string> <!-- YTXT: Body text for submission status fetch failed --> - <string name="submission_status_card_body_failed">"Testul dvs. are o vechime de peste 21 de zile È™i, prin urmare, nu mai este relevant. Vă rugăm să È™tergeÈ›i textul. Apoi puteÈ›i adăuga altul."</string> + <string name="submission_status_card_body_failed">"Testul dvs. are o vechime de peste 21 de zile È™i, prin urmare, nu mai este relevant. Vă rugăm să È™tergeÈ›i testul. Apoi puteÈ›i adăuga altul."</string> <!-- XBUT: submission status card unregistered button --> - <string name="submission_status_card_button_unregistered">"AflaÈ›i mai multe È™i ajutor"</string> + <string name="submission_status_card_button_unregistered">"PaÈ™ii următori"</string> <!-- XBUT: submission status card show results button --> <string name="submission_status_card_button_show_results">"AfiÈ™are test"</string> <!-- XBUT: submission status card fetch failed button --> @@ -1140,7 +1213,51 @@ </string-array> <!-- XBUT Symptoms exact date button --> - <string name="symptoms_calendar_exact_date_button">"Data exactă"</string> + <string name="symptoms_calendar_exact_date_button">"Dată"</string> + + <!-- Submission consent custom view --> + <!-- XHED: Title for consent given --> + <string name="submission_consent_view_consent_given">"Consimțământ\n„AvertizaÈ›i-i pe ceilalÈ›i†acordat"</string> + <!-- XHED: Title for consent NOT given --> + <string name="submission_consent_view_consent_not_given">"Consimțământ\n„AvertizaÈ›i-i pe ceilalÈ›i†neacordat"</string> + + <!-- Submission test result available --> + <!-- XHED: Page title for test results available step --> + <string name="submission_test_result_available_title">"Rezultatul testului dvs. este disponibil"</string> + <!-- XACT: Test result available illustration description --> + <string name="submission_test_result_available_illustration_description">"O femeie își È›ine în mână smartphone-ul. Acesta trimite un semnal către un alt smartphone."</string> + <!-- YTXT: Text for consent given --> + <string name="submission_test_result_available_text_consent_given">"Vă mulÈ›umim pentru că sunteÈ›i de acord să partajaÈ›i rezultatul testului dvs. È™i să ajutaÈ›i astfel la avertizarea celorlalÈ›i. \n\n"<b>"La pasul următor, partajaÈ›i rezultatul testului dvs. apăsând „Partajareâ€."</b></string> + <!-- XHED: Close screen popup title for consent given --> + <string name="submission_test_result_available_close_dialog_title_consent_given">"DoriÈ›i să anulaÈ›i?"</string> + <!-- XTXT: Close screen popup text for consent given --> + <string name="submission_test_result_available_close_dialog_body_consent_given">"Intrările dvs. nu vor fi salvate."</string> + <!-- YTXT: Text for consent NOT given --> + <string name="submission_test_result_available_text_consent_not_given">"AÈ›i ales să nu partajaÈ›i rezultatele testului dvs. CeilalÈ›i nu vor fi avertizaÈ›i. \n\nLa pasul următor, aveÈ›i ocazia să vă răzgândiÈ›i È™i să partajaÈ›i totuÈ™i rezultatul testului dvs., pentru a ajuta la oprirea răspândirii coronavirusului È™i a-i proteja pe ceilalÈ›i."</string> + <!-- XHED: Close screen popup title for consent NOT given --> + <string name="submission_test_result_available_close_dialog_title_consent_not_given">"Important:\nSunteÈ›i pe punctul de a anula acest proces.\nÃŽncă nu i-aÈ›i avertizat pe ceilalÈ›i. Vă rugăm să finalizaÈ›i procesul È™i să ajutaÈ›i la protejarea celorlalÈ›i."</string> + <!-- XTXT: Close screen popup text for consent NOT given --> + <string name="submission_test_result_available_close_dialog_body_consent_not_given">"Sigur doriÈ›i să anulaÈ›i acest proces?"</string> + <!-- XBUT: Close screen popup cancel button --> + <string name="submission_test_result_available_close_dialog_cancel_button">"Anulare"</string> + <!-- XBUT: Close screen popup continue button --> + <string name="submission_test_result_available_close_dialog_continue_button">"Continuare"</string> + + <!-- Submission your consent screen --> + <!-- XHED: Your consent screen title --> + <string name="submission_your_consent_title">"Consimțământul dvs."</string> + <!-- XTXT: Your consent screen switch label - next to a switch --> + <string name="submission_your_consent_switch_subtitle">"AvertizaÈ›i-i pe ceilalÈ›i"</string> + <!-- XTXT: Your consent screen switch status on --> + <string name="submission_your_consent_switch_status_on">"Activ"</string> + <!-- XTXT: Your consent screen switch status off --> + <string name="submission_your_consent_switch_status_off">"Oprit"</string> + <!-- XTXT: Your consent screen about agreement --> + <string name="submission_your_consent_about_agreement">"V-aÈ›i dat următorul consimțământ:"</string> + <!-- XHED: Your consent screen agreement title --> + <string name="submission_your_consent_agreement_title"><b>"Consimțământ"</b></string> + <!-- XTXT: Your consent screen detailed information --> + <string name="submission_your_consent_agreement_details">"InformaÈ›ii detaliate privind Prelucrarea datelor È™i Consimțământul dvs."</string> <!-- #################################### Button Tooltips for Accessibility @@ -1215,8 +1332,6 @@ <!-- NOTR --> <string name="test_api_button_show_qr_code">"Show QR Code"</string> <!-- NOTR --> - <string name="test_api_button_submit_keys">"Submit keys to Server"</string> - <!-- NOTR --> <string name="test_api_button_scan_qr_code">"Scan Exposure Key"</string> <!-- NOTR --> <string name="test_api_switch_last_three_hours_from_server">"Last 3 Hours Mode"</string> @@ -1309,7 +1424,7 @@ <!-- XTXT: First section after the header of the interoperability information/configuration view --> <string name="interoperability_configuration_first_section">"Mai multe țări colaborează pentru a susÈ›ine alarmele transnaÈ›ionale printr-un server de schimb comun. De exemplu, contactele cu utilizatorii unei aplicaÈ›ii oficiale anticoronavirus din alte țări participante pot fi, de asemenea, luate în considerare pentru înregistrarea în jurnal a expunerilor."</string> <!-- XTXT: Second section after the header of the interoperability information/configuration view --> - <string name="interoperability_configuration_second_section">"Pentru aceasta, aplicaÈ›ia descarcă o listă care este actualizată zilnic de ID-uri aleatorii ale tuturor utilizatorilor care È™i-au partajat ID-urile aleatorii prin propria aplicaÈ›ie. Această listă este apoi comparată cu ID-urile aleatorii înregistrate de smartphone-ul dvs. Descărcarea zilnică a listei de ID-uri aleatorii este, de obicei, gratuită pentru dvs. – nu veÈ›i suporta costuri pentru datele utilizate de aplicaÈ›ie în acest context È™i nu vor fi aplicate costuri de roaming pentru această opÈ›iune în alte țări UE."</string> + <string name="interoperability_configuration_second_section">"Pentru aceasta, aplicaÈ›ia descarcă o listă, care este actualizată zilnic, de ID-uri aleatorii ale tuturor utilizatorilor care È™i-au partajat rezultatele testelor pentru a-i avertiza pe ceilalÈ›i prin intermediul propriei aplicaÈ›ii. Apoi, această listă este comparată cu ID-urile aleatorii înregistrate de smartphone-ul dvs. Android. Descărcările listelor sunt, de obicei, gratuite pentru dvs. ÃŽn mod specific, aceasta înseamnă că operatorii de reÈ›ele mobile nu percep costuri pentru datele utilizate de aplicaÈ›ie în acest context È™i nu aplică niciun fel de costuri de roaming pentru această opÈ›iune în alte țări UE. ContactaÈ›i operatorul reÈ›elei mobile pentru mai multe informaÈ›ii."</string> <!-- XHED: Header right above the country list in the interoperability information/configuration view --> <string name="interoperability_configuration_list_title">"Următoarele țări participă în prezent la înregistrarea în jurnal a expunerilor la nivel transnaÈ›ional:"</string> <!-- XTXT: Text right under the country list in the interoperability information/configuration view --> @@ -1320,9 +1435,9 @@ <!-- YMSG: Onboarding tracing step first section in interoperability after the title --> <string name="interoperability_onboarding_first_section">"Mai multe țări s-au asociat pentru a susÈ›ine avertizarea la nivel transnaÈ›ional. Cu alte cuvinte, acum poate fi luată în considerare posibila dvs. expunere la utilizatori ai aplicaÈ›iilor oficiale anticoronavirus din toate țările participante."</string> <!-- YMSG: Onboarding tracing step second section in interoperability after the title --> - <string name="interoperability_onboarding_second_section">"Când un utilizator transmite ID-urile sale aleatorii la serverul de schimb operat în comun de țările participante, utilizatorii aplicaÈ›iilor oficiale anticoronavirus din toate aceste țări pot fi avertizaÈ›i de posibila expunere."</string> + <string name="interoperability_onboarding_second_section">"Când un utilizator transmite rezultatul pozitiv al testului său (mai exact: ID-urile sale aleatorii) pentru a-i avertiza pe ceilalÈ›i prin intermediul serverului de schimb operat în comun de țările participante, toÈ›i utilizatorii aplicaÈ›iilor oficiale anticoronavirus din toate aceste țări pot fi avertizaÈ›i de posibila lor expunere."</string> <!-- YMSG: Onboarding tracing step third section in interoperability after the title. --> - <string name="interoperability_onboarding_randomid_download_free">"Descărcarea zilnică a listei cu ID-uri aleatorii este, de obicei, gratuită pentru dvs. ÃŽn mod specific, aceasta înseamnă că operatorii de reÈ›ele mobile nu percep costuri pentru datele utilizate de aplicaÈ›ie în acest context È™i nu aplică niciun fel de costuri de roaming pentru această opÈ›iune în alte țări UE. ContactaÈ›i operatorul reÈ›elei mobile pentru mai multe informaÈ›ii."</string> + <string name="interoperability_onboarding_randomid_download_free">"Descărcările zilnice ale listelor cu ID-uri aleatorii de la utilizatori care au partajat rezultate pozitive ale testelor sunt, de obicei, gratuite pentru dvs. ÃŽn mod specific, aceasta înseamnă că operatorii de reÈ›ele mobile nu percep costuri pentru datele utilizate de aplicaÈ›ie în acest context È™i nu aplică niciun fel de costuri de roaming pentru această opÈ›iune în alte țări UE. ContactaÈ›i operatorul reÈ›elei mobile pentru mai multe informaÈ›ii."</string> <!-- XTXT: Small header above the country list in the onboarding screen for interoperability. --> <string name="interoperability_onboarding_list_title">"ÃŽn prezent participă următoarele țări:"</string> @@ -1337,9 +1452,9 @@ <!-- XTXT: Description of the interoperability extension of the app. Below interoperability_onboarding_delta_title --> <string name="interoperability_onboarding_delta_subtitle">"Caracteristicile aplicaÈ›iei Corona-Warn au fost extinse. Multe țări s-au asociat pentru a susÈ›ine avertizarea la nivel internaÈ›ional, pe baza unui server de schimb operat în comun. Acum poate fi luată în considerare posibila expunere la utilizatori ai aplicaÈ›iilor oficiale anticoronavirus din alte țări participante când se calculează riscul dvs. de expunere."</string> <!-- YMSG: Onboarding tracing step third section in interoperability after the title. --> - <string name="interoperability_onboarding_delta_randomid">"Pentru aceasta, aplicaÈ›ia descarcă o listă, care este actualizată zilnic, de ID-uri aleatorii ale tuturor utilizatorilor care È™i-au partajat ID-urile aleatorii prin intermediul propriei aplicaÈ›ii. Apoi, această listă este comparată cu ID-urile aleatorii înregistrate de dispozitivul dvs."</string> + <string name="interoperability_onboarding_delta_randomid">"Pentru aceasta, aplicaÈ›ia descarcă o listă, care este actualizată zilnic, de ID-uri aleatorii ale tuturor utilizatorilor care È™i-au partajat rezultatele testelor pentru a-i avertiza pe ceilalÈ›i prin intermediul propriei aplicaÈ›ii. Apoi, această listă este comparată cu ID-urile aleatorii înregistrate de smartphone-ul dvs. Android."</string> <!-- YMSG: Onboarding tracing step third section in interoperability after the title. --> - <string name="interoperability_onboarding_delta_free_download">"Descărcarea zilnică a listei cu ID-urilor aleatorii este, de obicei, gratuită pentru dvs. ÃŽn mod specific, aceasta înseamnă că operatorii de reÈ›ele mobile nu percep costuri pentru datele utilizate de aplicaÈ›ie în acest context È™i nu aplică niciun fel de costuri de roaming pentru această opÈ›iune în alte țări UE. ContactaÈ›i operatorul reÈ›elei mobile pentru mai multe informaÈ›ii."</string> + <string name="interoperability_onboarding_delta_free_download">"Descărcările listelor sunt, de obicei, gratuite pentru dvs. ÃŽn mod specific, aceasta înseamnă că operatorii de reÈ›ele mobile nu percep costuri pentru datele utilizate de aplicaÈ›ie în acest context È™i nu aplică niciun fel de costuri de roaming pentru această opÈ›iune în alte țări UE. ContactaÈ›i operatorul reÈ›elei mobile pentru mai multe informaÈ›ii."</string> <!-- XACT: interoperability (eu) - illustraction description, explanation image --> <string name="interoperability_eu_illustration_description">"O mână È›ine un smartphone. ÃŽn fundal sunt ilustrate Europa È™i steagul european."</string> @@ -1356,4 +1471,15 @@ <!-- XBUT: Title for the interoperability onboarding Settings-Button if no network is available --> <string name="interoperability_onboarding_list_button_title_no_network">"DeschideÈ›i configurările dispozitivului"</string> -</resources> + <!-- XHED: Title for the dialog on test result positive no consent screen --> + <string name="submission_test_result_positive_no_consent_dialog_title">"DoriÈ›i să trimiteÈ›i o avertizare?"</string> + <!-- XTXT: Message for the dialog on test result positive no consent screen --> + <string name="submission_test_result_positive_no_consent_dialog_message">"Trebuie să partajaÈ›i rezultatul testului dvs. dacă doriÈ›i să îi avertizaÈ›i pe ceilalÈ›i."</string> + <!-- XBUT: Positive button for the dialog on test result positive no consent screen --> + <string name="submission_test_result_positive_no_consent_dialog_positive_button">"AvertizaÈ›i-i pe ceilalÈ›i"</string> + <!-- XBUT: Negative button for the dialog on test result positive no consent screen --> + <string name="submission_test_result_positive_no_consent_dialog_negative_button">"Nu îi avertizaÈ›i pe ceilalÈ›i"</string> + <!-- XBUT: Abort button for test result positive no consent screen --> + <string name="submission_test_result_positive_no_consent_button_abort">"Anulare"</string> + +</resources> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/values-tr/strings.xml b/Corona-Warn-App/src/main/res/values-tr/strings.xml index 143aabdff837caafe35e6d92a0027755de524b23..b308b2df25bde335f768b2e85c7fb8f4a58d1783 100644 --- a/Corona-Warn-App/src/main/res/values-tr/strings.xml +++ b/Corona-Warn-App/src/main/res/values-tr/strings.xml @@ -162,7 +162,7 @@ <string name="risk_card_low_risk_no_encounters_body">"Åžu ana dek hiçbir maruz kalma yok"</string> <!-- XTXT: risk card - Low risk state - Days with low risk encounters --> <plurals name="risk_card_low_risk_encounter_days_body"> - <item quantity="one">"%1$d gün için düşük riskli maruz kalmalar"</item> + <item quantity="one">"Bir gün için düşük riskli maruz kalmalar"</item> <item quantity="other">"%1$d gün için düşük riskli maruz kalmalar"</item> <item quantity="zero">"%1$d gün için düşük riskli maruz kalmalar"</item> <item quantity="two">"%1$d gün için düşük riskli maruz kalmalar"</item> @@ -174,7 +174,7 @@ <string name="risk_card_high_risk_no_encounters_body">"Åžu ana dek hiçbir maruz kalma yok"</string> <!-- XTXT: risk card - High risk state - Days with high risk encounters --> <plurals name="risk_card_high_risk_encounter_days_body"> - <item quantity="one">"%1$d gün için artmış riskli maruz kalmalar"</item> + <item quantity="one">"Bir gün için artmış riskli maruz kalmalar"</item> <item quantity="other">"%1$d gün için artmış riskli maruz kalmalar"</item> <item quantity="zero">"%1$d gün için artmış riskli maruz kalmalar"</item> <item quantity="two">"%1$d gün için artmış riskli maruz kalmalar"</item> @@ -242,7 +242,7 @@ <!-- XHED: App overview subtitle for risk explanation --> <string name="main_overview_subtitle_risk">"Enfeksiyon Riski"</string> <!-- YTXT: App overview body text about risk levels --> - <string name="main_overview_body_risk">"Son 14 gün içerisinde COVID-19 tanısı konan biriyle temasınız olduysa uygulama kiÅŸisel enfeksiyon riskinizi hesaplar. Bunu, maruz kalma süresini ve yakınlığını ölçerek gerçekleÅŸtirir."</string> + <string name="main_overview_body_risk">"Son 14 gün içerisinde koronavirüs tanısı konan biriyle temasınız olduysa uygulama kiÅŸisel enfeksiyon riskinizi hesaplar. Bunu, maruz kalma süresini ve yakınlığını ölçerek gerçekleÅŸtirir."</string> <!-- XHED: App overview subtitle for risk level list --> <string name="main_overview_subtitle_risk_levels">"Åžu risk durumu gösterilebilir:"</string> <!-- XTXT: App overview increased risk level --> @@ -254,7 +254,7 @@ <!-- XHED: App overview subtitle for test procedure explanation --> <string name="main_overview_headline_test">"DiÄŸer Kullanıcıları Bilgilendirme"</string> <!-- YTXT: App overview body text about rest procedure --> - <string name="main_overview_body_test">"DiÄŸer bir temel özellik, testinizi kaydetme ve sonucunu alma özelliÄŸidir. COVID-19 tanısı konursa diÄŸer kiÅŸileri bilgilendirerek enfeksiyon zincirini kırabilirsiniz."</string> + <string name="main_overview_body_test">"DiÄŸer bir temel özellik, testinizi kaydetme ve sonucunu alma özelliÄŸidir. Koronavirüs tanısı alırsanız diÄŸer kiÅŸileri bilgilendirerek enfeksiyon zincirini kırabilirsiniz."</string> <!-- XHED: App overview headline for glossary --> <string name="main_overview_headline_glossary">"Terimlerin Tanımı:"</string> <!-- XHED: App overview subtitle for glossary key storage --> @@ -276,7 +276,7 @@ <!-- XHED: App overview subtitle for glossary keys --> <string name="main_overview_subtitle_glossary_keys">"Rastgele Kimlik"</string> <!-- YTXT: App overview body for glossary keys --> - <string name="main_overview_body_glossary_keys">"Rastgele Kimlikler, rastgele oluÅŸturulan rakam ve harf kombinasyonlarıdır. Yakın mesafedeki akıllı telefonlar arasında deÄŸiÅŸtirilir. Rastgele Kimlikler belirli bir kiÅŸiyi izlemek üzere kullanılamaz ve 14 günün sonunda otomatik olarak silinir. COVID-19 tanısı konan kiÅŸiler son 14 güne kadar rastgele kimliklerinin uygulamanın diÄŸer kullanıcıları ile paylaşılmasını seçebilir."</string> + <string name="main_overview_body_glossary_keys">"Rastgele Kimlikler, rastgele oluÅŸturulan rakam ve harf kombinasyonlarıdır. Yakın mesafedeki akıllı telefonlar arasında deÄŸiÅŸtirilir. Rastgele Kimlikler belirli bir kiÅŸiyi izlemek üzere kullanılamaz ve 14 günün sonunda otomatik olarak silinir. Koronavirüs tanısı konan kiÅŸiler son 14 güne kadar rastgele kimliklerinin uygulamanın diÄŸer kullanıcıları ile paylaşılmasını seçebilir."</string> <!-- XACT: main (overview) - illustraction description, explanation image --> <string name="main_overview_illustration_description">"Bir akıllı telefon, 1 ila 3 olarak numaralandırılmış farklı içerikleri gösterir."</string> <!-- XACT: App main page title --> @@ -293,11 +293,11 @@ <!-- XHED: risk details - subtitle for additional info in case of encounter with low risk --> <string name="risk_details_additional_info_subtitle">"Enfeksiyon riskiniz neden düşük?"</string> <!-- XHED: risk details - text for additional info in case of encounter with low risk --> - <string name="risk_details_additional_info_text">"Daha sonra COVID-19 tanısı konmuÅŸ bir kiÅŸiyle karşılaÅŸtınız. Ancak maruz kalma günlüğü verilerine göre enfeksiyon riskiniz düşük. Kısa süreyle ya da uzak mesafeyle karşılaÅŸmanız durumunda risk düşük olur. EndiÅŸelenmeniz gerekmez ve eylem gerçekleÅŸtirmeniz özel bir ihtiyaç bulunmuyor. Mesafe ve hijyen konusunda belirlenen kurallara riayet etmenizi öneririz."</string> + <string name="risk_details_additional_info_text">"Daha sonra koronavirüs tanısı konmuÅŸ bir kiÅŸiyle karşılaÅŸtınız. Ancak maruz kalma günlüğü verilerine göre enfeksiyon riskiniz düşük. Kısa süreyle ya da uzak mesafeyle karşılaÅŸmanız durumunda risk düşük olur. EndiÅŸelenmeniz gerekmez ve eylem gerçekleÅŸtirmeniz özel bir ihtiyaç bulunmuyor. Mesafe ve hijyen konusunda belirlenen kurallara riayet etmenizi öneririz."</string> <!-- XHED: risk details - headline, how a user should act --> <string name="risk_details_headline_behavior">"Talimatlar"</string> <!-- XHED: risk details - multiline headline, bold, how to act correct --> - <string name="risk_details_subtitle_behavior">"Yapmanız gerekenler"</string> + <string name="risk_details_subtitle_behavior">"Yapmanız gerekenler:"</string> <!-- XMSG: risk details - go/stay home, something like a bullet point --> <string name="risk_details_behavior_body_stay_home">"Mümkünse lütfen eve gidin ve evde kalın."</string> <!-- XMSG: risk details - get in touch with the corresponding people, something like a bullet point --> @@ -327,23 +327,23 @@ <!-- XHED: risk details - infection period logged information body, below behaviors --> <string name="risk_details_information_body_period_logged_assessment">"Maruz kalma günlüğü son 14 günü kapsar. Bu süre boyunca akıllı telefonunuzdaki günlüğe kaydetme özelliÄŸi %1$s gün etkindi. Uygulama, enfeksiyondan korunma için artık ilgili olmadığından daha eski kayıtları otomatik olarak siler."</string> <!-- XHED: risk details - how your risk level was calculated, below behaviors --> - <string name="risk_details_subtitle_infection_risk_past">"Riskiniz bu ÅŸekilde hesaplandı"</string> + <string name="risk_details_subtitle_infection_risk_past">"Riskiniz bu ÅŸekilde hesaplandı."</string> <!-- XHED: risk details - how your risk level will be calculated, below behaviors --> - <string name="risk_details_subtitle_infection_risk">"Riskiniz bu ÅŸekilde hesaplanır"</string> + <string name="risk_details_subtitle_infection_risk">"Riskiniz bu ÅŸekilde hesaplanır."</string> <!-- XMSG: risk details - risk calculation wasn't possible for 24h, below behaviors --> <string name="risk_details_information_body_outdated_risk">"Maruz kalma günlüğünüz 24 saatten uzun süre için güncellenemedi."</string> <!-- YTXT: risk details - low risk explanation text --> - <string name="risk_details_information_body_low_risk">"Daha sonra COVID-19 tanısı konan kiÅŸilere maruz kaldığınıza dair bir günlük kaydı oluÅŸturulmadığı veya bu kiÅŸilerle yalnızca kısa süreyle ve uzak mesafeden karşılaÅŸtığınız için enfeksiyon riskiniz düşüktür."</string> + <string name="risk_details_information_body_low_risk">"Daha sonra koronavirüs tanısı konan kiÅŸilere maruz kaldığınıza dair bir günlük kaydı oluÅŸturulmadığı veya bu kiÅŸilerle yalnızca kısa süreyle ve uzak mesafeden karşılaÅŸtığınız için enfeksiyon riskiniz düşüktür."</string> <!-- YTXT: risk details - low risk explanation text with encounter with low risk --> - <string name="risk_details_information_body_low_risk_with_encounter">"Enfeksiyon riskiniz, maruz kalma günlüğünün verileri kullanılarak yerel olarak akıllı telefonunuzda hesaplanır. Hesaplamada COVID-19 tanısı konan kiÅŸilere maruz kalma mesafesi ve süresinin yanında potansiyel enfeksiyon bulaÅŸtırma durumu da göz önünde bulundurulur. Enfeksiyon riskiniz bir baÅŸkası tarafından görüntülenemez ya da bir baÅŸkasına aktarılamaz."</string> + <string name="risk_details_information_body_low_risk_with_encounter">"Enfeksiyon riskiniz, maruz kalma günlüğünün verileri kullanılarak yerel olarak akıllı telefonunuzda hesaplanır. Hesaplamada koronavirüs tanısı konan kiÅŸilere maruz kalma mesafesi ve süresinin yanında potansiyel enfeksiyon bulaÅŸtırma durumu da göz önünde bulundurulur. Enfeksiyon riskiniz bir baÅŸkası tarafından görüntülenemez ya da bir baÅŸkasına aktarılamaz."</string> <!-- YTXT: risk details - increased risk explanation text with variable for day(s) since last contact --> <plurals name="risk_details_information_body_increased_risk"> - <item quantity="one">"En son %1$s gün önce, COVID-19 tanısı konan en az bir kiÅŸiyle daha uzun süreyle ve yakın mesafeden maruz kalma yaÅŸadığınız için enfeksiyon riskiniz daha yüksektir."</item> - <item quantity="other">"En son %1$s gün önce, COVID-19 tanısı konan en az bir kiÅŸiyle daha uzun süreyle ve yakın mesafeden maruz kalma yaÅŸadığınız için enfeksiyon riskiniz daha yüksektir."</item> - <item quantity="zero">"En son %1$s gün önce, COVID-19 tanısı konan en az bir kiÅŸiyle daha uzun süreyle ve yakın mesafeden maruz kalma yaÅŸadığınız için enfeksiyon riskiniz daha yüksektir."</item> - <item quantity="two">"En son %1$s gün önce, COVID-19 tanısı konan en az bir kiÅŸiyle daha uzun süreyle ve yakın mesafeden maruz kalma yaÅŸadığınız için enfeksiyon riskiniz daha yüksektir."</item> - <item quantity="few">"En son %1$s gün önce, COVID-19 tanısı konan en az bir kiÅŸiyle daha uzun süreyle ve yakın mesafeden maruz kalma yaÅŸadığınız için enfeksiyon riskiniz daha yüksektir."</item> - <item quantity="many">"En son %1$s gün önce, COVID-19 tanısı konan en az bir kiÅŸiyle daha uzun süreyle ve yakın mesafeden maruz kalma yaÅŸadığınız için enfeksiyon riskiniz daha yüksektir."</item> + <item quantity="one">"En son %1$s gün önce, koronavirüs tanısı konan en az bir kiÅŸiyle daha uzun süreyle ve yakın mesafeden maruz kalma yaÅŸadığınız için enfeksiyon riskiniz daha yüksektir."</item> + <item quantity="other">"En son %1$s gün önce, koronavirüs tanısı konan en az bir kiÅŸiyle daha uzun süreyle ve yakın mesafeden maruz kalma yaÅŸadığınız için enfeksiyon riskiniz daha yüksektir."</item> + <item quantity="zero">"En son %1$s gün önce, koronavirüs tanısı konan en az bir kiÅŸiyle daha uzun süreyle ve yakın mesafeden maruz kalma yaÅŸadığınız için enfeksiyon riskiniz daha yüksektir."</item> + <item quantity="two">"En son %1$s gün önce, koronavirüs tanısı konan en az bir kiÅŸiyle daha uzun süreyle ve yakın mesafeden maruz kalma yaÅŸadığınız için enfeksiyon riskiniz daha yüksektir."</item> + <item quantity="few">"En son %1$s gün önce, koronavirüs tanısı konan en az bir kiÅŸiyle daha uzun süreyle ve yakın mesafeden maruz kalma yaÅŸadığınız için enfeksiyon riskiniz daha yüksektir."</item> + <item quantity="many">"En son %1$s gün önce, koronavirüs tanısı konan en az bir kiÅŸiyle daha uzun süreyle ve yakın mesafeden maruz kalma yaÅŸadığınız için enfeksiyon riskiniz daha yüksektir."</item> </plurals> <!-- YTXT: risk details - risk calculation explanation --> <string name="risk_details_information_body_notice">"Enfeksiyon riskiniz, akıllı telefonunuzda yerel olarak bulunan maruz kalma günlüğü verileri (süre ve mesafe) kullanılarak hesaplanır. Enfeksiyon riskiniz baÅŸkaları tarafından görüntülenemez veya baÅŸkalarına aktarılmaz."</string> @@ -404,7 +404,7 @@ <!-- XHED: onboarding(together) - two/three line headline under an illustration --> <string name="onboarding_subtitle">"Sizin için ve hepimiz için daha fazla koruma. Corona-Warn-App uygulamasını kullanarak enfeksiyon zincirlerini çok daha kısa süre içinde kırabiliriz."</string> <!-- YTXT: onboarding(together) - inform about the app --> - <string name="onboarding_body">"Akıllı telefonunuzu koronavirüs uyarı sistemine dönüştürün. Risk durumunuza iliÅŸkin genel bir bakış elde edin ve son 14 gün içinde COVID-19 tanısı konan herhangi biri ile yakın temasa geçip geçmediÄŸinizi öğrenin."</string> + <string name="onboarding_body">"Akıllı telefonunuzu koronavirüs uyarı sistemine dönüştürün. Risk durumunuza iliÅŸkin genel bir bakış elde edin ve son 14 gün içinde koronavirüs tanısı konan herhangi biri ile yakın temasa geçip geçmediÄŸinizi öğrenin."</string> <!-- YTXT: onboarding(together) - explain application --> <string name="onboarding_body_emphasized">"Uygulama kiÅŸilerin akıllı telefonları arasında ÅŸifrelenmiÅŸ rastgele kimlikleri paylaÅŸarak karşılaÅŸma günlüğü oluÅŸturur ve bu sırada hiçbir kiÅŸisel veriye eriÅŸim saÄŸlanmaz."</string> <!-- XACT: onboarding(together) - illustraction description, header image --> @@ -421,9 +421,9 @@ <!-- XHED: onboarding(tracing) - how to enable tracing --> <string name="onboarding_tracing_headline">"Maruz Kalma Günlüğünü EtkinleÅŸtirme"</string> <!-- XHED: onboarding(tracing) - two/three line headline under an illustration --> - <string name="onboarding_tracing_subtitle">"Enfeksiyon riski taşıyıp taşımadığınızı belirlemek için maruz kalma günlüğü özelliÄŸini etkinleÅŸtirmeniz gerekir."</string> + <string name="onboarding_tracing_subtitle">"Enfeksiyon riski taşıyıp taşımadığınızı belirlemek için maruz kalma günlüğünü etkinleÅŸtirmeniz gerekir."</string> <!-- YTXT: onboarding(tracing) - explain tracing --> - <string name="onboarding_tracing_body">"Maruz kalma günlüğü, akıllı telefonunuzun Bluetooth üzerinden diÄŸer kullanıcıların ÅŸifrelenmiÅŸ rastgele kimliklerini alması ve size ait rastgele kimlikleri diÄŸer kullanıcıların akıllı telefonlarına aktarmasıyla çalışır. Maruz kalma günlüğü, dilediÄŸiniz zaman devre dışı bırakılabilir. "</string> + <string name="onboarding_tracing_body">"Maruz kalma günlüğü, Android akıllı telefonunuzun Bluetooth üzerinden diÄŸer kullanıcıların ÅŸifrelenmiÅŸ rastgele kimliklerini alması ve size ait rastgele kimlikleri diÄŸer kullanıcıların akıllı telefonlarına aktarmasıyla çalışır. Maruz kalma günlüğü, dilediÄŸiniz zaman devre dışı bırakılabilir. "</string> <!-- YTXT: onboarding(tracing) - explain tracing --> <string name="onboarding_tracing_body_emphasized">"ÅžifrelenmiÅŸ rastgele kimlikler diÄŸer kullanıcılara yalnızca tarih, süre ve yakınlık (sinyal gücü ile hesaplanır) hakkındaki bilgileri aktarır. KiÅŸilerin kimlikleri rastgele kimliklere göre belirlenemez."</string> <!-- YTXT: onboarding(tracing) - easy language explain tracing link--> @@ -471,9 +471,9 @@ <!-- XBUT: onboarding(tracing) - button enable tracing --> <string name="onboarding_tracing_location_button">"Cihaz Ayarlarını Aç"</string> <!-- XACT: Onboarding (test) page title --> - <string name="onboarding_test_accessibility_title">"EtkinleÅŸtirme sayfası 5/6: COVID-19 Tanısı Aldıysanız"</string> + <string name="onboarding_test_accessibility_title">"EtkinleÅŸtirme sayfası 5/6: Koronavirüs Tanısı Aldıysanız"</string> <!-- XHED: onboarding(test) - about positive tests --> - <string name="onboarding_test_headline">"COVID-19 tanısı aldıysanız..."</string> + <string name="onboarding_test_headline">"Koronavirüs tanısı aldıysanız..."</string> <!-- XHED: onboarding(test) - two/three line headline under an illustration --> <string name="onboarding_test_subtitle">"… lütfen bunu Corona-Warn-App\'te belirtin. Test sonuçlarınızı paylaÅŸmanız gönüllülük esasına dayalıdır ve güvenlidir. Lütfen herkesin saÄŸlığı için bunu yapın."</string> <!-- YTXT: onboarding(test) - explain test --> @@ -496,7 +496,7 @@ ###################################### --> <!-- XACT: onboarding(sixteen) title --> - <string name="sixteen_title_text">"YaÅŸ Sınırı: 16 ve Ãœzeri"</string> + <string name="sixteen_title_text">"16 YaÅŸ Uyarısı"</string> <!-- XACT: onboarding(sixteen) title --> <string name="sixteen_description_text">"Bu uygulama, 16 yaÅŸ ve üzerinde olan ve Almanya\'da yaÅŸayan kiÅŸilerin kullanması için hazırlanmıştır."</string> @@ -525,7 +525,7 @@ <!-- XTXT: settings(tracing) - shows status under header in home, inactive location --> <string name="settings_tracing_body_inactive_location">"Konum hizmetleri devre dışı bırakıldı"</string> <!-- YTXT: settings(tracing) - explains tracings --> - <string name="settings_tracing_body_text">"Uygulamanın, enfekte olan bir kullanıcı ile karşılaÅŸmanızın ardından risk altında olup olmadığınızı belirleyebilmesi için maruz kalma günlüğü özelliÄŸini etkinleÅŸtirmeniz gerekir. Maruz kalma günlüğü özelliÄŸi uluslararası olarak çalışır; yani, kullanıcılara iliÅŸkin tüm olası maruz kalmalar da diÄŸer resmi koronavirüs uygulamalarıyla tespit edilir.\n\nMaruz kalma günlüğü özelliÄŸi, akıllı telefonunuzun Bluetooth üzerinden diÄŸer kullanıcıların ÅŸifrelenmiÅŸ rastgele kimliklerini alması ve size ait rastgele kimlikleri diÄŸer kullanıcıların akıllı telefonlarına aktarmasıyla çalışır. Uygulama her gün, virüs testi pozitif olan ve uygulamaları aracılığıyla bu bilgileri gönüllü olarak paylaÅŸan tüm kullanıcıların rastgele kimliklerini içeren bir liste ile birlikte bu kullanıcıların semptomlarının baÅŸlangıcına iliÅŸkin gönüllü olarak verilen tüm bilgileri indirir. Ardından bu liste, sizin de enfekte olma olasılığınızı hesaplamak ve gereken durumlarda sizi uyarmak için akıllı telefonunuzun kaydetttiÄŸi diÄŸer kullanıcıların rastgele kimliklerle karşılaÅŸtırılır. Düğmeyi kullanarak dilediÄŸiniz zaman maruz kalma günlüğünü devre dışı bırakabilirsiniz.\n\nUygulama hiçbir durumda adınız, adresiniz veya konumunuz gibi kiÅŸisel verileri toplamaz ve bu bilgileri diÄŸer kullanıcılara aktarmaz. Rastgele kimlikleri kullanarak kiÅŸilerin kimlikleri hakkında sonuçlar çıkarılamaz."</string> + <string name="settings_tracing_body_text">"Uygulamanın, enfekte olan bir kullanıcı ile karşılaÅŸmanızın ardından risk altında olup olmadığınızı belirleyebilmesi için maruz kalma günlüğü özelliÄŸini etkinleÅŸtirmeniz gerekir. Maruz kalma günlüğü özelliÄŸi uluslararası olarak çalışır; yani, kullanıcılara iliÅŸkin tüm olası maruz kalmalar da diÄŸer resmi koronavirüs uygulamalarıyla tespit edilir.\n\nMaruz kalma günlüğü özelliÄŸi, Android akıllı telefonunuzun Bluetooth üzerinden diÄŸer kullanıcıların ÅŸifrelenmiÅŸ rastgele kimliklerini alması ve size ait rastgele kimlikleri diÄŸer kullanıcıların akıllı telefonlarına aktarmasıyla çalışır. Uygulama her gün, virüs testi pozitif olan ve uygulamaları aracılığıyla bu bilgileri (özellikle rastgele kimliklerini) gönüllü olarak paylaÅŸan tüm kullanıcıların rastgele kimliklerini içeren bir liste ile birlikte bu kullanıcıların semptomlarının baÅŸlangıcına iliÅŸkin gönüllü olarak verilen tüm bilgileri indirir. Ardından bu liste, sizin de enfekte olma olasılığınızı hesaplamak ve gereken durumlarda sizi uyarmak için Android akıllı telefonunuzun kaydetttiÄŸi ve karşılaÅŸtığınız diÄŸer kullanıcıların rastgele kimliklerle karşılaÅŸtırılır. Düğmeyi kullanarak dilediÄŸiniz zaman maruz kalma günlüğünü devre dışı bırakabilirsiniz.\n\nUygulama hiçbir durumda adınız, adresiniz veya konumunuz gibi kiÅŸisel verileri toplamaz ve bu bilgileri diÄŸer kullanıcılara aktarmaz. Rastgele kimlikleri kullanarak kiÅŸilerin kimlikleri hakkında sonuçlar çıkarılamaz."</string> <!-- XTXT: settings(tracing) - status next to switch under title --> <string name="settings_tracing_status_active">"Etkin"</string> <!-- XTXT: settings(tracing) - status next to switch under title --> @@ -595,7 +595,7 @@ <!-- XTXT: settings(notification) - next to a switch --> <string name="settings_notifications_subtitle_update_risk">"Enfeksiyon riskiniz deÄŸiÅŸti"</string> <!-- XTXT: settings(notification) - next to a switch --> - <string name="settings_notifications_subtitle_update_test">"COVID-19 testinizin durumu"</string> + <string name="settings_notifications_subtitle_update_test">"Koronavirüs testinizin durumu"</string> <!-- XBUT: settings(notification) - go to operating settings --> <string name="settings_notifications_button_open_settings">"Cihaz Ayarlarını Aç"</string> <!-- XACT: main (overview) - illustraction description, explanation image, displays notificatin status, active --> @@ -604,7 +604,7 @@ <string name="settings_notifications_illustration_description_inactive">"Bir kadın Corona-Warn-App bildirimlerini devre dışı bıraktı."</string> <!-- XBUT: settings - go to reset application --> <string name="settings_reset_title">"Uygulamayı Sıfırla"</string> - <!-- XTXT: settings(reset) - explains the user what do expect when he navigates to reset --> + <!-- XTXT: settings(reset) - explains the user what do expect when navigating to reset --> <string name="settings_reset_body_description">"Uygulamadaki tüm verilerinizi silin."</string> <!-- XHED: settings(reset) - multiline headline below illustration --> <string name="settings_reset_headline">"Uygulamayı sıfırlamak istediÄŸinizden emin misiniz?"</string> @@ -660,7 +660,7 @@ <!-- YTXT: Body text for about information page --> <string name="information_about_body_emphasized">"Robert Koch Institute (RKI), Almanya\'nın federal kamu saÄŸlığı kurumudur. RKI, Federal Hükûmet adına Corona-Warn-App uygulamasını yayınlamaktadır. Uygulama, daha önce açıklanan kamu saÄŸlığı önlemlerine iliÅŸkin dijital bir tamamlayıcı niteliÄŸindedir: sosyal mesafe, hijyen uygulamaları ve yüz maskeleri."</string> <!-- YTXT: Body text for about information page --> - <string name="information_about_body">"Uygulamayı kullanan kiÅŸiler, enfeksiyon zincirlerinin takip edilmesine ve kırılmasına yardımcı olur. Uygulama, diÄŸer kiÅŸilerle karşılaÅŸmaları cihazınızda yerel olarak kaydeder. Daha sonra COVID-19 tanısı konan kiÅŸilerle karşılaÅŸmışsanız size bildirim gönderilir. KimliÄŸiniz ve gizliliÄŸiniz daima koruma altındadır."</string> + <string name="information_about_body">"Uygulamayı kullanan kiÅŸiler, enfeksiyon zincirlerinin takip edilmesine ve kırılmasına yardımcı olur. Uygulama, diÄŸer kiÅŸilerle karşılaÅŸmaları cihazınızda yerel olarak kaydeder. Daha sonra koronavirüs tanısı konan kiÅŸilerle karşılaÅŸmışsanız size bildirim gönderilir. KimliÄŸiniz ve gizliliÄŸiniz daima koruma altındadır."</string> <!-- XACT: describes illustration --> <string name="information_about_illustration_description">"Bölgedeki bir grup insan akıllı telefonlarını kullanıyor."</string> <!-- XHED: Page title for privacy information page, also menu item / button text --> @@ -754,7 +754,7 @@ <!-- XHED: Dialog title for already paired test error: qr --> <string name="submission_error_dialog_web_test_paired_title">"QR kod geçersiz"</string> <!-- XMSG: Dialog body for already paired test error: qr --> - <string name="submission_error_dialog_web_test_paired_body">"QR kod geçersiz veya baÅŸka bir akıllı telefona zaten kaydedilmiÅŸ. QR kod geçerli olsun veya olmasın test sonucunuzu test merkezinden veya laboratuvardan alacaksınız. COVID-19 tanısı alırsanız kamu saÄŸlığı yetkilisi tarafından bilgilendirileceksiniz."</string> + <string name="submission_error_dialog_web_test_paired_body">"QR kod geçersiz veya baÅŸka bir akıllı telefona zaten kaydedilmiÅŸ. QR kod geçerli olsun veya olmasın test sonucunuzu test merkezinden veya laboratuvardan alacaksınız. Koronavirüs tanısı alırsanız kamu saÄŸlığı yetkilisi tarafından bilgilendirileceksiniz."</string> <!-- XHED: Dialog title for already paired test error: tan --> <string name="submission_error_dialog_web_test_paired_title_tan">"TAN geçersiz"</string> <!-- XMSG: Dialog body for already paired test via tan - error: tan --> @@ -784,9 +784,9 @@ <string name="submission_error_dialog_web_tan_redeemed_button_positive">"Tamam"</string> <!-- XHED: Dialog title for keys submission process cancellation --> - <string name="submission_error_dialog_confirm_cancellation_title">"Ä°ptal etmek istiyor musunuz?"</string> + <string name="submission_error_dialog_confirm_cancellation_title">"Belirtilerinizi girmeyi iptal etmek istiyor musunuz?"</string> <!-- XMSG: Dialog body for keys submission process cancellation --> - <string name="submission_error_dialog_confirm_cancellation_body">"GiriÅŸleriniz kaydedilmeyecektir."</string> + <string name="submission_error_dialog_confirm_cancellation_body">"Belirtilerinizle ilgili olarak bilgi verirseniz diÄŸer kullanıcıları daha net bir biçimde uyarabilir."</string> <!-- XBUT: Positive button for keys submission process cancellation --> <string name="submission_error_dialog_confirm_cancellation_button_positive">"Evet"</string> <!-- XBUT: Negative button for keys submission process cancellation --> @@ -814,7 +814,7 @@ <!-- XHED: Dialog headline for invalid QR code --> <string name="submission_qr_code_scan_invalid_dialog_headline">"QR kod geçersiz"</string> <!-- YTXT: Dialog Body text for invalid QR code --> - <string name="submission_qr_code_scan_invalid_dialog_body">"QR kod yanlış veya baÅŸka bir akıllı telefona zaten kaydedilmiÅŸ. QR kod geçerli olsun veya olmasın test sonucunuzu test merkezinden veya laboratuvardan alacaksınız. COVID-19 tanısı alırsanız kamu saÄŸlığı yetkilisi yasal olarak belirlenen kanal üzerinden bilgilendirilecektir ve kamu saÄŸlığı yetkilisi sizinle iletiÅŸime geçecektir."</string> + <string name="submission_qr_code_scan_invalid_dialog_body">"QR kod yanlış veya baÅŸka bir akıllı telefona zaten kaydedilmiÅŸ. QR kod geçerli olsun veya olmasın test sonucunuzu test merkezinden veya laboratuvardan alacaksınız. Koronavirüs tanısı alırsanız kamu saÄŸlığı yetkilisi yasal olarak belirlenen kanal üzerinden bilgilendirilecektir ve kamu saÄŸlığı yetkilisi sizinle iletiÅŸime geçecektir."</string> <!-- XBUT: Dialog(Invalid QR code) - positive button (right) --> <string name="submission_qr_code_scan_invalid_dialog_button_positive">"Lütfen tekrar deneyin."</string> <!-- XBUT: Dialog(Invalid QR code) - negative button (left) --> @@ -825,6 +825,34 @@ <!-- YTXT: instruction text for QR code scanning --> <string name="submission_qr_code_scan_body">"QR kodu çerçeveye sığdırın."</string> + <!-- QR Code Consent Screen --> + <!-- XHED: Page headline for Submission consent --> + <string name="submission_consent_main_headline">"Onayınız"</string> + <!-- YTXT: Body for Submissionconsent --> + <string name="submission_consent_main_headline_body">"Test sonucunuzu alabilmeniz ve diÄŸer kullanıcıları uyarabilmeniz için onayınız gereklidir."</string> + <!-- XHED: Page subheadline for consent call test result --> + <string name="submission_consent_call_test_result">"Test Sonucunu Al"</string> + <!-- YTXT: Body for Submission Consent call test result body --> + <string name="submission_consent_call_test_result_body">"Sonraki adımda, testinizdeki QR kodu tarayın ve test sonucunuzu alın."</string> + <!-- YTXT: Body sub text 1 for Submission Consent call test result --> + <string name="submission_consent_call_test_result_scan_your_test_only">"Yalnızca kendi testinizi tarayın."</string> + <!-- YTXT: Body sub text 2 for Submission Consent call test result --> + <string name="submission_consent_call_test_result_scan_test_only_once">"Testiniz yalnızca bir kez taranabilir. Uygulama aynı anda birden fazla testi yönetememektedir."</string> + <!-- XHED: Page subheadline for consent help by warning others --> + <string name="submission_consent_help_by_warning_others_headline">"Lütfen karşılaÅŸtığınız diÄŸer kullanıcıları uyararak onlara yardımcı olun!"</string> + <!-- YTXT: Body for consent help by warning others --> + <string name="submission_consent_help_by_warning_others_body">"Koronavirüs tanısı aldıysanız uygulama üzerinden diÄŸer kullanıcıları uyarabilirsiniz. Uyarı iÅŸlevi birden fazla ülkede etkindir. Åžu anda aÅŸağıdaki ülkeler katılmaktadır:"</string> + <!-- YTXT: Page bottom text for consent screen --> + <string name="submission_consent_main_bottom_body">"Veri Ä°ÅŸleme ve Onayınız Hakkında Ayrıntılı Bilgiler"</string> + <!-- YTXT: Body for consent main section first point --> + <string name="submission_consent_main_first_point">"Onayınız gönüllülük esasına dayalıdır."</string> + <!-- YTXT: Body for consent main section second point --> + <string name="submission_consent_main_second_point">"PaylaÅŸmamayı seçseniz de test sonucunuzu alabilirsiniz. Ancak test sonucunuzu paylaşırsanız diÄŸer kullanıcıların enfeksiyona karşı korunmasına yardımcı olursunuz."</string> + <!-- YTXT: Body for consent main section third point --> + <string name="submission_consent_main_third_point">"KimliÄŸiniz gizli tutulacaktır. DiÄŸer kullanıcılar, kimin test sonucunu paylaÅŸtığını bilmeyecektir."</string> + <!-- YTXT: Body for consent main section fourth point --> + <string name="submission_consent_main_fourth_point">"Onay vermek için 16 yaşın üzerinde olmanız gerekir."</string> + <!-- Submission Test Result --> <!-- XHED: Page headline for test result --> <string name="submission_test_result_headline">"Test Sonucu"</string> @@ -835,9 +863,9 @@ <!-- YTXT: Body text for for results next steps --> <string name="submission_test_result_steps_added_body">"Testiniz Corona-Warn-App\'e kaydedildi."</string> <!-- XHED: Page headline for pending test result next steps --> - <string name="submission_test_result_pending_steps_waiting_heading">"Test sonucu henüz çıkmadı"</string> + <string name="submission_test_result_pending_steps_waiting_heading">"Test sonucunuz henüz çıkmadı."</string> <!-- YTXT: Body text for next steps section of waiting test result page --> - <string name="submission_test_result_pending_steps_waiting_body">"DeÄŸerlendirme birkaç gün sürebilir, bu nedenle lütfen sabırlı olun.\n\nTest sonucunuz uygulama dışından da tarafınıza iletilecektir. Testinizin pozitif sonuç vermesi halinde kamu saÄŸlığı yetkilileri sizi bilgilendirecektir.\n\nTest sonucunun pozitif olması halinde sonucu uygulamaya kaydetmek ve diÄŸer kullanıcıları uyarmak için lütfen \"TAN Talebi\" baÅŸlığının altında görüntülenen numarayı arayın."</string> + <string name="submission_test_result_pending_steps_waiting_body">"Test sonucunuz çıkar çıkmaz uygulamada görüntülenecektir."</string> <!-- XBUT: test result pending : refresh button --> <string name="submission_test_result_pending_refresh_button">"Güncelle"</string> <!-- XBUT: test result pending : remove the test button --> @@ -845,7 +873,7 @@ <!-- XHED: Page headline for negative test result next steps --> <string name="submission_test_result_negative_steps_negative_heading">"Test Sonucunuz"</string> <!-- YTXT: Body text for next steps section of test negative result --> - <string name="submission_test_result_negative_steps_negative_body">"Laboratuvar sonucuna göre koronavirüs SARS-CoV-2 olduÄŸunuza dair bir doÄŸrulama yok.\n\nGerekirse yeni bir test kodu kaydedebilmeniz için lütfen testi Corona-Warn-App\'ten silin."</string> + <string name="submission_test_result_negative_steps_negative_body">"Laboratuvar sonucuna göre SARS-CoV-2 koronavirüs olduÄŸunuza dair bir doÄŸrulama yok.\n\nGerekirse yeni bir test kodu kaydedebilmeniz için lütfen testi Corona-Warn-App\'ten silin."</string> <!-- XBUT: negative test result : remove the test button --> <string name="submission_test_result_negative_remove_test_button">"Testi Sil"</string> <!-- XHED: Page headline for other warnings screen --> @@ -873,7 +901,7 @@ <!-- XHED: Dialog title for test removal --> <string name="submission_test_result_dialog_remove_test_title">"Test yalnızca bir kez taranabilir."</string> <!-- YTXT: Dialog text for test removal --> - <string name="submission_test_result_dialog_remove_test_message">"Testi kaldırırsanız test sonucunuzu alamazsınız. QR kod geçerli olsun veya olmasın test sonucunuzu test merkezinden veya laboratuvardan alacaksınız. COVID-19 tanısı alırsanız kamu saÄŸlığı yetkilisi yasal olarak belirlenen kanal üzerinden bilgilendirilecektir ve kamu saÄŸlığı yetkilisi sizinle iletiÅŸime geçecektir."</string> + <string name="submission_test_result_dialog_remove_test_message">"Testi kaldırırsanız test sonucunuzu alamazsınız. QR kod geçerli olsun veya olmasın test sonucunuzu test merkezinden veya laboratuvardan alacaksınız. Koronavirüs tanısı alırsanız kamu saÄŸlığı yetkilisi yasal olarak belirlenen kanal üzerinden bilgilendirilecektir ve kamu saÄŸlığı yetkilisi sizinle iletiÅŸime geçecektir."</string> <!-- XBUT: Positive button for test removal --> <string name="submission_test_result_dialog_remove_test_button_positive">"Kaldır"</string> <!-- XBUT: Negative button for test removal --> @@ -882,6 +910,16 @@ <string name="submission_test_result_card_positive_title">"SARS-CoV-2 pozitif"</string> <!-- YTXT: Body text for test result card positive --> <string name="submission_test_result_card_positive_body">"SARS-CoV-2 virüsü tanısı aldınız."</string> + <!-- XHED: Page headline for test result with consent given --> + <string name="submission_test_result_consent_given_heading">"Test Sonucunuz"</string> + <!-- XHED: Subtitle text for test result card with consent given --> + <string name="submission_test_result_consent_given_subtitle">"Koronavirüsün yayılmasını durdurmaya yardımcı olduÄŸunuz için teÅŸekkür ederiz."</string> + <!-- YTXT: body text for test result card with consent given --> + <string name="submission_test_result_consent_given_body"><b>"Åžimdi temasta bulunduÄŸunuz diÄŸer kullanıcılar uyarılacak."</b>" "<br/><br/>"Uyarıların daha doÄŸru olmasını saÄŸlamaya yardımcı olabilirsiniz. Bunun için sonraki adımda belirtilerinizin ilk kez ne zaman görülmeye baÅŸladığını belirtin. Bu adımı dilediÄŸiniz zaman iptal edebilirsiniz."</string> + <!-- XBUT: button text for the 'break up' button option on test result consent given page --> + <string name="submission_test_result_consent_given_breakup_button">"Çıkış"</string> + + <!-- Submission Tan --> <!-- XHED: Page title for TAN submission pge --> @@ -903,7 +941,7 @@ <!-- XHED: Page headline for menu the at start of the submission process --> <string name="submission_intro_headline">"Corona-Warn-App bu ÅŸekilde çalışır"</string> <!-- YTXT: submission introduction text --> - <string name="submission_intro_text">"Uygulamanın düzgün çalışması için COVID-19 tanısı konan kiÅŸilerin desteÄŸine güveniyoruz.\n\nYalnızca ÅŸifrelenmiÅŸ rastgele kimlikler gönderilip alındığından kimliÄŸiniz gizli kalır. Åžu ÅŸekilde devam edebilirsiniz:"</string> + <string name="submission_intro_text">"Uygulamanın düzgün çalışması için koronavirüs tanısı konan kiÅŸilerin desteÄŸine güveniyoruz.\n\nYalnızca ÅŸifrelenmiÅŸ rastgele kimlikler gönderilip alındığından kimliÄŸiniz gizli kalır. Åžu ÅŸekilde devam edebilirsiniz:"</string> <!-- XBUT: Submission introduction next button--> <string name="submission_intro_button_next">"Sonraki"</string> <!-- XACT: Submission intro - illustration description, explanation image --> @@ -911,7 +949,7 @@ <!-- YTXT: submission introduction bullet points --> <string-array name="submission_intro_bullet_points"> <item>"Test belgenizde bir QR kod varsa bu kodu tarayıp testi kaydedebilirsiniz. Sonuç çıkar çıkmaz sonucu uygulamada görüntüleyebilirsiniz."</item> - <item>"Size COVID-19 tanısı konduysa diÄŸer insanları uyarabilirsiniz."</item> + <item>"Size koronavirüs tanısı konduysa diÄŸer insanları uyarabilirsiniz."</item> <item>"Pozitif tanı için TAN verildiyse bunu kullanarak testi kaydedebilirsiniz."</item> <item>"TAN verilmediyse telefonla talep edebilirsiniz."</item> </string-array> @@ -920,25 +958,25 @@ <!-- Dispatcher --> <!-- XHED: Page headline for dispatcher menu --> - <string name="submission_dispatcher_headline">"Seçim"</string> + <string name="submission_dispatcher_headline">"Test Sonucunu Al"</string> <!-- XHED: Page subheadline for dispatcher menu --> - <string name="submission_dispatcher_subheadline">"Hangi bilgilere sahipsiniz?"</string> + <string name="submission_dispatcher_subheadline">"Uygulama üzerinden test sonucunuzu alın ve ardından diÄŸer kullanıcıları uyarın. Kendinizi koruyacak ve koronavirüsün yayılmasını durdurmaya yardımcı olacaksınız."</string> <!-- XHED: Page subheadline for dispatcher options asking if they have already been tested: QR and TAN --> - <string name="submission_dispatcher_needs_testing_subheadline">""</string> + <string name="submission_dispatcher_needs_testing_subheadline">"Test yaptırdınız mı?"</string> <!-- XHED: Page subheadline for dispatcher options asking if they already have a positive test: tele-TAN --> - <string name="submission_dispatcher_already_positive_subheadline">""</string> + <string name="submission_dispatcher_already_positive_subheadline">"Koronavirüs testinizin sonucu pozitif mi?"</string> <!-- YTXT: Dispatcher text for QR code option --> - <string name="submission_dispatcher_card_qr">"QR kod ile belgeleyin"</string> + <string name="submission_dispatcher_card_qr">"QR Kodlu Test"</string> <!-- YTXT: Body text for QR code dispatcher option --> <string name="submission_dispatcher_qr_card_text">"Test belgenizin QR kodunu tarayarak testinizi kaydedin."</string> <!-- YTXT: Dispatcher text for TAN code option --> - <string name="submission_dispatcher_card_tan_code">"TAN"</string> + <string name="submission_dispatcher_card_tan_code">"TAN GiriÅŸi"</string> <!-- YTXT: Body text for TAN code dispatcher option --> - <string name="submission_dispatcher_tan_code_card_text">"TAN\'yi manüel olarak girerek kaydedin."</string> + <string name="submission_dispatcher_tan_code_card_text">"TAN\'niz var mı? DiÄŸer kullanıcıları uyarabilmek için TAN\'nizi girmek üzere devam edin. "</string> <!-- YTXT: Dispatcher text for TELE-TAN option --> - <string name="submission_dispatcher_card_tan_tele">"TAN Talebi"</string> + <string name="submission_dispatcher_card_tan_tele">"TAN yok mu?"</string> <!-- YTXT: Body text for TELE_TAN dispatcher option --> - <string name="submission_dispatcher_tan_tele_card_text">"COVID-19 tanısı konduysa lütfen bizi arayın."</string> + <string name="submission_dispatcher_tan_tele_card_text">"Bizi arayın ve TAN alın."</string> <!-- XACT: Dispatcher Tan page title --> <string name="submission_dispatcher_accessibility_title">"Hangi bilgilere sahipsiniz?"</string> @@ -956,6 +994,25 @@ <!-- XHED: Title for the interop country list--> <string name="submission_interoperability_list_title">"AÅŸağıdaki ülkeler, uluslararası maruz kalma günlüğüne katılmaktadır:"</string> + <!-- Submission Positive Other Warning No Consent --> + <!-- YTXT: Body text for the positive result additional warning page--> + <string name="submission_positive_other_warning_no_consent_body_first_part">"Koronavirüs testinizin sonucu pozitif olduÄŸu için ÅŸimdi diÄŸer kullanıcıları uygulama üzerinden uyarabilirsiniz."</string> + <!-- YTXT: Body text for the positive result additional warning page--> + <string name="submission_positive_other_warning_no_consent_body_second_part">"Uyarı iÅŸlevi birden fazla ülkede etkindir. Åžu anda aÅŸağıdaki ülkeler katılmaktadır:"</string> + + + <!-- Test result positive and no consent given --> + <!-- XHED: Title for test result positive and no consent given--> + <string name="submission_test_result_positive_no_consent_subtitle">"Lütfen hepimize yardımcı olun!"</string> + <!-- XTXT: First bullet point when test result is positive and consent is requested for key sharing--> + <string name="submission_test_result_positive_no_consent_text_1"><b>"Test sonucunuzu paylaşın ve diÄŸer kullanıcıların enfeksiyondan korunmasına yardımcı olun."</b></string> + <!-- XTXT: Second bullet point when test result is positive and consent is requested for key sharing--> + <string name="submission_test_result_positive_no_consent_text_2">"KimliÄŸiniz gizli tutulacaktır. DiÄŸer kullanıcılar, kimin test sonucunu paylaÅŸtığını bilmeyecektir."</string> + <!-- XTXT: Third bullet point when test result is positive and consent is requested for key sharing--> + <string name="submission_test_result_positive_no_consent_text_3">"BaÅŸka insanların enfeksiyona yakalanmaması için lütfen kamu saÄŸlığı yetkilinizin talimatlarına uyun ve evde kalın."</string> + <!-- XBUT: Button for giving consent for key sharing --> + <string name="submission_test_result_positive_no_consent_button_warn_others">"DiÄŸer Kullanıcıları Uyarın"</string> + <!-- Submission Country Selector --> <!-- XHED: Page title for the submission country selection page --> <string name="submission_positive_country_selection_title">"Avrupa geneli uyarılar"</string> @@ -995,13 +1052,29 @@ <!-- XACT: submission finished - illustration description, explanation image --> <string name="submission_done_illustration_description">"Son birkaç günde aÅŸağıdaki belirtilerden birini veya daha fazlasını yaÅŸadınız mı?"</string> + <!-- Submission Done No Consent--> + <!-- XHED: Page title for completed submission page --> + <string name="submission_done_no_consent_title">"TeÅŸekkür ederiz"</string> + <!-- YTXT: Page subtitle for completed submission page --> + <string name="submission_done_no_consent_subtitle">"Koronavirüsün yayılmasını durdurmaya yardımcı olduÄŸunuz için teÅŸekkür ederiz."</string> + <!-- YTXT: Page body for submission no consent page --> + <string name="submission_done_no_consent_body_title">"Åžimdi diÄŸer kullanıcılar uyarılacak."</string> + <!-- YTXT: Page body for submission no consent page --> + <string name="submission_done_no_consent_body">"Uyarıların daha doÄŸru olmasını saÄŸlamaya yardımcı olabilirsiniz. Bunun için sonraki adımda belirtilerinizin ilk kez ne zaman görülmeye baÅŸladığını belirtin. Bu adımı dilediÄŸiniz zaman iptal edebilirsiniz."</string> + <!-- XBUT: submission continue with symptom recording button --> + <string name="submission_done_no_consent_continue_with_symptom_recording">"Semptomları Gir"</string> + <!-- XBUT: submission continue break flow button--> + <string name="submission_done_no_consent_break_flow">"Çıkış"</string> + <!-- XACT: submission finished - illustration description, explanation image --> + <string name="submission_done_no_consent_illustration_description">"Birden fazla kiÅŸi akıllı telefonlarına bakıyor."</string> + <!-- Submission Symptoms --> <!-- XHED: Page title for symptom screens --> <string name="submission_symptom_title">"Belirtiler"</string> <!-- XTXT: headline text for initial symptom screen --> - <string name="submission_symptom_initial_headline">"AÅŸağıdaki belirtilerden birini veya daha fazlasını yaÅŸadınız mı?"</string> + <string name="submission_symptom_initial_headline">"Son birkaç günde aÅŸağıdaki belirtilerden birini veya daha fazlasını yaÅŸadınız mı?"</string> <!-- YTXT: explanation text for initial symptom screen --> - <string name="submission_symptom_initial_explanation">"Uygulamanın, diÄŸer kullanıcılar açısından enfeksiyon riskini daha doÄŸru bir biçimde hesaplayabilmesi için herhangi bir korona belirtisi fark edip etmediÄŸinizi ve ne zaman fark ettiÄŸinizi belirtebilirsiniz. Bu bilgileri saÄŸlamak istemiyorsanız \"bilgi yok\" seçeneÄŸini belirlemeniz yeterlidir."</string> + <string name="submission_symptom_initial_explanation">"Uygulamanın, diÄŸer kullanıcılar açısından enfeksiyon riskini daha doÄŸru bir biçimde hesaplayabilmesi için herhangi bir korona belirtisi fark edip etmediÄŸinizi ve ne zaman fark ettiÄŸinizi belirtebilirsiniz. Bu adım gönüllülük esasına dayanır. Belirtilerinizle ilgili bilgi vermek istemiyorsanız \"Bilgi yok\" seçeneÄŸini belirlemeniz yeterlidir."</string> <!-- YTXT: Bullet points for symptoms --> <string-array name="submission_symptom_symptom_bullets"> <item>"Artan vücut sıcaklığı veya ateÅŸ"</item> @@ -1058,9 +1131,9 @@ <!-- XHED: Page title for calendar page in submission symptom flow --> <string name="submission_symptom_calendar_title">"Belirtilerin baÅŸlangıcı"</string> <!-- XHED: Page headline for calendar page in symptom submission flow --> - <string name="submission_symptom_calendar_headline">"Bu belirtileri ilk kez ne zaman yaÅŸamaya baÅŸladınız? "</string> + <string name="submission_symptom_calendar_headline">"Belirtileri ilk kez ne zaman fark ettiniz?"</string> <!-- YTXT: Body text for calendar page in symptom submission flow--> - <string name="submission_symptom_calendar_body">"Takvimde tam tarihi seçin veya tam tarihi hatırlayamıyorsanız diÄŸer seçeneklerden birini seçin."</string> + <string name="submission_symptom_calendar_body">"Lütfen mümkün olduÄŸunca doÄŸru ÅŸekilde tarih belirtin."</string> <!-- XBUT: symptom calendar screen less than 7 days button --> <string name="submission_symptom_less_seven">"Son 7 gün içinde"</string> <!-- XBUT: symptom calendar screen 1-2 weeks button --> @@ -1076,9 +1149,9 @@ <!-- XHED: Page title for the various submission status: unregistered --> <string name="submission_status_card_title_unregistered">"Test yaptırdınız mı?"</string> <!-- XHED: Page title for the various submission status: pending --> - <string name="submission_status_card_title_pending">"Sonucunuz henüz çıkmadı"</string> + <string name="submission_status_card_title_pending">"Test sonucunuz henüz çıkmadı"</string> <!-- XHED: Page title for the various submission status: available --> - <string name="submission_status_card_title_available">"Sonucunuz çıktı"</string> + <string name="submission_status_card_title_available">"Test sonucunuz çıktı"</string> <!-- XHED: Page title for the various submission status: positive --> <string name="submission_status_card_title_positive">"Pozitif Tanı"</string> <!-- XHED: Page title for the various submission status fetch failed --> @@ -1090,7 +1163,7 @@ <!-- YTXT: Body text for submission status: fetching --> <string name="submission_status_card_body_fetching">"Sonucunuz güncelleniyor"</string> <!-- YTXT: Body text for submission status: unregistered --> - <string name="submission_status_card_body_unregistered">"DiÄŸer kullanıcıları uyararak enfeksiyon zincirini kırmaya yardımcı olun."</string> + <string name="submission_status_card_body_unregistered">"Kendinizi ve diÄŸer kullanıcıları korumaya yardımcı olun."</string> <!-- YTXT: Body text for submission status: pending --> <string name="submission_status_card_body_pending">"Testinize iliÅŸkin deÄŸerlendirme henüz tamamlanmadı."</string> <!-- YTXT: Body text for submission status: invalid --> @@ -1102,7 +1175,7 @@ <!-- YTXT: Body text for submission status fetch failed --> <string name="submission_status_card_body_failed">"Testiniz 21 günden eski ve bu nedenle artık geçerli deÄŸil. Lütfen testi silin. Ardından baÅŸka bir test ekleyebilirsiniz."</string> <!-- XBUT: submission status card unregistered button --> - <string name="submission_status_card_button_unregistered">"Daha Fazla Bilgi ve Yardım"</string> + <string name="submission_status_card_button_unregistered">"Sonraki Adımlar"</string> <!-- XBUT: submission status card show results button --> <string name="submission_status_card_button_show_results">"Testi Görüntüle"</string> <!-- XBUT: submission status card fetch failed button --> @@ -1140,7 +1213,51 @@ </string-array> <!-- XBUT Symptoms exact date button --> - <string name="symptoms_calendar_exact_date_button">"Tam tarih"</string> + <string name="symptoms_calendar_exact_date_button">"Tarih"</string> + + <!-- Submission consent custom view --> + <!-- XHED: Title for consent given --> + <string name="submission_consent_view_consent_given">"“DiÄŸer kullanıcıları uyarâ€\nonayı verildi"</string> + <!-- XHED: Title for consent NOT given --> + <string name="submission_consent_view_consent_not_given">"“DiÄŸer kullanıcıları uyarâ€\nonayı verilmedi"</string> + + <!-- Submission test result available --> + <!-- XHED: Page title for test results available step --> + <string name="submission_test_result_available_title">"Test Sonucunuz Çıktı"</string> + <!-- XACT: Test result available illustration description --> + <string name="submission_test_result_available_illustration_description">"Bir kadın elinde akıllı telefonunu tutuyor. Bu telefondan baÅŸka bir akıllı telefona sinyal gönderiliyor."</string> + <!-- YTXT: Text for consent given --> + <string name="submission_test_result_available_text_consent_given">"Test sonucunuzu paylaÅŸmayı kabul ederek diÄŸer kullanıcıların uyarılmasına yardımcı olduÄŸunuz için teÅŸekkür ederiz. \n\n"<b>"Sonraki adımda lütfen “Paylaş†seçeneÄŸine dokunarak test sonucunuzu paylaşın."</b></string> + <!-- XHED: Close screen popup title for consent given --> + <string name="submission_test_result_available_close_dialog_title_consent_given">"Ä°ptal etmek istiyor musunuz?"</string> + <!-- XTXT: Close screen popup text for consent given --> + <string name="submission_test_result_available_close_dialog_body_consent_given">"GiriÅŸleriniz kaydedilmeyecektir."</string> + <!-- YTXT: Text for consent NOT given --> + <string name="submission_test_result_available_text_consent_not_given">"Test sonuçlarınızı paylaÅŸmamayı seçtiniz. DiÄŸer kullanıcılar uyarılmayacak. \n\nSonraki adımda dilerseniz fikrinizi deÄŸiÅŸtirip test sonucunuzu paylaÅŸarak koronavirüsün yayılmasını durdurmaya ve diÄŸer kullanıcıların korunmasına yardımcı olabilirsiniz."</string> + <!-- XHED: Close screen popup title for consent NOT given --> + <string name="submission_test_result_available_close_dialog_title_consent_not_given">"Önemli:\nBu iÅŸlemi iptal etmek üzeresiniz.\nHenüz diÄŸer kullanıcıları uyarmadınız. Lütfen bu iÅŸlemi tamamlayın ve diÄŸer kullanıcıların korunmasına yardımcı olun."</string> + <!-- XTXT: Close screen popup text for consent NOT given --> + <string name="submission_test_result_available_close_dialog_body_consent_not_given">"Ä°ÅŸlemi gerçekten iptal etmek istiyor musunuz?"</string> + <!-- XBUT: Close screen popup cancel button --> + <string name="submission_test_result_available_close_dialog_cancel_button">"Ä°ptal"</string> + <!-- XBUT: Close screen popup continue button --> + <string name="submission_test_result_available_close_dialog_continue_button">"Devam"</string> + + <!-- Submission your consent screen --> + <!-- XHED: Your consent screen title --> + <string name="submission_your_consent_title">"Ä°zniniz"</string> + <!-- XTXT: Your consent screen switch label - next to a switch --> + <string name="submission_your_consent_switch_subtitle">"DiÄŸer Kullanıcıları Uyarın"</string> + <!-- XTXT: Your consent screen switch status on --> + <string name="submission_your_consent_switch_status_on">"Etkin"</string> + <!-- XTXT: Your consent screen switch status off --> + <string name="submission_your_consent_switch_status_off">"Durduruldu"</string> + <!-- XTXT: Your consent screen about agreement --> + <string name="submission_your_consent_about_agreement">"Åžu onayı verdiniz:"</string> + <!-- XHED: Your consent screen agreement title --> + <string name="submission_your_consent_agreement_title"><b>"Onay"</b></string> + <!-- XTXT: Your consent screen detailed information --> + <string name="submission_your_consent_agreement_details">"Veri Ä°ÅŸleme ve Onayınız Hakkında Ayrıntılı Bilgiler"</string> <!-- #################################### Button Tooltips for Accessibility @@ -1215,8 +1332,6 @@ <!-- NOTR --> <string name="test_api_button_show_qr_code">"Show QR Code"</string> <!-- NOTR --> - <string name="test_api_button_submit_keys">"Submit keys to Server"</string> - <!-- NOTR --> <string name="test_api_button_scan_qr_code">"Scan Exposure Key"</string> <!-- NOTR --> <string name="test_api_switch_last_three_hours_from_server">"Last 3 Hours Mode"</string> @@ -1309,7 +1424,7 @@ <!-- XTXT: First section after the header of the interoperability information/configuration view --> <string name="interoperability_configuration_first_section">"Bazı ülkeler, ortak bir exchange sunucusu üzerinden uluslararası uyarıları etkinleÅŸtirmek üzere birlikte çalışma yürütmektedir. ÖrneÄŸin, diÄŸer katılımcı ülkelerin resmi koronavirüs uygulamasının kullanıcıları ile temaslar da maruz kalma günlüğünde hesaba katılabilir."</string> <!-- XTXT: Second section after the header of the interoperability information/configuration view --> - <string name="interoperability_configuration_second_section">"Bunun için uygulama, uygulamaları aracılığıyla kendi rastgele kimliklerini paylaÅŸan tüm kullanıcıların rastgele kimliklerinin bir listesini (günlük olarak güncellenir) indirir. Ardından bu liste, akıllı telefonunuzun kaydettiÄŸi rastgele kimliklerle karşılaÅŸtırılır. Normal koÅŸullarda, rastgele kimlikleri içeren listenin günlük olarak indirilmesi için ücret alınmaz, bu baÄŸlamda uygulamanın kullandığı veriler için de ücret alınmaz ve diÄŸer AB ülkelerinde bunun için dolaşım ücretleri de alınmaz."</string> + <string name="interoperability_configuration_second_section">"Bunun için uygulama kendi uygulamalarından diÄŸer kullanıcıları uyarmak için test sonuçlarını paylaÅŸan tüm kullanıcıların rastgele kimliklerinden oluÅŸan ve günlük olarak güncellenen bir listeyi indirir. Ardından bu liste Android akıllı telefonunuzun kaydettiÄŸi rastgele kimliklerle karşılaÅŸtırılır. Liste indirmeleri genellikle ücretsizdir. Buna göre, mobil aÄŸ operatörleri uygulamanın bu baÄŸlamda kullandığı veriler için ücret almaz ve bu doÄŸrultuda, diÄŸer AB ülkelerindeki kullanımlar için dolaşım ücreti almaz. Daha fazla bilgi için lütfen mobil aÄŸ operatörünüzle iletiÅŸime geçin."</string> <!-- XHED: Header right above the country list in the interoperability information/configuration view --> <string name="interoperability_configuration_list_title">"AÅŸağıdaki ülkeler, uluslararası maruz kalma günlüğüne katılmaktadır:"</string> <!-- XTXT: Text right under the country list in the interoperability information/configuration view --> @@ -1320,9 +1435,9 @@ <!-- YMSG: Onboarding tracing step first section in interoperability after the title --> <string name="interoperability_onboarding_first_section">"Bazı ülkeler uluslararası uyarıları etkinleÅŸtirmek üzere iÅŸ birliÄŸi yapmaktadır. DiÄŸer bir ifadeyle, tüm katılımcı ülkelerdeki resmi korona uygulamalarının kullanıcılarına maruz kalma olasılığınız da artık hesaba katılabilir."</string> <!-- YMSG: Onboarding tracing step second section in interoperability after the title --> - <string name="interoperability_onboarding_second_section">"Bir kullanıcı, katılımcı ülkeler tarafından ortak olarak iÅŸletilen exchange sunucusuna rastgele kimliklerini gönderdiÄŸinde tüm bu ülkelerdeki resmi korona uygulamalarının kullanıcıları maruz kalma olasılığı konusunda uyarılabilir."</string> + <string name="interoperability_onboarding_second_section">"Bir kullanıcı, diÄŸer kullanıcıları uyarmak için uygulama üzerinden pozitif test sonucunu (daha doÄŸru bir ifadeyle rastgele kimliklerini) katılımcı ülkeler tarafından ortak olarak iÅŸletilen exchange sunucusuna gönderdiÄŸinde tüm bu ülkelerdeki resmi korona uygulamalarının tüm kullanıcıları maruz kalma olasılığı konusunda uyarılabilir."</string> <!-- YMSG: Onboarding tracing step third section in interoperability after the title. --> - <string name="interoperability_onboarding_randomid_download_free">"Rastgele kimlikleri içeren bu listenin günlük olarak indirilmesi için ücret alınmaz. Buna göre, mobil aÄŸ operatörleri uygulamanın bu baÄŸlamda kullandığı veriler için ücret almaz ve bu doÄŸrultuda, diÄŸer AB ülkelerindeki kullanımlar için dolaşım ücreti almaz. Daha fazla bilgi için lütfen mobil aÄŸ operatörünüzle iletiÅŸime geçin."</string> + <string name="interoperability_onboarding_randomid_download_free">"Pozitif test sonuçlarını paylaÅŸan kullanıcıların rastgele kimliklerini içeren listelerin günlük olarak indirilmesi için ücret alınmaz. Buna göre, mobil aÄŸ operatörleri uygulamanın bu baÄŸlamda kullandığı veriler için ücret almaz ve bu doÄŸrultuda, diÄŸer AB ülkelerindeki kullanımlar için dolaşım ücreti almaz. Daha fazla bilgi için lütfen mobil aÄŸ operatörünüzle iletiÅŸime geçin."</string> <!-- XTXT: Small header above the country list in the onboarding screen for interoperability. --> <string name="interoperability_onboarding_list_title">"Åžu anda aÅŸağıdaki ülkeler katılmaktadır:"</string> @@ -1337,9 +1452,9 @@ <!-- XTXT: Description of the interoperability extension of the app. Below interoperability_onboarding_delta_title --> <string name="interoperability_onboarding_delta_subtitle">"Corona-Warn-App\'in özellikleri geniÅŸletildi. Çok sayıda ülke, ortak olarak iÅŸletilen bir exchange sunucusu bazında uluslararası uyarıları etkinleÅŸtirmek üzere iÅŸ birliÄŸi yapmıştır. Maruz kalma riskiniz hesaplanırken diÄŸer katılımcı ülkelerdeki resmi korona uygulamalarının kullanıcılarına maruz kalıp kalmadığınız da artık hesaba katılabilir."</string> <!-- YMSG: Onboarding tracing step third section in interoperability after the title. --> - <string name="interoperability_onboarding_delta_randomid">"Bunun için uygulama, rastgele kimliklerini kendi uygulamaları üzerinden paylaÅŸan tüm kullanıcıların rastgele kimliklerinden oluÅŸan ve günlük olarak güncellenen bir listeyi indirir. Ardından bu liste cihazınızın kaydettiÄŸi rastgele kimliklerle karşılaÅŸtırılır."</string> + <string name="interoperability_onboarding_delta_randomid">"Bunun için uygulama, diÄŸer kullanıcıları uyarmak üzere test sonuçlarını kendi uygulamaları üzerinden paylaÅŸan tüm kullanıcıların rastgele kimliklerinden oluÅŸan ve günlük olarak güncellenen bir listeyi indirir. Ardından bu liste Android akıllı telefonunuzun kaydettiÄŸi rastgele kimliklerle karşılaÅŸtırılır."</string> <!-- YMSG: Onboarding tracing step third section in interoperability after the title. --> - <string name="interoperability_onboarding_delta_free_download">"Rastgele kimlikleri içeren bu listenin günlük olarak indirilmesi için ücret alınmaz. Buna göre, mobil aÄŸ operatörleri uygulamanın bu baÄŸlamda kullandığı veriler için ücret almaz ve bu doÄŸrultuda, diÄŸer AB ülkelerindeki kullanımlar için dolaşım ücreti almaz. Daha fazla bilgi için lütfen mobil aÄŸ operatörünüzle iletiÅŸime geçin."</string> + <string name="interoperability_onboarding_delta_free_download">"Liste indirmeleri genellikle ücretsizdir. Buna göre, mobil aÄŸ operatörleri uygulamanın bu baÄŸlamda kullandığı veriler için ücret almaz ve bu doÄŸrultuda, diÄŸer AB ülkelerindeki kullanımlar için dolaşım ücreti almaz. Daha fazla bilgi için lütfen mobil aÄŸ operatörünüzle iletiÅŸime geçin."</string> <!-- XACT: interoperability (eu) - illustraction description, explanation image --> <string name="interoperability_eu_illustration_description">"Birinin elinde akıllı telefon tutuluyor. Arka planda Avrupa ve Avrupa bayrağı gösterilmektedir."</string> @@ -1356,4 +1471,15 @@ <!-- XBUT: Title for the interoperability onboarding Settings-Button if no network is available --> <string name="interoperability_onboarding_list_button_title_no_network">"Cihaz Ayarlarını Aç"</string> -</resources> + <!-- XHED: Title for the dialog on test result positive no consent screen --> + <string name="submission_test_result_positive_no_consent_dialog_title">"Uyarı göndermek istiyor musunuz?"</string> + <!-- XTXT: Message for the dialog on test result positive no consent screen --> + <string name="submission_test_result_positive_no_consent_dialog_message">"DiÄŸer kullanıcıları uyarmak istiyorsanız test sonucunuzu paylaÅŸmanız gereklidir."</string> + <!-- XBUT: Positive button for the dialog on test result positive no consent screen --> + <string name="submission_test_result_positive_no_consent_dialog_positive_button">"DiÄŸer kullanıcıları uyar"</string> + <!-- XBUT: Negative button for the dialog on test result positive no consent screen --> + <string name="submission_test_result_positive_no_consent_dialog_negative_button">"DiÄŸer kullanıcıları uyarma"</string> + <!-- XBUT: Abort button for test result positive no consent screen --> + <string name="submission_test_result_positive_no_consent_button_abort">"Ä°ptal"</string> + +</resources> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/values/legal_strings.xml b/Corona-Warn-App/src/main/res/values/legal_strings.xml index c1b6212e5dc2d7d35e3f7359d6344a76a7fdb21c..ad3f40f78b4881f6a0b61d6a44069ec6e040d3b4 100644 --- a/Corona-Warn-App/src/main/res/values/legal_strings.xml +++ b/Corona-Warn-App/src/main/res/values/legal_strings.xml @@ -14,23 +14,23 @@ <!-- YTXT: onboarding(tracing) - body for consent information --> <string name="onboarding_tracing_body_consent" translatable="false">"You need to enable exposure logging to find out whether you have had possible exposures involving app users in the participating countries and are therefore at risk of infection yourself. By tapping on the “Enable exposure logging†button, you agree to enabling the exposure logging feature and to the associated data processing by the app.\n\nIn order to use the exposure logging feature, you will also have to enable the “COVID-19 Exposure Notifications†functionality provided by Google on your Android smartphone and grant the Corona-Warn-App permission to use this.\n\nYour Android smartphone will then continuously generate random IDs and send them via Bluetooth so that they can be received by other smartphones near you. Your Android smartphone, in turn, receives the random IDs of other smartphones. Your own random IDs and those received from other smartphones are recorded by your Android smartphone and stored there for 14 days.\n\nFor exposure logging, the app downloads up-to-date lists every day of the random IDs of all users who have shared their test result (more precisely: their own random IDs) via their official coronavirus app in order to warn other users. These lists are then compared with the random IDs of other users which have been recorded by your Android smartphone.\n\nThe app will inform you if it detects a possible exposure. In this case, the app gains access to the data recorded by your Android smartphone about the possible exposure (date, duration and Bluetooth signal strength of the contact). The Bluetooth signal strength is used to derive the physical distance to the other user (the stronger the signal, the smaller the distance). The app analyses this information in order to calculate your risk of infection and to give you recommendations for what to do next. This analysis is only performed locally on your Android smartphone.\n\nApart from you, nobody (not even the RKI or the health authorities of participating countries) will know whether a possible exposure has been detected and what risk of infection has been identified for you.\n\nYou can withdraw your consent to the exposure logging feature at any time by either disabling the feature using the toggle switch in the app or deleting the app. If you would like to use the exposure logging feature again, you can toggle the feature back on or reinstall the app. If you disable the exposure logging feature, the app will no longer check for possible exposures. If you also wish to stop your device sending and receiving random IDs, you will need to disable the “COVID-19 Exposure Notifications†functionality in your Android smartphone’s settings. Please note that the app will not delete your random IDs or those received from other smartphones which have been recorded by this functionality on your Android smartphone. You can only permanently delete these in your Android smartphone settings.\n\nThe app’s privacy notice (including information about the data processing carried out for the transnational exposure logging feature) can be found in the menu under „App Information“ > „Data Privacy“."</string> <!-- XHED: Page subheadline for consent sub section your consent --> - <string name="submission_consent_your_consent_subsection_headline" translatable="false"></string> + <string name="submission_consent_your_consent_subsection_headline" translatable="false">"Your consent"</string> <!-- YTXT: Body for consent sub section your consent subtext --> - <string name="submission_consent_your_consent_subsection_tapping_agree" translatable="false"></string> + <string name="submission_consent_your_consent_subsection_tapping_agree" translatable="false">"By tapping on “Acceptâ€, you consent to the following steps:"</string> <!-- YTXT: Body for consent sub section your consent subtext first point --> - <string name="submission_consent_your_consent_subsection_first_point" translatable="false"></string> + <string name="submission_consent_your_consent_subsection_first_point" translatable="false">"<b>The app will retrieve your test result.</b>If you change your mind later, you can delete the test in the app."</string> <!-- YTXT: Body for consent sub section your consent subtext second point --> - <string name="submission_consent_your_consent_subsection_second_point" translatable="false"></string> + <string name="submission_consent_your_consent_subsection_second_point" translatable="false">"<b>If you have tested positive for coronavirus, the app will share your test result in order to warn other users whom you have encountered. This includes users of the official coronavirus apps of the countries mentioned above. If you provide additional information about the onset of your symptoms, this will also be shared.</b>"</string> <!-- YTXT: Body for consent sub section your consent subtext third point --> - <string name="submission_consent_your_consent_subsection_third_point" translatable="false"></string> - <!-- YTXT: Your consent screen agreement share test results --> - <string name="submission_your_consent_agreement_share_test_results" translatable="false">""</string> - <!-- YTXT: Your consent screen agreement share symptoms --> - <string name="submission_your_consent_agreement_share_symptoms" translatable="false">""</string> + <string name="submission_consent_your_consent_subsection_third_point" translatable="false">"You can withdraw your consent at any time. The setting for this can be found under “Display testâ€. Before sharing your test result, you will be reminded of your consent and asked to confirm your willingness to share your test result."</string> + <!-- YTXT: Body for your consent screen agreement share test results --> + <string name="submission_your_consent_agreement_share_test_results" translatable="false">"<b>If you have tested positive for coronavirus, the app will share your test result in order to warn other users whom you have encountered.</b>\n\n<b>The warning will reach users of the official coronavirus apps of the following participating countries:</b>"</string> + <!-- YTXT: Body for your consent screen agreement share symptoms --> + <string name="submission_your_consent_agreement_share_symptoms" translatable="false">"<b>If you provide additional information about the onset of your symptoms, this will also be shared.</b>\n\nYou can withdraw your consent by disabling “Warn others†above."</string> <!-- YTXT: Body for keys submission no consent text first part--> - <string name="submission_no_consent_your_consent_subsection_body_first_part" translatable="false">""</string> + <string name="submission_no_consent_your_consent_subsection_body_first_part" translatable="false">"By tapping on “Acceptâ€, you consent to the following:"</string> <!-- YTXT: Body for keys submission no consent text second part--> - <string name="submission_no_consent_your_consent_subsection_body_second_part" translatable="false">""</string> + <string name="submission_no_consent_your_consent_subsection_body_second_part" translatable="false">"<b>The app will share your test result in order to warn other users of official coronavirus apps whom you have encountered. The warning will work in the countries mentioned above. If you provide additional information about the onset of your symptoms, this will also be shared.</b>In the next step, please share your test result (or more precisely: your random IDs from the last 14 days) by tapping on “Shareâ€."</string> <!-- YTXT: Body for keys submission no consent text third part--> - <string name="submission_no_consent_your_consent_subsection_body_third_part" translatable="false">""</string> + <string name="submission_no_consent_your_consent_subsection_body_third_part" translatable="false">"If you have already warned other users, you can withdraw your consent by deleting the app."</string> </resources> diff --git a/Corona-Warn-App/src/main/res/values/strings.xml b/Corona-Warn-App/src/main/res/values/strings.xml index b2ecd313c9df9759164c5fd77dd9750988f5d4a9..a4e0b4d43ea32ac2f255549d8fc7dbd0bbedec4e 100644 --- a/Corona-Warn-App/src/main/res/values/strings.xml +++ b/Corona-Warn-App/src/main/res/values/strings.xml @@ -108,6 +108,10 @@ <string name="notification_headline_share_positive_result">"You can help!"</string> <!-- XTXT: Notification body - Reminder to share a positive test result--> <string name="notification_body_share_positive_result">"Please share your test result and warn others."</string> + <!-- XHED: Notification title - test result is ready --> + <string name="notification_headline_test_result_ready">""</string> + <!-- XTXT: Notification body - test result is ready --> + <string name="notification_body_test_result_ready">""</string> <!-- #################################### App Auto Update diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/ENFClientTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/ENFClientTest.kt index 39e4639e53407bb9b4e1066c2a203045f8f5c364..895786746e298b032b47a229c7540ba800ec558e 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/ENFClientTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/ENFClientTest.kt @@ -2,11 +2,13 @@ package de.rki.coronawarnapp.nearby import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient import com.google.android.gms.nearby.exposurenotification.ExposureWindow +import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey import de.rki.coronawarnapp.nearby.modules.detectiontracker.ExposureDetectionTracker import de.rki.coronawarnapp.nearby.modules.detectiontracker.TrackedExposureDetection import de.rki.coronawarnapp.nearby.modules.diagnosiskeyprovider.DiagnosisKeyProvider import de.rki.coronawarnapp.nearby.modules.exposurewindow.ExposureWindowProvider import de.rki.coronawarnapp.nearby.modules.locationless.ScanningSupport +import de.rki.coronawarnapp.nearby.modules.tekhistory.TEKHistoryProvider import de.rki.coronawarnapp.nearby.modules.tracing.TracingStatus import de.rki.coronawarnapp.nearby.modules.version.ENFVersion import io.kotest.matchers.shouldBe @@ -42,6 +44,7 @@ class ENFClientTest : BaseTest() { @MockK lateinit var exposureWindowProvider: ExposureWindowProvider @MockK lateinit var exposureDetectionTracker: ExposureDetectionTracker @MockK lateinit var enfVersion: ENFVersion + @MockK lateinit var tekHistoryProvider: TEKHistoryProvider @BeforeEach fun setup() { @@ -62,7 +65,8 @@ class ENFClientTest : BaseTest() { scanningSupport = scanningSupport, enfVersion = enfVersion, exposureWindowProvider = exposureWindowProvider, - exposureDetectionTracker = exposureDetectionTracker + exposureDetectionTracker = exposureDetectionTracker, + tekHistoryProvider = tekHistoryProvider ) @Test @@ -288,4 +292,14 @@ class ENFClientTest : BaseTest() { coVerifySequence { enfVersion.getENFClientVersion() } } + + @Test + fun `tek history provider calls are forwarded to the right module`() = runBlocking { + val mockTEK = mockk<TemporaryExposureKey>() + coEvery { tekHistoryProvider.getTEKHistory() } returns listOf(mockTEK) + + createClient().getTEKHistory() shouldBe listOf(mockTEK) + + coVerifySequence { tekHistoryProvider.getTEKHistory() } + } } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/ResolutionRequestCodeConstantsTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/ResolutionRequestCodeConstantsTest.kt deleted file mode 100644 index cb87e4cf48d1e025576f58669063b0f4bd4ff329..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/ResolutionRequestCodeConstantsTest.kt +++ /dev/null @@ -1,13 +0,0 @@ -package de.rki.coronawarnapp.nearby - -import org.junit.Assert -import org.junit.Test - -class ResolutionRequestCodeConstantsTest { - - @Test - fun allResolutionRequestCodeConstants() { - Assert.assertEquals(ResolutionRequestCodeConstants.REQUEST_CODE_START_EXPOSURE_NOTIFICATION_CODE, 1111) - Assert.assertEquals(ResolutionRequestCodeConstants.REQUEST_CODE_GET_TEMP_EXPOSURE_KEY_HISTORY_CODE, 2222) - } -} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/ResolutionRequestCodesTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/ResolutionRequestCodesTest.kt deleted file mode 100644 index 2ccfe6e9b26cba8144466fbe61be97028766f5f1..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/ResolutionRequestCodesTest.kt +++ /dev/null @@ -1,19 +0,0 @@ -package de.rki.coronawarnapp.nearby - -import org.junit.Assert -import org.junit.Test - -class ResolutionRequestCodesTest { - - @Test - fun allResolutionRequestCodes() { - Assert.assertEquals( - ResolutionRequestCodes.REQUEST_CODE_START_EXPOSURE_NOTIFICATION.code, - ResolutionRequestCodeConstants.REQUEST_CODE_START_EXPOSURE_NOTIFICATION_CODE - ) - Assert.assertEquals( - ResolutionRequestCodes.REQUEST_CODE_GET_TEMP_EXPOSURE_KEY_HISTORY.code, - ResolutionRequestCodeConstants.REQUEST_CODE_GET_TEMP_EXPOSURE_KEY_HISTORY_CODE - ) - } -} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/TracingPermissionHelperTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/TracingPermissionHelperTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..f40bde5af39ecfb9b9b4735e8d1328224fdac5d7 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/TracingPermissionHelperTest.kt @@ -0,0 +1,57 @@ +package de.rki.coronawarnapp.nearby + +import android.app.Activity +import io.mockk.MockKAnnotations +import io.mockk.Runs +import io.mockk.coEvery +import io.mockk.every +import io.mockk.impl.annotations.MockK +import io.mockk.just +import io.mockk.mockk +import io.mockk.verify +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.test.runBlockingTest +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import testhelpers.BaseTest + +class TracingPermissionHelperTest : BaseTest() { + @MockK lateinit var enfClient: ENFClient + + @BeforeEach + fun setup() { + MockKAnnotations.init(this) + + coEvery { enfClient.isTracingEnabled } returns flowOf(false) + } + + fun createInstance(scope: CoroutineScope) = TracingPermissionHelper( + scope = scope, + enfClient = enfClient + ) + + @Test + fun `request is forwarded if tracing is disabled`() = runBlockingTest { +// TODO() + } + + @Test + fun `request is not forwarded if tracing is enabled`() = runBlockingTest { + coEvery { enfClient.isTracingEnabled } returns flowOf(true) + + val callback = mockk<TracingPermissionHelper.Callback>() + every { callback.onUpdateTracingStatus(any()) } just Runs + + val instance = createInstance(scope = this) + instance.callback = callback + + val permissionRequestListener = mockk<(permissionRequest: (Activity) -> Unit) -> Unit>() + + instance.startTracing(permissionRequestListener) + + advanceUntilIdle() + + verify { callback.onUpdateTracingStatus(true) } + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/detectiontracker/ExposureDetectionTrackerExtensionsTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/detectiontracker/ExposureDetectionTrackerExtensionsTest.kt index 18702738c8cc0c58bde2bf7263f94895c3387d80..beb1bd1ef988ec42f6dd8616892e964214741dd1 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/detectiontracker/ExposureDetectionTrackerExtensionsTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/detectiontracker/ExposureDetectionTrackerExtensionsTest.kt @@ -48,7 +48,7 @@ class ExposureDetectionTrackerExtensionsTest : BaseTest() { fakeCalculations.value = mapOf( tr1.identifier to tr1, tr2.identifier to tr2, - tr3.identifier to tr3, + tr3.identifier to tr3 ) runBlockingTest { tracker.lastSubmission(onlyFinished = false) shouldBe tr3 @@ -72,7 +72,7 @@ class ExposureDetectionTrackerExtensionsTest : BaseTest() { fakeCalculations.value = mapOf( tr1.identifier to tr1, tr2.identifier to tr2, - tr3.identifier to tr3, + tr3.identifier to tr3 ) runBlockingTest { tracker.latestSubmission(onlySuccessful = false).first() shouldBe tr3 diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/tekhistory/DefaultTEKHistoryProviderTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/tekhistory/DefaultTEKHistoryProviderTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..e9c8e735adfce7d5be19c7550fdba1a21a5ce337 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/tekhistory/DefaultTEKHistoryProviderTest.kt @@ -0,0 +1,65 @@ +package de.rki.coronawarnapp.nearby.modules.tekhistory + +import com.google.android.gms.common.api.ApiException +import com.google.android.gms.common.api.Status +import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient +import io.kotest.assertions.throwables.shouldThrowExactly +import io.kotest.matchers.shouldBe +import io.mockk.Called +import io.mockk.MockKAnnotations +import io.mockk.clearAllMocks +import io.mockk.every +import io.mockk.impl.annotations.MockK +import io.mockk.mockk +import io.mockk.verify +import kotlinx.coroutines.test.runBlockingTest +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import testhelpers.BaseTest +import testhelpers.gms.MockGMSTask + +class DefaultTEKHistoryProviderTest : BaseTest() { + + @MockK lateinit var client: ExposureNotificationClient + + @BeforeEach + fun setup() { + MockKAnnotations.init(this) + + every { client.temporaryExposureKeyHistory } answers { MockGMSTask.forValue(listOf(mockk())) } + } + + @AfterEach + fun teardown() { + clearAllMocks() + } + + private fun createInstance() = DefaultTEKHistoryProvider( + client = client + ) + + @Test + fun `init is sideeffect free and lazy`() = runBlockingTest { + createInstance() + + advanceUntilIdle() + + verify { client wasNot Called } + } + + @Test + fun `history is forwarded`() = runBlockingTest { + val instance = createInstance() + instance.getTEKHistory().size shouldBe 1 + } + + @Test + fun `errors are forwarded`() = runBlockingTest { + val error = ApiException(Status.RESULT_DEAD_CLIENT) + every { client.temporaryExposureKeyHistory } answers { MockGMSTask.forError(error) } + val instance = createInstance() + + shouldThrowExactly<ApiException> { instance.getTEKHistory() } shouldBe error + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/version/DefaultENFVersionTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/version/DefaultENFVersionTest.kt index 48a020e449e2a295afbef3b536432b2f928ffa57..239501653d801580e7d1e48b718594f54d7b370d 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/version/DefaultENFVersionTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/version/DefaultENFVersionTest.kt @@ -17,10 +17,11 @@ import kotlinx.coroutines.test.runBlockingTest import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test +import testhelpers.BaseTest import testhelpers.gms.MockGMSTask @ExperimentalCoroutinesApi -internal class DefaultENFVersionTest { +internal class DefaultENFVersionTest : BaseTest() { @MockK lateinit var client: ExposureNotificationClient diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/storage/SubmissionRepositoryTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/storage/SubmissionRepositoryTest.kt index 67d81ff5cc319c27fb85005d4b9720b214325994..55e380df2bb36da86372fc1477d3b522c83567c2 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/storage/SubmissionRepositoryTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/storage/SubmissionRepositoryTest.kt @@ -3,23 +3,32 @@ package de.rki.coronawarnapp.storage import de.rki.coronawarnapp.playbook.BackgroundNoise import de.rki.coronawarnapp.service.submission.SubmissionService import de.rki.coronawarnapp.submission.SubmissionSettings +import de.rki.coronawarnapp.submission.Symptoms +import de.rki.coronawarnapp.submission.data.tekhistory.TEKHistoryStorage +import de.rki.coronawarnapp.task.TaskController +import de.rki.coronawarnapp.util.NetworkRequestWrapper import de.rki.coronawarnapp.util.TimeStamper -import de.rki.coronawarnapp.util.coroutine.AppCoroutineScope import de.rki.coronawarnapp.util.di.AppInjector import de.rki.coronawarnapp.util.di.ApplicationComponent import de.rki.coronawarnapp.util.formatter.TestResult import de.rki.coronawarnapp.util.security.EncryptedPreferencesFactory import de.rki.coronawarnapp.util.security.EncryptionErrorResetTool +import io.kotest.matchers.shouldBe import io.mockk.MockKAnnotations import io.mockk.Runs import io.mockk.coEvery import io.mockk.coVerify +import io.mockk.coVerifyOrder import io.mockk.every import io.mockk.impl.annotations.MockK import io.mockk.just import io.mockk.mockkObject import io.mockk.verify -import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.emptyFlow +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.test.runBlockingTest +import org.joda.time.Instant import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import testhelpers.preferences.mockFlowPreference @@ -31,6 +40,9 @@ class SubmissionRepositoryTest { @MockK lateinit var backgroundNoise: BackgroundNoise @MockK lateinit var appComponent: ApplicationComponent + @MockK lateinit var taskController: TaskController + @MockK lateinit var tekHistoryStorage: TEKHistoryStorage + @MockK lateinit var timeStamper: TimeStamper @MockK lateinit var encryptedPreferencesFactory: EncryptedPreferencesFactory @MockK lateinit var encryptionErrorResetTool: EncryptionErrorResetTool @@ -41,8 +53,6 @@ class SubmissionRepositoryTest { private val testResult = TestResult.PENDING private val registrationData = SubmissionService.RegistrationData(registrationToken, testResult) - lateinit var submissionRepository: SubmissionRepository - @BeforeEach fun setUp() { MockKAnnotations.init(this) @@ -63,11 +73,25 @@ class SubmissionRepositoryTest { every { LocalData.devicePairingSuccessfulTimestamp(any()) } just Runs every { submissionSettings.hasGivenConsent } returns mockFlowPreference(false) + every { submissionSettings.symptoms } returns mockFlowPreference(Symptoms.NO_INFO_GIVEN) + every { submissionSettings.clear() } just Runs + + every { taskController.tasks } returns emptyFlow() - val appScope = AppCoroutineScope() - submissionRepository = SubmissionRepository(submissionSettings, submissionService, appScope, TimeStamper()) + coEvery { tekHistoryStorage.clear() } just Runs + + every { timeStamper.nowUTC } returns Instant.EPOCH } + fun createInstance(scope: CoroutineScope) = SubmissionRepository( + scope = scope, + submissionSettings = submissionSettings, + submissionService = submissionService, + timeStamper = timeStamper, + taskController = taskController, + tekHistoryStorage = tekHistoryStorage + ) + @Test fun deleteRegistrationTokenSucceeds() { SubmissionRepository.deleteRegistrationToken() @@ -79,13 +103,13 @@ class SubmissionRepositoryTest { } @Test - fun registrationWithGUIDSucceeds() { + fun registrationWithGUIDSucceeds() = runBlockingTest { every { LocalData.testGUID(any()) } just Runs coEvery { submissionService.asyncRegisterDeviceViaGUID(guid) } returns registrationData - runBlocking { - submissionRepository.asyncRegisterDeviceViaGUID(guid) - } + val submissionRepository = createInstance(scope = this) + + submissionRepository.asyncRegisterDeviceViaGUID(guid) verify(exactly = 1) { LocalData.devicePairingSuccessfulTimestamp(any()) @@ -97,13 +121,13 @@ class SubmissionRepositoryTest { } @Test - fun registrationWithTeleTANSucceeds() { + fun registrationWithTeleTANSucceeds() = runBlockingTest { every { LocalData.teletan(any()) } just Runs coEvery { submissionService.asyncRegisterDeviceViaTAN(tan) } returns registrationData - runBlocking { - submissionRepository.asyncRegisterDeviceViaTAN(tan) - } + val submissionRepository = createInstance(scope = this) + + submissionRepository.asyncRegisterDeviceViaTAN(tan) coVerify(exactly = 1) { LocalData.devicePairingSuccessfulTimestamp(any()) @@ -113,4 +137,17 @@ class SubmissionRepositoryTest { submissionRepository.updateTestResult(testResult) } } + + @Test + fun `reset clears tek history and settings`() = runBlockingTest { + val instance = createInstance(this) + instance.reset() + + instance.deviceUIStateFlow.first() shouldBe NetworkRequestWrapper.RequestIdle + + coVerifyOrder { + tekHistoryStorage.clear() + submissionSettings.clear() + } + } } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/SubmissionTaskConfigTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/SubmissionTaskConfigTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..d1fbd6e793ceeedf06030c83379e4a6e3218fdc5 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/SubmissionTaskConfigTest.kt @@ -0,0 +1,14 @@ +package de.rki.coronawarnapp.submission + +import io.kotest.matchers.comparables.shouldBeLessThan +import org.joda.time.Duration +import org.junit.jupiter.api.Test +import testhelpers.BaseTest + +class SubmissionTaskConfigTest : BaseTest() { + + @Test + fun `task timeout below 9 minutes`() { + SubmissionTask.Config().executionTimeout.shouldBeLessThan(Duration.standardMinutes(9)) + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/SubmissionTaskTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/SubmissionTaskTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..598527408794591fb47d3ebcb3f1ae2e95c3bf49 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/SubmissionTaskTest.kt @@ -0,0 +1,190 @@ +package de.rki.coronawarnapp.submission + +import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey +import de.rki.coronawarnapp.appconfig.AppConfigProvider +import de.rki.coronawarnapp.appconfig.ConfigData +import de.rki.coronawarnapp.exception.NoRegistrationTokenSetException +import de.rki.coronawarnapp.notification.TestResultNotificationService +import de.rki.coronawarnapp.playbook.Playbook +import de.rki.coronawarnapp.server.protocols.external.exposurenotification.TemporaryExposureKeyExportOuterClass +import de.rki.coronawarnapp.storage.LocalData +import de.rki.coronawarnapp.submission.data.tekhistory.TEKHistoryStorage +import de.rki.coronawarnapp.task.Task +import de.rki.coronawarnapp.util.preferences.FlowPreference +import de.rki.coronawarnapp.worker.BackgroundWorkScheduler +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.matchers.shouldBe +import io.mockk.MockKAnnotations +import io.mockk.Runs +import io.mockk.coEvery +import io.mockk.coVerify +import io.mockk.coVerifySequence +import io.mockk.every +import io.mockk.impl.annotations.MockK +import io.mockk.just +import io.mockk.mockkObject +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.test.runBlockingTest +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import testhelpers.BaseTest +import testhelpers.preferences.mockFlowPreference +import java.io.IOException + +class SubmissionTaskTest : BaseTest() { + + @MockK lateinit var playbook: Playbook + @MockK lateinit var appConfigProvider: AppConfigProvider + @MockK lateinit var tekHistoryCalculations: ExposureKeyHistoryCalculations + @MockK lateinit var tekHistoryStorage: TEKHistoryStorage + @MockK lateinit var submissionSettings: SubmissionSettings + @MockK lateinit var testResultNotificationService: TestResultNotificationService + + @MockK lateinit var tekBatch: TEKHistoryStorage.TEKBatch + @MockK lateinit var tek: TemporaryExposureKey + @MockK lateinit var userSymptoms: Symptoms + @MockK lateinit var transformedKey: TemporaryExposureKeyExportOuterClass.TemporaryExposureKey + + @MockK lateinit var appConfigData: ConfigData + + private lateinit var mockSymptomsPreference: FlowPreference<Symptoms?> + + @BeforeEach + fun setup() { + MockKAnnotations.init(this) + + mockkObject(LocalData) + every { LocalData.registrationToken() } returns "regtoken" + every { LocalData.numberOfSuccessfulSubmissions(any()) } just Runs + + mockkObject(BackgroundWorkScheduler) + every { BackgroundWorkScheduler.stopWorkScheduler() } just Runs + + every { tekBatch.keys } returns listOf(tek) + every { tekHistoryStorage.tekData } returns flowOf(listOf(tekBatch)) + coEvery { tekHistoryStorage.clear() } just Runs + + every { + tekHistoryCalculations.transformToKeyHistoryInExternalFormat(listOf(tek), userSymptoms) + } returns listOf(transformedKey) + + mockSymptomsPreference = mockFlowPreference(userSymptoms) + every { submissionSettings.symptoms } returns mockSymptomsPreference + + coEvery { appConfigProvider.getAppConfig() } returns appConfigData + every { appConfigData.supportedCountries } returns listOf("NL") + + coEvery { playbook.submit(any()) } just Runs + + every { testResultNotificationService.cancelPositiveTestResultNotification() } just Runs + } + + private fun createTask() = SubmissionTask( + playbook = playbook, + appConfigProvider = appConfigProvider, + tekHistoryCalculations = tekHistoryCalculations, + tekHistoryStorage = tekHistoryStorage, + submissionSettings = submissionSettings, + testResultNotificationService + ) + + @Test + fun `submission flow`() = runBlockingTest { + val task = createTask() + task.run(object : Task.Arguments {}) + + coVerifySequence { + LocalData.registrationToken() + tekHistoryStorage.tekData + mockSymptomsPreference.value + + tekHistoryCalculations.transformToKeyHistoryInExternalFormat(listOf(tek), userSymptoms) + + appConfigProvider.getAppConfig() + playbook.submit( + Playbook.SubmissionData( + "regtoken", + listOf(transformedKey), + true, + listOf("NL") + ) + ) + + tekHistoryStorage.clear() + mockSymptomsPreference.update(any()) + + BackgroundWorkScheduler.stopWorkScheduler() + LocalData.numberOfSuccessfulSubmissions(1) + + testResultNotificationService.cancelPositiveTestResultNotification() + } + + submissionSettings.symptoms.value shouldBe null + } + + @Test + fun `submission data is not deleted if submission fails`() = runBlockingTest { + coEvery { playbook.submit(any()) } throws IOException() + + shouldThrow<IOException> { + createTask().run(object : Task.Arguments {}) + } + + coVerifySequence { + LocalData.registrationToken() + tekHistoryStorage.tekData + mockSymptomsPreference.value + + tekHistoryCalculations.transformToKeyHistoryInExternalFormat(listOf(tek), userSymptoms) + + appConfigProvider.getAppConfig() + playbook.submit( + Playbook.SubmissionData( + "regtoken", + listOf(transformedKey), + true, + listOf("NL") + ) + ) + } + coVerify(exactly = 0) { + tekHistoryStorage.clear() + mockSymptomsPreference.update(any()) + testResultNotificationService.cancelPositiveTestResultNotification() + } + submissionSettings.symptoms.value shouldBe userSymptoms + } + + @Test + fun `task throws if no registration token is available`() = runBlockingTest { + every { LocalData.registrationToken() } returns null + + val task = createTask() + shouldThrow<NoRegistrationTokenSetException> { + task.run(object : Task.Arguments {}) + } + } + + @Test + fun `DE is used as fallback country`() = runBlockingTest { + every { appConfigData.supportedCountries } returns listOf("DE") + + createTask().run(object : Task.Arguments {}) + + coVerifySequence { + playbook.submit( + Playbook.SubmissionData( + "regtoken", + listOf(transformedKey), + true, + listOf("DE") + ) + ) + } + } + + @Test + fun `NO_INFORMATION symptoms are used when the stored symptoms are null`() { + // TODO + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/data/SubmissionSettingsTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/data/SubmissionSettingsTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..b1b1f7c5df7e50acbf4f1de90f1619f596a93a1a --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/data/SubmissionSettingsTest.kt @@ -0,0 +1,140 @@ +package de.rki.coronawarnapp.submission.data + +import android.content.Context +import com.google.gson.Gson +import de.rki.coronawarnapp.submission.SubmissionSettings +import de.rki.coronawarnapp.submission.Symptoms +import de.rki.coronawarnapp.util.serialization.SerializationModule +import io.kotest.matchers.shouldBe +import io.mockk.MockKAnnotations +import io.mockk.every +import io.mockk.impl.annotations.MockK +import org.joda.time.LocalDate +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import testhelpers.preferences.MockSharedPreferences + +class SubmissionSettingsTest { + @MockK lateinit var context: Context + private lateinit var mockPreferences: MockSharedPreferences + private lateinit var baseGson: Gson + + @BeforeEach + fun setup() { + MockKAnnotations.init(this) + + mockPreferences = MockSharedPreferences() + + every { + context.getSharedPreferences("submission_localdata", Context.MODE_PRIVATE) + } returns mockPreferences + + baseGson = SerializationModule().baseGson().newBuilder().apply { + setPrettyPrinting() + }.create() + } + + fun createInstance() = SubmissionSettings( + context = context, + baseGson = baseGson + ) + + @Test + fun consentIsPersisted() { + createInstance().apply { + hasGivenConsent.value shouldBe false + hasGivenConsent.update { true } + hasGivenConsent.value shouldBe true + } + } + + @Test + fun `persist symptoms`() { + createInstance().apply { + symptoms.value shouldBe null + mockPreferences.dataMapPeek.isEmpty() shouldBe true + + Symptoms(startOfSymptoms = Symptoms.StartOf.NoInformation, Symptoms.Indication.POSITIVE).let { value -> + symptoms.update { value } + symptoms.value shouldBe value + mockPreferences.dataMapPeek["submission.symptoms.latest"] shouldBe """ + { + "startOfSymptoms": { + "type": "NoInformation" + }, + "symptomIndication": "POSITIVE" + } + """.trimIndent() + } + + Symptoms(startOfSymptoms = Symptoms.StartOf.OneToTwoWeeksAgo, Symptoms.Indication.NEGATIVE).let { value -> + symptoms.update { value } + symptoms.value shouldBe value + mockPreferences.dataMapPeek["submission.symptoms.latest"] shouldBe """ + { + "startOfSymptoms": { + "type": "OneToTwoWeeksAgo" + }, + "symptomIndication": "NEGATIVE" + } + """.trimIndent() + } + + Symptoms( + startOfSymptoms = Symptoms.StartOf.MoreThanTwoWeeks, + Symptoms.Indication.NO_INFORMATION + ).let { value -> + symptoms.update { value } + symptoms.value shouldBe value + mockPreferences.dataMapPeek["submission.symptoms.latest"] shouldBe """ + { + "startOfSymptoms": { + "type": "MoreThanTwoWeeks" + }, + "symptomIndication": "NO_INFORMATION" + } + """.trimIndent() + } + + Symptoms( + startOfSymptoms = Symptoms.StartOf.LastSevenDays, + Symptoms.Indication.NO_INFORMATION + ).let { value -> + symptoms.update { value } + symptoms.value shouldBe value + mockPreferences.dataMapPeek["submission.symptoms.latest"] shouldBe """ + { + "startOfSymptoms": { + "type": "LastSevenDays" + }, + "symptomIndication": "NO_INFORMATION" + } + """.trimIndent() + } + + Symptoms( + startOfSymptoms = Symptoms.StartOf.Date(LocalDate.parse("2020-12-24")), + Symptoms.Indication.NO_INFORMATION + ).let { value -> + symptoms.update { value } + symptoms.value shouldBe value + mockPreferences.dataMapPeek["submission.symptoms.latest"] shouldBe """ + { + "startOfSymptoms": { + "type": "Date", + "date": "2020-12-24" + }, + "symptomIndication": "NO_INFORMATION" + } + """.trimIndent() + } + } + } + + @Test + fun `symptoms default to null`() { + createInstance().apply { + symptoms.value shouldBe null + } + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/data/tekhistory/TEKHistoryUpdaterTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/data/tekhistory/TEKHistoryUpdaterTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..e927516bd547f435720b7e8302e90bea6e9d1e8c --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/data/tekhistory/TEKHistoryUpdaterTest.kt @@ -0,0 +1,47 @@ +package de.rki.coronawarnapp.submission.data.tekhistory + +import de.rki.coronawarnapp.nearby.ENFClient +import de.rki.coronawarnapp.util.TimeStamper +import io.mockk.MockKAnnotations +import io.mockk.Runs +import io.mockk.coEvery +import io.mockk.coVerify +import io.mockk.impl.annotations.MockK +import io.mockk.just +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.test.runBlockingTest +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import testhelpers.BaseTest + +class TEKHistoryUpdaterTest : BaseTest() { + @MockK lateinit var tekHistoryStorage: TEKHistoryStorage + @MockK lateinit var timeStamper: TimeStamper + @MockK lateinit var enfClient: ENFClient + + @BeforeEach + fun setup() { + MockKAnnotations.init(this) + + coEvery { enfClient.getTEKHistoryOrRequestPermission(any(), any()) } just Runs + } + + fun createInstance(scope: CoroutineScope) = TEKHistoryUpdater( + scope = scope, + tekHistoryStorage = tekHistoryStorage, + timeStamper = timeStamper, + enfClient = enfClient + ) + + @Test + fun `request is forwaded to enf client`() = runBlockingTest { + val instance = createInstance(scope = this) + instance.updateTEKHistoryOrRequestPermission { } + coVerify { + enfClient.getTEKHistoryOrRequestPermission( + any(), + any() + ) + } + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/data/tekhistory/storage/internal/TEKEntryDaoTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/data/tekhistory/storage/internal/TEKEntryDaoTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..1f1558b74a15c1b6a3a8784e10342e7a8eb863ed --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/data/tekhistory/storage/internal/TEKEntryDaoTest.kt @@ -0,0 +1,53 @@ +package de.rki.coronawarnapp.submission.data.tekhistory.storage.internal + +import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey +import de.rki.coronawarnapp.submission.data.tekhistory.TEKHistoryStorage +import de.rki.coronawarnapp.submission.data.tekhistory.internal.TEKEntryDao +import de.rki.coronawarnapp.submission.data.tekhistory.internal.toPersistedTEK +import io.kotest.matchers.shouldBe +import okio.ByteString.Companion.toByteString +import org.joda.time.Instant +import org.junit.jupiter.api.Test +import testhelpers.BaseTest + +class TEKEntryDaoTest : BaseTest() { + + private val testData = TEKHistoryStorage.TEKBatch( + obtainedAt = Instant.ofEpochMilli(1234), + batchId = "batch-id", + keys = listOf( + TemporaryExposureKey.TemporaryExposureKeyBuilder().apply { + setKeyData("keydata".toByteArray()) + setRollingStartIntervalNumber(123) + setTransmissionRiskLevel(3) + setRollingPeriod(144) + setReportType(1) + setDaysSinceOnsetOfSymptoms(7) + }.build() + ) + ) + + private val testDataDao = TEKEntryDao( + id = "keydata".toByteArray().toByteString().base64(), + obtainedAt = Instant.ofEpochMilli(1234), + batchId = "batch-id", + persistedTEK = TEKEntryDao.PersistedTEK( + keyData = "keydata".toByteArray(), + rollingStartIntervalNumber = 123, + transmissionRiskLevel = 3, + rollingPeriod = 144, + reportType = 1, + daysSinceOnsetOfSymptoms = 7 + ) + ) + + @Test + fun `temporary exposure key to persisted tek`() { + testData.keys[0].toPersistedTEK() shouldBe testDataDao.persistedTEK + } + + @Test + fun `persisted tek to temporary exposure key`() { + testDataDao.persistedTEK.toTemporaryExposureKey() shouldBe testData.keys.first() + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/data/tekhistory/storage/internal/TEKHistoryStorageTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/data/tekhistory/storage/internal/TEKHistoryStorageTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..17d68b49cfc3b9aa8db8d67dc3ba896452dfbd44 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/data/tekhistory/storage/internal/TEKHistoryStorageTest.kt @@ -0,0 +1,108 @@ +package de.rki.coronawarnapp.submission.data.tekhistory.storage.internal + +import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey +import de.rki.coronawarnapp.submission.data.tekhistory.TEKHistoryStorage +import de.rki.coronawarnapp.submission.data.tekhistory.internal.TEKEntryDao +import de.rki.coronawarnapp.submission.data.tekhistory.internal.TEKHistoryDatabase +import de.rki.coronawarnapp.submission.data.tekhistory.internal.toPersistedTEK +import io.kotest.matchers.shouldBe +import io.mockk.MockKAnnotations +import io.mockk.Runs +import io.mockk.coEvery +import io.mockk.coVerifySequence +import io.mockk.every +import io.mockk.impl.annotations.MockK +import io.mockk.just +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.test.runBlockingTest +import okio.ByteString.Companion.toByteString +import org.joda.time.Instant +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import testhelpers.BaseTest +import testhelpers.room.mockDefaultOperations + +class TEKHistoryStorageTest : BaseTest() { + + @MockK lateinit var tekHistoryDatabaseFactory: TEKHistoryDatabase.Factory + @MockK lateinit var tekHistoryDatabase: TEKHistoryDatabase + @MockK lateinit var tekHistoryTables: TEKHistoryDatabase.TEKHistoryDao + + @BeforeEach + fun setup() { + MockKAnnotations.init(this) + + every { tekHistoryDatabaseFactory.create() } returns tekHistoryDatabase + every { tekHistoryDatabase.tekHistory() } returns tekHistoryTables + + coEvery { tekHistoryTables.insertEntry(any()) } just Runs + every { tekHistoryDatabase.clearAllTables() } just Runs + + tekHistoryDatabase.mockDefaultOperations() + } + + private fun createInstance() = TEKHistoryStorage( + tekHistoryDatabaseFactory = tekHistoryDatabaseFactory + ) + + private val testData = TEKHistoryStorage.TEKBatch( + obtainedAt = Instant.ofEpochMilli(1234), + batchId = "batch-id", + keys = listOf( + TemporaryExposureKey.TemporaryExposureKeyBuilder().apply { + setKeyData("keydata".toByteArray()) + setRollingStartIntervalNumber(123) + setTransmissionRiskLevel(3) + setRollingPeriod(144) + setReportType(1) + setDaysSinceOnsetOfSymptoms(7) + }.build(), + TemporaryExposureKey.TemporaryExposureKeyBuilder().apply { + setKeyData("keydata2".toByteArray()) + setRollingStartIntervalNumber(123) + setTransmissionRiskLevel(3) + setRollingPeriod(144) + setReportType(1) + setDaysSinceOnsetOfSymptoms(8) + }.build() + ) + ) + private val persistedTEK1 = TEKEntryDao( + id = testData.keys[0].keyData.toByteString().base64(), + batchId = testData.batchId, + obtainedAt = testData.obtainedAt, + persistedTEK = testData.keys[0].toPersistedTEK() + ) + + private val persistedTEK2 = TEKEntryDao( + id = testData.keys[1].keyData.toByteString().base64(), + batchId = testData.batchId, + obtainedAt = testData.obtainedAt, + persistedTEK = testData.keys[1].toPersistedTEK() + ) + + @Test + fun `store data`() = runBlockingTest { + val instance = createInstance() + + instance.storeTEKData(testData) + coVerifySequence { + tekHistoryTables.insertEntry(persistedTEK1) + tekHistoryTables.insertEntry(persistedTEK2) + } + } + + @Test + fun `retrieve data`() = runBlockingTest { + every { tekHistoryTables.allEntries() } returns flowOf(listOf(persistedTEK1, persistedTEK2)) + val instance = createInstance() + instance.tekData.first() shouldBe listOf(testData) + } + + @Test + fun `clear all data`() = runBlockingTest { + createInstance().clear() + coVerifySequence { tekHistoryDatabase.clearAllTables() } + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/task/TaskControllerTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/task/TaskControllerTest.kt index d84078cf9b2bd447d63555b5c44d2b6ecb197b5e..1db3f96d9a29c871609aa58e5fc93aff11f7db4e 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/task/TaskControllerTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/task/TaskControllerTest.kt @@ -3,6 +3,7 @@ package de.rki.coronawarnapp.task import de.rki.coronawarnapp.task.common.DefaultTaskRequest import de.rki.coronawarnapp.task.example.QueueingTask import de.rki.coronawarnapp.task.testtasks.SkippingTask +import de.rki.coronawarnapp.task.testtasks.precondition.PreconditionTask import de.rki.coronawarnapp.task.testtasks.timeout.TimeoutTask import de.rki.coronawarnapp.task.testtasks.timeout.TimeoutTask2 import de.rki.coronawarnapp.task.testtasks.timeout.TimeoutTaskArguments @@ -54,6 +55,7 @@ class TaskControllerTest : BaseIOTest() { private val timeoutFactory2 = spyk(TimeoutTask2.Factory(Provider { TimeoutTask2() })) private val queueingFactory = spyk(QueueingTask.Factory(Provider { QueueingTask() })) private val skippingFactory = spyk(SkippingTask.Factory(Provider { SkippingTask() })) + private val preconditionFactory = spyk(PreconditionTask.Factory(Provider { PreconditionTask() })) @BeforeEach fun setup() { @@ -63,6 +65,7 @@ class TaskControllerTest : BaseIOTest() { taskFactoryMap[SkippingTask::class.java] = skippingFactory taskFactoryMap[TimeoutTask::class.java] = timeoutFactory taskFactoryMap[TimeoutTask2::class.java] = timeoutFactory2 + taskFactoryMap[PreconditionTask::class.java] = preconditionFactory every { timeStamper.nowUTC } answers { Instant.now() @@ -340,6 +343,43 @@ class TaskControllerTest : BaseIOTest() { instance.close() } + @Test + fun `tasks with preconditions that are not met are skipped`() = runBlockingTest { + val instance = createInstance(scope = this) + + val request = DefaultTaskRequest(type = PreconditionTask::class) + preconditionFactory.arePreconditionsMet = false + instance.submit(request) + + advanceUntilIdle() + + val request2 = DefaultTaskRequest(type = PreconditionTask::class) + preconditionFactory.arePreconditionsMet = true + instance.submit(request2) + + this.advanceUntilIdle() + + val infoFinished = instance.tasks.first { emission -> + emission.any { it.taskState.executionState == TaskState.ExecutionState.FINISHED } + } + infoFinished.size shouldBe 2 + + infoFinished.single { it.taskState.request == request }.apply { + taskState.type shouldBe PreconditionTask::class + taskState.isSkipped shouldBe true + taskState.result shouldBe null + taskState.error shouldBe null + } + infoFinished.single { it.taskState.request == request2 }.apply { + taskState.type shouldBe PreconditionTask::class + taskState.isSkipped shouldBe false + taskState.result shouldNotBe null + taskState.error shouldBe null + } + + instance.close() + } + @Test fun `collision behavior only affects task of same type`() = runBlockingTest { val arguments = QueueingTask.Arguments(path = File(testDir, UUID.randomUUID().toString())) diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/task/testtasks/precondition/PreconditionTask.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/task/testtasks/precondition/PreconditionTask.kt new file mode 100644 index 0000000000000000000000000000000000000000..f85bb257879f3808498f3fb69b0eac35cbd7bd09 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/task/testtasks/precondition/PreconditionTask.kt @@ -0,0 +1,53 @@ +package de.rki.coronawarnapp.task.testtasks.precondition + +import de.rki.coronawarnapp.task.Task +import de.rki.coronawarnapp.task.TaskFactory +import de.rki.coronawarnapp.task.common.DefaultProgress +import kotlinx.coroutines.channels.ConflatedBroadcastChannel +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.asFlow +import org.joda.time.Duration +import timber.log.Timber +import javax.inject.Provider + +class PreconditionTask : Task<DefaultProgress, PreconditionTask.Result> { + + private val internalProgress = ConflatedBroadcastChannel<DefaultProgress>() + override val progress: Flow<DefaultProgress> = internalProgress.asFlow() + + private var isCanceled = false + + override suspend fun run(arguments: Task.Arguments): Result = try { + Timber.d("Running with arguments=%s", arguments) + + Result() + } finally { + Timber.i("Finished (isCanceled=$isCanceled).") + internalProgress.close() + } + + override suspend fun cancel() { + Timber.w("cancel() called.") + isCanceled = true + } + + class Config(private val arePreconditionsMet: Boolean) : TaskFactory.Config { + override val executionTimeout: Duration = Duration.standardSeconds(10) + + override val collisionBehavior: TaskFactory.Config.CollisionBehavior = + TaskFactory.Config.CollisionBehavior.ENQUEUE + + override val preconditions: List<suspend () -> Boolean> + get() = listOf { arePreconditionsMet } + } + + class Result : Task.Result + + class Factory constructor( + private val taskByDagger: Provider<PreconditionTask> + ) : TaskFactory<DefaultProgress, Result> { + var arePreconditionsMet = true + override suspend fun createConfig(): TaskFactory.Config = Config(arePreconditionsMet) + override val taskProvider: () -> Task<DefaultProgress, Result> = { taskByDagger.get() } + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/testavailable/SubmissionTestResultAvailableViewModelTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/testavailable/SubmissionTestResultAvailableViewModelTest.kt index 07332e85a84210c170c9c6061454719ba6df9ff5..a5274f77ca4b407f73fe3fd1de1c6a85cff07f69 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/testavailable/SubmissionTestResultAvailableViewModelTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/testavailable/SubmissionTestResultAvailableViewModelTest.kt @@ -1,13 +1,17 @@ package de.rki.coronawarnapp.ui.submission.testavailable import de.rki.coronawarnapp.storage.SubmissionRepository -import de.rki.coronawarnapp.ui.submission.resultavailable.SubmissionTestResultAvailableEvents +import de.rki.coronawarnapp.submission.data.tekhistory.TEKHistoryUpdater +import de.rki.coronawarnapp.ui.submission.resultavailable.SubmissionTestResultAvailableFragmentDirections import de.rki.coronawarnapp.ui.submission.resultavailable.SubmissionTestResultAvailableViewModel import io.kotest.matchers.shouldBe import io.mockk.MockKAnnotations +import io.mockk.Runs import io.mockk.clearAllMocks import io.mockk.every import io.mockk.impl.annotations.MockK +import io.mockk.just +import io.mockk.verify import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.flowOf import org.junit.jupiter.api.AfterEach @@ -23,16 +27,23 @@ import testhelpers.extensions.InstantExecutorExtension class SubmissionTestResultAvailableViewModelTest : BaseTest() { @MockK lateinit var submissionRepository: SubmissionRepository + @MockK lateinit var tekHistoryUpdater: TEKHistoryUpdater @BeforeEach fun setUp() { MockKAnnotations.init(this) every { submissionRepository.hasGivenConsentToSubmission } returns flowOf(true) + every { tekHistoryUpdater.callback = any() } just Runs + every { tekHistoryUpdater.updateTEKHistoryOrRequestPermission(any()) } just Runs + + // TODO Check specific behavior + every { submissionRepository.refreshDeviceUIState(any()) } just Runs } private fun createViewModel(): SubmissionTestResultAvailableViewModel = SubmissionTestResultAvailableViewModel( submissionRepository = submissionRepository, - dispatcherProvider = TestDispatcherProvider + dispatcherProvider = TestDispatcherProvider, + tekHistoryUpdater = tekHistoryUpdater ) @AfterEach @@ -58,8 +69,9 @@ class SubmissionTestResultAvailableViewModelTest : BaseTest() { fun `go back`() { val viewModel = createViewModel() + viewModel.showCloseDialog.value shouldBe null viewModel.goBack() - viewModel.clickEvent.value shouldBe SubmissionTestResultAvailableEvents.GoBack + viewModel.showCloseDialog.value shouldBe Unit } @Test @@ -67,14 +79,27 @@ class SubmissionTestResultAvailableViewModelTest : BaseTest() { val viewModel = createViewModel() viewModel.goConsent() - viewModel.clickEvent.value shouldBe SubmissionTestResultAvailableEvents.GoConsent + viewModel.routeToScreen.value shouldBe SubmissionTestResultAvailableFragmentDirections + .actionSubmissionTestResultAvailableFragmentToSubmissionYourConsentFragment() + } + + @Test + fun `update TEK history if consent is given`() { + val viewModel = createViewModel() + + viewModel.proceed() + verify { + tekHistoryUpdater.updateTEKHistoryOrRequestPermission(any()) + } } @Test - fun `go to next page`() { + fun `go to test result without updating TEK history if NO consent is given`() { + every { submissionRepository.hasGivenConsentToSubmission } returns flowOf(false) val viewModel = createViewModel() viewModel.proceed() - viewModel.clickEvent.value shouldBe SubmissionTestResultAvailableEvents.Proceed + viewModel.routeToScreen.value shouldBe SubmissionTestResultAvailableFragmentDirections + .actionSubmissionTestResultAvailableFragmentToSubmissionTestResultNoConsentFragment() } } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/testresult/SubmissionTestResultConsentGivenViewModelTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/testresult/SubmissionTestResultConsentGivenViewModelTest.kt index 13b2daaca059c2fc35e2c52104e971f9ad1025be..d3107f9c8df27e388dd31518d9aa8a2b5b545f74 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/testresult/SubmissionTestResultConsentGivenViewModelTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/testresult/SubmissionTestResultConsentGivenViewModelTest.kt @@ -9,6 +9,7 @@ import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith import testhelpers.BaseTest +import testhelpers.TestDispatcherProvider import testhelpers.extensions.InstantExecutorExtension @ExtendWith(InstantExecutorExtension::class) @@ -22,14 +23,16 @@ class SubmissionTestResultConsentGivenViewModelTest : BaseTest() { MockKAnnotations.init(this, relaxed = true) } - private fun createViewModel() = SubmissionTestResultConsentGivenViewModel(submissionRepository) + private fun createViewModel() = SubmissionTestResultConsentGivenViewModel( + submissionRepository = submissionRepository, + dispatcherProvider = TestDispatcherProvider + ) @Test fun testOnConsentProvideSymptomsButtonClick() { viewModel = createViewModel() viewModel.onContinuePressed() viewModel.routeToScreen.value shouldBe SubmissionNavigationEvents.NavigateToSymptomIntroduction - } @Test diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/tracing/card/TracingCardStateTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/tracing/card/TracingCardStateTest.kt index dd06def65231a1bba01790341fbe48f662a6edb4..c3f145a36d2adb2d12145baf34ec892451926c29 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/tracing/card/TracingCardStateTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/tracing/card/TracingCardStateTest.kt @@ -169,6 +169,48 @@ class TracingCardStateTest : BaseTest() { } } + @Test + fun `saved risk body when tracing is disabled`() { + createInstance( + riskState = CALCULATION_FAILED, + lastSuccessfulRiskState = LOW_RISK, + tracingStatus = Status.TRACING_INACTIVE + ).apply { + getSavedRiskBody(context) + verify { + context + .getString(R.string.risk_card_no_calculation_possible_body_saved_risk) + .format(context.getString(R.string.risk_card_low_risk_headline)) + } + } + + createInstance( + riskState = CALCULATION_FAILED, + lastSuccessfulRiskState = INCREASED_RISK, + tracingStatus = Status.TRACING_INACTIVE + ).apply { + getSavedRiskBody(context) + verify { + context + .getString(R.string.risk_card_no_calculation_possible_body_saved_risk) + .format(context.getString(R.string.risk_card_increased_risk_headline)) + } + } + + createInstance( + riskState = CALCULATION_FAILED, + lastSuccessfulRiskState = LOW_RISK, + tracingStatus = Status.TRACING_INACTIVE + ).apply { + getSavedRiskBody(context) + verify { + context + .getString(R.string.risk_card_no_calculation_possible_body_saved_risk) + .format(context.getString(R.string.risk_card_low_risk_headline)) + } + } + } + @Test fun `risk contact body is affected by risklevel`() { createInstance(riskState = CALCULATION_FAILED, daysWithEncounters = 0).apply { diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/worker/DiagnosisKeyRetrievalOneTimeWorkerTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/worker/DiagnosisKeyRetrievalOneTimeWorkerTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..3a52e5a32629ee92e88f34c0ca793fbd0922d320 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/worker/DiagnosisKeyRetrievalOneTimeWorkerTest.kt @@ -0,0 +1,53 @@ +package de.rki.coronawarnapp.worker + +/** + * DiagnosisKeyRetrievalOneTimeWorker test. + */ +class DiagnosisKeyRetrievalOneTimeWorkerTest { +// private lateinit var context: Context +// private lateinit var worker: ListenableWorker +// +// @Before +// fun setUp() { +// context = ApplicationProvider.getApplicationContext() +// mockkObject(RetrieveDiagnosisKeysTransaction) +// } +// +// /** +// * Test worker result = [ListenableWorker.Result.success] +// */ +// @Test +// fun testDiagnosisKeyRetrievalOneTimeWorkerSuccess() { +// worker = +// TestListenableWorkerBuilder<DiagnosisKeyRetrievalOneTimeWorker>(context).build() +// coEvery { RetrieveDiagnosisKeysTransaction.start() } just Runs +// val result = worker.startWork().get() +// assertThat(result, `is`(ListenableWorker.Result.success())) +// } +// +// /** +// * Test worker result = [ListenableWorker.Result.retry] +// */ +// @Test +// fun testDiagnosisKeyRetrievalOneTimeWorkerRetry() { +// worker = +// TestListenableWorkerBuilder<DiagnosisKeyRetrievalOneTimeWorker>(context).build() +// coEvery { RetrieveDiagnosisKeysTransaction.start() } throws Exception("test exception") +// val result = worker.startWork().get() +// assertThat(result, `is`(ListenableWorker.Result.retry())) +// } +// +// /** +// * Test worker result = [ListenableWorker.Result.failure] +// * Check [BackgroundConstants.WORKER_RETRY_COUNT_THRESHOLD] for proper attempt count. +// * +// * @see [BackgroundConstants.WORKER_RETRY_COUNT_THRESHOLD] +// */ +// @Test +// fun testDiagnosisKeyRetrievalOneTimeWorkerFailed() { +// worker = +// TestListenableWorkerBuilder<DiagnosisKeyRetrievalOneTimeWorker>(context).setRunAttemptCount(5).build() +// val result = worker.startWork().get() +// assertThat(result, `is`(ListenableWorker.Result.failure())) +// } +} diff --git a/Corona-Warn-App/src/test/java/testhelpers/room/RoomMockExtensions.kt b/Corona-Warn-App/src/test/java/testhelpers/room/RoomMockExtensions.kt new file mode 100644 index 0000000000000000000000000000000000000000..0a3840f884e6d7b800f252574bc0f172934dd8a9 --- /dev/null +++ b/Corona-Warn-App/src/test/java/testhelpers/room/RoomMockExtensions.kt @@ -0,0 +1,15 @@ +package testhelpers.room + +import androidx.room.RoomDatabase +import androidx.room.withTransaction +import io.mockk.coEvery +import io.mockk.mockkStatic +import io.mockk.slot + +fun RoomDatabase.mockDefaultOperations() { + mockkStatic("androidx.room.RoomDatabaseKt") + val transaction = slot<suspend () -> Unit>() + coEvery { any<RoomDatabase>().withTransaction(capture(transaction)) } coAnswers { + transaction.captured.invoke() + } +} diff --git a/Corona-Warn-App/src/testDeviceForTesters/java/de/rki/coronawarnapp/test/api/ui/TestForApiFragmentViewModelTest.kt b/Corona-Warn-App/src/testDeviceForTesters/java/de/rki/coronawarnapp/test/api/ui/TestForApiFragmentViewModelTest.kt index b132c1dec5cc6518c811289293f39578b911b531..f78db7fb609e26accf5ec64bcb9dae722a0e7b5c 100644 --- a/Corona-Warn-App/src/testDeviceForTesters/java/de/rki/coronawarnapp/test/api/ui/TestForApiFragmentViewModelTest.kt +++ b/Corona-Warn-App/src/testDeviceForTesters/java/de/rki/coronawarnapp/test/api/ui/TestForApiFragmentViewModelTest.kt @@ -30,9 +30,4 @@ class TestForApiFragmentViewModelTest : BaseTest() { fun teardown() { clearAllMocks() } - - private fun createViewModel(): TestForApiFragmentViewModel = TestForApiFragmentViewModel( - context = context, - taskController = taskController - ) }