From 387c9d34f418215f5a5eb59e50d9863d3bebbfcf Mon Sep 17 00:00:00 2001 From: Giorgos Papadopoulos Date: Fri, 1 Dec 2023 14:23:18 +0100 Subject: [PATCH 01/21] start app in the app deactivated status --- holder/src/main/res/navigation/holder_nav_graph_root.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/holder/src/main/res/navigation/holder_nav_graph_root.xml b/holder/src/main/res/navigation/holder_nav_graph_root.xml index f08f18aeb..637cfa8bf 100644 --- a/holder/src/main/res/navigation/holder_nav_graph_root.xml +++ b/holder/src/main/res/navigation/holder_nav_graph_root.xml @@ -3,7 +3,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/root_nav" - app:startDestination="@+id/nav_main"> + app:startDestination="@+id/nav_status"> Date: Fri, 1 Dec 2023 14:23:34 +0100 Subject: [PATCH 02/21] remove openid dependency --- .../ctr/appconfig/AppStatusFragment.kt | 2 +- .../res/navigation/app_status_nav_graph.xml | 4 +- holder/build.gradle | 2 - holder/src/main/AndroidManifest.xml | 74 +-------- .../MijnCNAuthenticationRepository.kt | 96 ------------ .../ctr/holder/get_events/DigiDFragment.kt | 100 +----------- .../ctr/holder/get_events/LoginViewModel.kt | 145 ------------------ .../ctr/holder/modules/RepositoriesModules.kt | 12 -- .../ctr/holder/modules/ViewModels.kt | 6 - .../ctr/holder/no_digid/PapFragment.kt | 4 - 10 files changed, 6 insertions(+), 439 deletions(-) delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/api/repositories/MijnCNAuthenticationRepository.kt diff --git a/appconfig/src/main/java/nl/rijksoverheid/ctr/appconfig/AppStatusFragment.kt b/appconfig/src/main/java/nl/rijksoverheid/ctr/appconfig/AppStatusFragment.kt index 01886d28c..f60bc03ed 100644 --- a/appconfig/src/main/java/nl/rijksoverheid/ctr/appconfig/AppStatusFragment.kt +++ b/appconfig/src/main/java/nl/rijksoverheid/ctr/appconfig/AppStatusFragment.kt @@ -20,7 +20,7 @@ class AppStatusFragment : Fragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - when (val status = args.appStatus) { + when (val status = args.appStatus ?: AppStatus.Deactivated) { is AppStatus.UpdateRequired, is AppStatus.Deactivated, is AppStatus.Archived, diff --git a/appconfig/src/main/res/navigation/app_status_nav_graph.xml b/appconfig/src/main/res/navigation/app_status_nav_graph.xml index 8988c3dc5..3f75c8c42 100644 --- a/appconfig/src/main/res/navigation/app_status_nav_graph.xml +++ b/appconfig/src/main/res/navigation/app_status_nav_graph.xml @@ -11,7 +11,9 @@ + app:argType="nl.rijksoverheid.ctr.appconfig.models.AppStatus" + app:nullable="true" + android:defaultValue="@null"/> - + @@ -21,79 +20,8 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - , - authService: AuthorizationService - ) { - val authServiceConfiguration = authorizationServiceConfiguration() - val authRequest = authRequest(serviceConfiguration = authServiceConfiguration) - val authIntent = authService.getAuthorizationRequestIntent(authRequest) - activityResultLauncher.launch(authIntent) - } - - private suspend fun authorizationServiceConfiguration(): AuthorizationServiceConfiguration { - return suspendCoroutine { continuation -> - AuthorizationServiceConfiguration.fetchFromIssuer(Uri.parse(BuildConfig.MIJNCN_BASEURL)) { serviceConfiguration, error -> - when { - error != null -> continuation.resumeWithException(error) - serviceConfiguration != null -> continuation.resume(serviceConfiguration) - else -> throw Exception("Could not get service configuration") - } - } - } - } - - private fun authRequest(serviceConfiguration: AuthorizationServiceConfiguration): AuthorizationRequest { - return AuthorizationRequest.Builder( - serviceConfiguration, - BuildConfig.OPEN_ID_CLIENT_ID, - ResponseTypeValues.CODE, - Uri.parse(BuildConfig.OPEN_ID_REDIRECT_URL) - ).setScope("openid email profile").build() - } - - override suspend fun tokenResponse( - authService: AuthorizationService, - authResponse: AuthorizationResponse - ): TokenResponse { - val request = authResponse.createTokenExchangeRequest() - val res = retrieveAccessToken(request) - return suspendCoroutine { continuation -> - when (res) { - is NetworkRequestResult.Success -> continuation.resume(TokenResponse(res.response.idToken, res.response.accessToken)) - is NetworkRequestResult.Failed -> continuation.resumeWithException(Exception("Failed to get JWT")) - } - } - } - - private suspend fun retrieveAccessToken(tokenRequest: TokenRequest): NetworkRequestResult { - val result = - networkRequestResultFactory.createResult(HolderStep.AccessTokensNetworkRequest) { - mijnCnApiClient.getAccessToken( - url = tokenRequest.configuration.tokenEndpoint.toString(), - code = tokenRequest.authorizationCode ?: "", - grantType = tokenRequest.grantType, - redirectUri = BuildConfig.OPEN_ID_REDIRECT_URL, - codeVerifier = tokenRequest.codeVerifier ?: "", - clientId = tokenRequest.clientId - ) - } - return result - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/DigiDFragment.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/DigiDFragment.kt index ddac367f0..0096fdfc4 100644 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/DigiDFragment.kt +++ b/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/DigiDFragment.kt @@ -9,13 +9,6 @@ package nl.rijksoverheid.ctr.holder.get_events import android.os.Bundle import android.view.View -import androidx.activity.result.contract.ActivityResultContracts -import net.openid.appauth.AppAuthConfiguration -import net.openid.appauth.AuthorizationService -import net.openid.appauth.browser.BrowserAllowList -import net.openid.appauth.browser.BrowserSelector -import net.openid.appauth.browser.VersionRange -import net.openid.appauth.browser.VersionedBrowserMatcher import nl.rijksoverheid.ctr.design.fragments.info.ButtonData import nl.rijksoverheid.ctr.design.fragments.info.DescriptionData import nl.rijksoverheid.ctr.design.fragments.info.InfoFragmentData @@ -33,15 +26,12 @@ import nl.rijksoverheid.ctr.holder.get_events.models.LoginType import nl.rijksoverheid.ctr.holder.get_events.models.RemoteOriginType import nl.rijksoverheid.ctr.holder.get_events.models.RemoteProtocol import nl.rijksoverheid.ctr.holder.get_events.utils.LoginTypeUtil -import nl.rijksoverheid.ctr.holder.modules.qualifier.LoginQualifier import nl.rijksoverheid.ctr.holder.your_events.YourEventsFragmentType import nl.rijksoverheid.ctr.shared.livedata.EventObserver import nl.rijksoverheid.ctr.shared.models.ErrorResult import nl.rijksoverheid.ctr.shared.models.ErrorResultFragmentData import org.koin.android.ext.android.inject -import org.koin.androidx.viewmodel.ext.android.sharedViewModel import org.koin.androidx.viewmodel.ext.android.viewModel -import org.koin.core.qualifier.named /* * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. @@ -55,19 +45,6 @@ abstract class DigiDFragment(contentLayoutId: Int) : BaseFragment(contentLayoutI private val infoFragmentUtil: InfoFragmentUtil by inject() private val loginTypeUtil: LoginTypeUtil by inject() private val getEventsViewModel: GetEventsViewModel by viewModel() - protected val digidViewModel: LoginViewModel by sharedViewModel(named(LoginQualifier.DIGID)) - protected val mijnCnViewModel: LoginViewModel by viewModel(named(LoginQualifier.MIJN_CN)) - private val authService by lazy { - val appAuthConfig = AppAuthConfiguration.Builder() - .setBrowserMatcher(BrowserAllowList(*getSupportedBrowsers())) - .build() - AuthorizationService(requireActivity(), appAuthConfig) - } - - private val loginResult = - registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { - digidViewModel.handleActivityResult(getLoginType(), it, authService) - } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -185,69 +162,13 @@ abstract class DigiDFragment(contentLayoutId: Int) : BaseFragment(contentLayoutI } }) - digidViewModel.loading.observe(viewLifecycleOwner, EventObserver { - onDigidLoading(it) - (parentFragment?.parentFragment as HolderMainFragment).presentLoading(it) - }) - - digidViewModel.loginResultLiveData.observe(viewLifecycleOwner, EventObserver { - when (it) { - is LoginResult.Success -> { - getEventsViewModel.getDigidEvents( - getLoginType(), - it.jwt, - getOriginTypes() - ) - } - is LoginResult.Failed -> { - presentError(it.errorResult) - } - is LoginResult.Cancelled -> { - openDialog( - DialogFragmentData( - title = loginTypeUtil.getCanceledDialogTitle(getLoginType()), - message = loginTypeUtil.getCanceledDialogDescription( - getLoginType(), - getOriginTypes().first() - ), - positiveButtonData = DialogButtonData.Dismiss( - textId = R.string.dialog_close - ) - ) - ) - dialogPresented() - } - LoginResult.NoBrowserFound -> { - openDialog( - DialogFragmentData( - title = R.string.dialog_no_browser_title, - message = R.string.dialog_no_browser_message, - messageArguments = listOf( - getString( - loginTypeUtil.getNoBrowserDialogDescription( - getLoginType() - ) - ) - ), - positiveButtonData = DialogButtonData.Dismiss( - textId = R.string.ok - ) - ) - ) - dialogPresented() - } - } - onDigidLoading(false) - (parentFragment?.parentFragment as HolderMainFragment).presentLoading(false) - }) - getEventsViewModel.loading.observe(viewLifecycleOwner, EventObserver { onGetEventsLoading(it) }) } fun loginWithDigiD() { - digidViewModel.login(getLoginType(), loginResult, authService) + } private fun getErrorCodes(errorResults: List): String { @@ -265,25 +186,6 @@ abstract class DigiDFragment(contentLayoutId: Int) : BaseFragment(contentLayoutI } } - /** - * Gets all supported browsers and filters out the custom tab browsers as those can cause - * issues with DigiD - * - * @return Array of browser matchers supported for the app auth config - */ - private fun getSupportedBrowsers(): Array = - BrowserSelector.getAllBrowsers(context) - .filter { it.useCustomTab == false } - .filter { it.packageName != "android" } - .map { - VersionedBrowserMatcher( - it.packageName, - it.signatureHashes, - false, - VersionRange.ANY_VERSION - ) - }.toTypedArray() - protected fun getCopyForOriginType(): GetEventsFragmentCopy { when (getOriginTypes().first()) { is RemoteOriginType.Test -> { diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/LoginViewModel.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/LoginViewModel.kt index 6e4d2e75f..bc38b684b 100644 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/LoginViewModel.kt +++ b/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/LoginViewModel.kt @@ -7,28 +7,11 @@ package nl.rijksoverheid.ctr.holder.get_events -import android.content.ActivityNotFoundException -import android.content.Intent -import androidx.activity.result.ActivityResult -import androidx.activity.result.ActivityResultLauncher import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import kotlinx.coroutines.launch -import net.openid.appauth.AuthorizationException -import net.openid.appauth.AuthorizationResponse -import net.openid.appauth.AuthorizationService -import nl.rijksoverheid.ctr.holder.BuildConfig -import nl.rijksoverheid.ctr.holder.get_events.models.LoginType -import nl.rijksoverheid.ctr.holder.models.HolderStep.DigidNetworkRequest -import nl.rijksoverheid.ctr.shared.exceptions.OpenIdAuthorizationException import nl.rijksoverheid.ctr.shared.livedata.Event -import nl.rijksoverheid.ctr.shared.models.NetworkRequestResult -import nl.rijksoverheid.ctr.shared.models.OpenIdErrorResult.Error -import nl.rijksoverheid.ctr.shared.models.OpenIdErrorResult.ServerBusy import nl.rijksoverheid.ctr.shared.utils.AndroidUtil -import nl.rijksoverheid.rdo.modules.openidconnect.OpenIDConnectRepository /* * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. @@ -38,137 +21,9 @@ import nl.rijksoverheid.rdo.modules.openidconnect.OpenIDConnectRepository * */ class LoginViewModel( - private val digidAuthenticationRepository: OpenIDConnectRepository, private val androidUtil: AndroidUtil ) : ViewModel() { - private companion object { - const val USER_CANCELLED_FLOW_CODE = 1 - const val NETWORK_ERROR = 3 - const val LOGIN_REQUIRED_ERROR = "login_required" - const val SAML_AUTHN_FAILED_ERROR = "saml_authn_failed" - const val CANCELLED = "cancelled" - } - val loading: LiveData> = MutableLiveData() val loginResultLiveData = MutableLiveData>() - - fun login( - loginType: LoginType, - activityResultLauncher: ActivityResultLauncher, - authService: AuthorizationService - ) { - (loading as MutableLiveData).value = Event(true) - val issuerUrl = when (loginType) { - LoginType.Max -> BuildConfig.MAX_BASE_URL - LoginType.Pap -> BuildConfig.PAP_BASE_URL - } - viewModelScope.launch { - try { - digidAuthenticationRepository.requestAuthorization(issuerUrl, activityResultLauncher, authService) - } catch (e: Exception) { - postExceptionResult(e) - loading.value = Event(false) - } - } - } - - fun handleActivityResult(loginType: LoginType, activityResult: ActivityResult, authService: AuthorizationService) { - viewModelScope.launch { - val intent = activityResult.data - if (intent != null) { - val authResponse = AuthorizationResponse.fromIntent(intent) - val authError = AuthorizationException.fromIntent(intent) - when { - authError != null -> postAuthErrorResult(authError) - authResponse != null -> postAuthResponseResult(loginType, authService, authResponse) - else -> postAuthNullResult() - } - } else { - loginResultLiveData.postValue(Event(LoginResult.Cancelled)) - } - } - } - - private fun postAuthErrorResult(authError: AuthorizationException) { - val digidResult = when { - isUserCancelled(authError) -> LoginResult.Cancelled - isNetworkError(authError) -> getNetworkErrorResult(authError) - isServerBusy(authError) -> getServerBusyResult(authError) - else -> LoginResult.Failed(Error(DigidNetworkRequest, mapToOpenIdException(authError))) - } - loginResultLiveData.postValue(Event(digidResult)) - } - - private fun mapToOpenIdException(authError: AuthorizationException) = - OpenIdAuthorizationException(type = authError.type, code = authError.code) - - private fun isNetworkError(authError: AuthorizationException): Boolean { - return authError.type == AuthorizationException.TYPE_GENERAL_ERROR && authError.code == NETWORK_ERROR - } - - private fun getNetworkErrorResult(authError: AuthorizationException): LoginResult { - return if (!androidUtil.isNetworkAvailable()) { - LoginResult.Failed(NetworkRequestResult.Failed.ClientNetworkError(DigidNetworkRequest)) - } else { - LoginResult.Failed( - NetworkRequestResult.Failed.ServerNetworkError( - DigidNetworkRequest, - mapToOpenIdException(authError) - ) - ) - } - } - - private fun isServerBusy(authError: AuthorizationException) = - authError.error == LOGIN_REQUIRED_ERROR - - private fun getServerBusyResult(authError: AuthorizationException) = - LoginResult.Failed( - ServerBusy(DigidNetworkRequest, mapToOpenIdException(authError)) - ) - - private fun isUserCancelled(authError: AuthorizationException) = - (authError.type == AuthorizationException.TYPE_GENERAL_ERROR && authError.code == USER_CANCELLED_FLOW_CODE) || - authError.error == SAML_AUTHN_FAILED_ERROR || - authError.error == CANCELLED - - private suspend fun postAuthResponseResult( - loginType: LoginType, - authService: AuthorizationService, - authResponse: AuthorizationResponse - ) { - try { - val tokenResponse = - digidAuthenticationRepository.tokenResponse(authService, authResponse) - val jwt = when (loginType) { - LoginType.Max -> tokenResponse.idToken!! - LoginType.Pap -> tokenResponse.accessToken!! - } - loginResultLiveData.postValue(Event(LoginResult.Success(jwt))) - } catch (e: Exception) { - postExceptionResult(e) - } - } - - private fun postExceptionResult(e: Exception) { - if (e is AuthorizationException) { - postAuthErrorResult(e) - } else { - // App Auth will launch a browser intent to log in with DigiD. - // When it throws an ActivityNotFoundException it means there is no browser app to handle the intent. - val result = if (e is ActivityNotFoundException) { - LoginResult.NoBrowserFound - } else { - LoginResult.Failed(Error(DigidNetworkRequest, e)) - } - loginResultLiveData.postValue(Event(result)) - } - } - - private fun postAuthNullResult() { - loginResultLiveData.postValue( - Event(LoginResult.Failed(Error(DigidNetworkRequest, NullPointerException()))) - ) - } } diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/RepositoriesModules.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/RepositoriesModules.kt index 1b16bfdef..745dc0071 100644 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/RepositoriesModules.kt +++ b/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/RepositoriesModules.kt @@ -1,6 +1,5 @@ package nl.rijksoverheid.ctr.holder.modules -import nl.rijksoverheid.ctr.holder.BuildConfig import nl.rijksoverheid.ctr.holder.api.HolderApiClientUtil import nl.rijksoverheid.ctr.holder.api.HolderApiClientUtilImpl import nl.rijksoverheid.ctr.holder.api.TestProviderApiClientUtil @@ -9,13 +8,9 @@ import nl.rijksoverheid.ctr.holder.api.repositories.CoronaCheckRepository import nl.rijksoverheid.ctr.holder.api.repositories.CoronaCheckRepositoryImpl import nl.rijksoverheid.ctr.holder.api.repositories.EventProviderRepository import nl.rijksoverheid.ctr.holder.api.repositories.EventProviderRepositoryImpl -import nl.rijksoverheid.ctr.holder.api.repositories.MijnCNAuthenticationRepository import nl.rijksoverheid.ctr.holder.api.repositories.TestProviderRepository import nl.rijksoverheid.ctr.holder.api.repositories.TestProviderRepositoryImpl import nl.rijksoverheid.ctr.holder.modules.qualifier.ErrorResponseQualifier -import nl.rijksoverheid.ctr.holder.modules.qualifier.LoginQualifier -import nl.rijksoverheid.rdo.modules.openidconnect.OpenIDConnectRepository -import nl.rijksoverheid.rdo.modules.openidconnect.OpenIDConnectRepositoryImpl import org.koin.core.qualifier.named import org.koin.dsl.module @@ -27,13 +22,6 @@ import org.koin.dsl.module * */ val repositoriesModule = module { - single(named(LoginQualifier.DIGID)) { OpenIDConnectRepositoryImpl(BuildConfig.OPEN_ID_CLIENT_ID, BuildConfig.OPEN_ID_REDIRECT_URL) } - single(named(LoginQualifier.MIJN_CN)) { - MijnCNAuthenticationRepository( - get(), - get() - ) - } factory { HolderApiClientUtilImpl(get(), get()) } diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/ViewModels.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/ViewModels.kt index 6f205ae61..d00cb9e31 100644 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/ViewModels.kt +++ b/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/ViewModels.kt @@ -45,12 +45,6 @@ val viewModels = module { viewModel { QrCodesViewModelImpl(get(), get(), get()) } viewModel { HolderMainActivityViewModelImpl() } viewModel { InputTokenViewModelImpl(get(), get()) } - viewModel(named(LoginQualifier.DIGID)) { - LoginViewModel(get(named(LoginQualifier.DIGID)), get()) - } - viewModel(named(LoginQualifier.MIJN_CN)) { - LoginViewModel(get(named(LoginQualifier.MIJN_CN)), get()) - } viewModel { DeviceRootedViewModelImpl(get(), get()) } viewModel { DeviceSecureViewModelImpl(get(), get()) } viewModel { YourEventsViewModelImpl(get(), get(), get()) } diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/no_digid/PapFragment.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/no_digid/PapFragment.kt index 29ffdb0d2..e0b0ecf14 100644 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/no_digid/PapFragment.kt +++ b/holder/src/main/java/nl/rijksoverheid/ctr/holder/no_digid/PapFragment.kt @@ -181,10 +181,6 @@ class PapFragment : DigiDFragment(R.layout.fragment_no_digid) { } } } - - digidViewModel.loading.observe(viewLifecycleOwner, EventObserver { - (parentFragment?.parentFragment as HolderMainFragment).presentLoading(it) - }) } override fun getLoginType(): LoginType { From fd28eb3990020664a2815b7151c55ac57e781ea2 Mon Sep 17 00:00:00 2001 From: Giorgos Papadopoulos Date: Fri, 1 Dec 2023 14:30:34 +0100 Subject: [PATCH 03/21] update deactivated messages --- holder/src/main/res/values-en/strings.xml | 2 +- holder/src/main/res/values/strings.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/holder/src/main/res/values-en/strings.xml b/holder/src/main/res/values-en/strings.xml index 79a34f278..18b079a19 100644 --- a/holder/src/main/res/values-en/strings.xml +++ b/holder/src/main/res/values-en/strings.xml @@ -93,7 +93,7 @@ This is the only way the app can scan your QR code. We\'re starting the app... App not in use - The app is not in use at the moment. For more information, go to CoronaCheck.nl + The app is not in use anymore. For more information, go to CoronaCheck.nl Go to CoronaCheck.nl Time for an update To continue, install the latest version of the app. diff --git a/holder/src/main/res/values/strings.xml b/holder/src/main/res/values/strings.xml index 5d5d61da0..3d0007a58 100644 --- a/holder/src/main/res/values/strings.xml +++ b/holder/src/main/res/values/strings.xml @@ -93,7 +93,7 @@ Alleen zo kan de app jouw QR-code scannen. We starten de app voor je op… App niet in gebruik - Op dit moment is de app niet in gebruik. Ga voor meer informatie naar CoronaCheck.nl + De app is niet meer in gebruikt. Ga voor meer informatie naar CoronaCheck.nl Naar CoronaCheck.nl Tijd voor een update Je hebt de laatste versie van de app nodig om verder te gaan. From 5bc8429fe4d913c858884d59b630f1235cc2b6bc Mon Sep 17 00:00:00 2001 From: Giorgos Papadopoulos Date: Fri, 1 Dec 2023 14:38:59 +0100 Subject: [PATCH 04/21] simplify app startup --- .../ctr/holder/HolderMainActivity.kt | 152 ------------------ 1 file changed, 152 deletions(-) diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/HolderMainActivity.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/HolderMainActivity.kt index 6e836ace2..7c18e42e9 100644 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/HolderMainActivity.kt +++ b/holder/src/main/java/nl/rijksoverheid/ctr/holder/HolderMainActivity.kt @@ -8,36 +8,18 @@ package nl.rijksoverheid.ctr.holder -import android.content.Intent -import android.net.ConnectivityManager -import android.net.Network -import android.net.NetworkRequest import android.os.Bundle import android.view.WindowManager import androidx.appcompat.app.AppCompatActivity -import androidx.lifecycle.coroutineScope -import androidx.lifecycle.lifecycleScope -import androidx.navigation.NavController -import androidx.navigation.fragment.NavHostFragment -import nl.rijksoverheid.ctr.appconfig.AppConfigViewModel -import nl.rijksoverheid.ctr.appconfig.models.AppStatus import nl.rijksoverheid.ctr.design.utils.DialogButtonData import nl.rijksoverheid.ctr.design.utils.DialogFragmentData import nl.rijksoverheid.ctr.design.utils.DialogUtil -import nl.rijksoverheid.ctr.design.utils.IntentUtil import nl.rijksoverheid.ctr.design.utils.SharedDialogFragment -import nl.rijksoverheid.ctr.holder.api.repositories.CoronaCheckRepository import nl.rijksoverheid.ctr.holder.databinding.ActivityMainBinding import nl.rijksoverheid.ctr.holder.ui.device_rooted.DeviceRootedViewModel import nl.rijksoverheid.ctr.holder.ui.device_secure.DeviceSecureViewModel import nl.rijksoverheid.ctr.holder.ui.priority_notification.PriorityNotificationViewModel -import nl.rijksoverheid.ctr.holder.usecases.HolderFeatureFlagUseCase -import nl.rijksoverheid.ctr.holder.workers.WorkerManagerUtil -import nl.rijksoverheid.ctr.introduction.IntroductionViewModel -import nl.rijksoverheid.ctr.shared.MobileCoreWrapper -import nl.rijksoverheid.ctr.shared.ext.disableSplashscreenExitAnimation import nl.rijksoverheid.ctr.shared.livedata.EventObserver -import nl.rijksoverheid.ctr.shared.utils.AndroidUtil import org.koin.android.ext.android.inject import org.koin.androidx.viewmodel.ext.android.viewModel @@ -50,36 +32,10 @@ import org.koin.androidx.viewmodel.ext.android.viewModel */ class HolderMainActivity : AppCompatActivity() { - private val introductionViewModel: IntroductionViewModel by viewModel() - private val appConfigViewModel: AppConfigViewModel by viewModel() private val deviceRootedViewModel: DeviceRootedViewModel by viewModel() private val deviceSecureViewModel: DeviceSecureViewModel by viewModel() private val priorityNotificationViewModel: PriorityNotificationViewModel by viewModel() private val dialogUtil: DialogUtil by inject() - private val mobileCoreWrapper: MobileCoreWrapper by inject() - private val intentUtil: IntentUtil by inject() - private var isFreshStart: Boolean = true // track if this is a fresh start of the app - private val androidUtil: AndroidUtil by inject() - private val workerManagerUtil: WorkerManagerUtil by inject() - private val coronaCheckRepository: CoronaCheckRepository by inject() - private val featureFlagUseCase: HolderFeatureFlagUseCase by inject() - - private val connectivityChangeCallback = - object : ConnectivityManager.NetworkCallback() { - private var refreshConfig = false - override fun onAvailable(network: Network) { - if (refreshConfig) { - appConfigViewModel.refresh(mobileCoreWrapper, true) - refreshConfig = false - } - } - - override fun onUnavailable() { - refreshConfig = true - } - } - private val networkChangeFilter = - NetworkRequest.Builder().build() // blank filter for all networks override fun onCreate(savedInstanceState: Bundle?) { setTheme(R.style.AppTheme_DayNight) @@ -94,18 +50,6 @@ class HolderMainActivity : AppCompatActivity() { ) } - val navHostFragment = - supportFragmentManager.findFragmentById(R.id.main_nav_host_fragment) as NavHostFragment - val navController = navHostFragment.navController - - introductionViewModel.introductionRequiredLiveData.observe(this, EventObserver { - navigateToIntroduction(navController) - }) - - appConfigViewModel.appStatusLiveData.observe(this) { - handleAppStatus(it, navController) - } - deviceRootedViewModel.deviceRootedLiveData.observe(this, EventObserver { if (it) { dialogUtil.presentDialog( @@ -144,101 +88,5 @@ class HolderMainActivity : AppCompatActivity() { ) ) }) - - disableSplashscreenExitAnimation() - } - - private fun navigateToIntroduction( - navController: NavController - ) { - navController.navigate(RootNavDirections.actionIntroduction()) - } - - private fun handleAppStatus( - appStatus: AppStatus, - navController: NavController - ) { - - if (appStatus == AppStatus.Deactivated || featureFlagUseCase.isInArchiveMode()) { - workerManagerUtil.cancelRefreshCredentialsJob(this) - } else { - // schedule background refresh for existing greencards - lifecycleScope.launchWhenCreated { - workerManagerUtil.scheduleRefreshCredentialsJob() - } - } - - if (appStatus is AppStatus.UpdateRecommended) { - showRecommendedUpdateDialog() - return - } - - if (appStatus !is AppStatus.NoActionRequired) { - navController.navigate(RootNavDirections.actionAppStatus(appStatus)) - } else { - closeAppStatusIfOpen(navController) - } - } - - private fun closeAppStatusIfOpen( - navController: NavController - ) { - val isAppStatusFragment = - navController.currentBackStackEntry?.destination?.id == R.id.nav_app_locked - if (isAppStatusFragment) { - navController.navigate(RootNavDirections.actionMain()) - } - } - - private fun showRecommendedUpdateDialog() { - dialogUtil.presentDialog( - context = this, - title = R.string.app_status_update_recommended_title, - message = getString(R.string.app_status_update_recommended_message), - positiveButtonText = R.string.app_status_update_recommended_action, - positiveButtonCallback = { intentUtil.openPlayStore(this) }, - negativeButtonText = R.string.app_status_update_recommended_dismiss_action - ) - } - - override fun onStart() { - super.onStart() - // get app and providers config on every app foreground when introduction is finished - if (!introductionViewModel.getIntroductionRequired()) { - appConfigViewModel.refresh(mobileCoreWrapper, isFreshStart) { - lifecycle.coroutineScope.launchWhenStarted { - coronaCheckRepository.configProviders(useCache = false) - } - } - isFreshStart = false - } - } - - override fun onResume() { - super.onResume() - // Add connectivity change listener. If a network is detected try to refresh the config - androidUtil.getConnectivityManager().registerNetworkCallback( - networkChangeFilter, connectivityChangeCallback - ) - } - - override fun onPause() { - super.onPause() - androidUtil.getConnectivityManager().unregisterNetworkCallback(connectivityChangeCallback) - } - - override fun onNewIntent(intent: Intent?) { - super.onNewIntent(intent) - - // Handle if an external app sets the launch mode of this activity to single top of single task. - // In this case we need to set the graph again and handle the deeplink ourselves so that the entire - // graph is traversed to find the deeplink - val navHostFragment = - supportFragmentManager.findFragmentById(R.id.main_nav_host_fragment) as NavHostFragment - val navController = navHostFragment.navController - navController.setGraph(R.navigation.holder_nav_graph_root) - if (featureFlagUseCase.getAddEventsButtonEnabled()) { - navController.handleDeepLink(intent) - } } } From 931520b5496560eed6ef47b216dcf60a92f6014a Mon Sep 17 00:00:00 2001 From: Giorgos Papadopoulos Date: Fri, 1 Dec 2023 14:51:40 +0100 Subject: [PATCH 05/21] don't use config --- .../ctr/holder/HolderMainActivity.kt | 54 ------------------- .../ctr/introduction/setup/SetupFragment.kt | 30 ----------- 2 files changed, 84 deletions(-) diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/HolderMainActivity.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/HolderMainActivity.kt index 7c18e42e9..a0c32aa03 100644 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/HolderMainActivity.kt +++ b/holder/src/main/java/nl/rijksoverheid/ctr/holder/HolderMainActivity.kt @@ -11,17 +11,7 @@ package nl.rijksoverheid.ctr.holder import android.os.Bundle import android.view.WindowManager import androidx.appcompat.app.AppCompatActivity -import nl.rijksoverheid.ctr.design.utils.DialogButtonData -import nl.rijksoverheid.ctr.design.utils.DialogFragmentData -import nl.rijksoverheid.ctr.design.utils.DialogUtil -import nl.rijksoverheid.ctr.design.utils.SharedDialogFragment import nl.rijksoverheid.ctr.holder.databinding.ActivityMainBinding -import nl.rijksoverheid.ctr.holder.ui.device_rooted.DeviceRootedViewModel -import nl.rijksoverheid.ctr.holder.ui.device_secure.DeviceSecureViewModel -import nl.rijksoverheid.ctr.holder.ui.priority_notification.PriorityNotificationViewModel -import nl.rijksoverheid.ctr.shared.livedata.EventObserver -import org.koin.android.ext.android.inject -import org.koin.androidx.viewmodel.ext.android.viewModel /* * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. @@ -32,11 +22,6 @@ import org.koin.androidx.viewmodel.ext.android.viewModel */ class HolderMainActivity : AppCompatActivity() { - private val deviceRootedViewModel: DeviceRootedViewModel by viewModel() - private val deviceSecureViewModel: DeviceSecureViewModel by viewModel() - private val priorityNotificationViewModel: PriorityNotificationViewModel by viewModel() - private val dialogUtil: DialogUtil by inject() - override fun onCreate(savedInstanceState: Bundle?) { setTheme(R.style.AppTheme_DayNight) super.onCreate(savedInstanceState) @@ -49,44 +34,5 @@ class HolderMainActivity : AppCompatActivity() { WindowManager.LayoutParams.FLAG_SECURE ) } - - deviceRootedViewModel.deviceRootedLiveData.observe(this, EventObserver { - if (it) { - dialogUtil.presentDialog( - context = this, - title = R.string.dialog_rooted_device_title, - message = getString(R.string.dialog_rooted_device_message), - positiveButtonText = R.string.dialog_rooted_device_positive_button, - positiveButtonCallback = { }, - onDismissCallback = { deviceRootedViewModel.setHasDismissedRootedDeviceDialog() } - ) - } - }) - - deviceSecureViewModel.deviceSecureLiveData.observe(this, EventObserver { - if (!it) { - dialogUtil.presentDialog( - context = this, - title = R.string.dialog_device_secure_warning_title, - message = getString(R.string.dialog_device_secure_warning_description), - positiveButtonText = R.string.dialog_device_secure_positive_button, - positiveButtonCallback = { }, - onDismissCallback = { - deviceSecureViewModel.setHasDismissedUnsecureDeviceDialog( - true - ) - } - ) - } - }) - - priorityNotificationViewModel.showPriorityNotificationLiveData.observe(this, EventObserver { - SharedDialogFragment.show( - supportFragmentManager, DialogFragmentData( - text = it, - positiveButtonData = DialogButtonData.Dismiss(R.string.ok) - ) - ) - }) } } diff --git a/introduction/src/main/java/nl/rijksoverheid/ctr/introduction/setup/SetupFragment.kt b/introduction/src/main/java/nl/rijksoverheid/ctr/introduction/setup/SetupFragment.kt index f0a1bfbba..1cff87d2d 100644 --- a/introduction/src/main/java/nl/rijksoverheid/ctr/introduction/setup/SetupFragment.kt +++ b/introduction/src/main/java/nl/rijksoverheid/ctr/introduction/setup/SetupFragment.kt @@ -3,14 +3,8 @@ package nl.rijksoverheid.ctr.introduction.setup import android.os.Bundle import android.view.View import androidx.fragment.app.Fragment -import nl.rijksoverheid.ctr.appconfig.AppConfigViewModel -import nl.rijksoverheid.ctr.appconfig.models.AppStatus import nl.rijksoverheid.ctr.introduction.R -import nl.rijksoverheid.ctr.shared.MobileCoreWrapper -import nl.rijksoverheid.ctr.shared.ext.findNavControllerSafety import nl.rijksoverheid.ctr.shared.utils.Accessibility -import org.koin.android.ext.android.inject -import org.koin.androidx.viewmodel.ext.android.sharedViewModel /* * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. @@ -21,33 +15,9 @@ import org.koin.androidx.viewmodel.ext.android.sharedViewModel */ class SetupFragment : Fragment(R.layout.fragment_setup) { - private val appStatusViewModel: AppConfigViewModel by sharedViewModel() - private val mobileCoreWrapper: MobileCoreWrapper by inject() - private val setupViewModel: SetupViewModel by inject() - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) Accessibility.announce(requireContext(), getString(R.string.app_setup_text)) - - setObservers() - } - - override fun onStart() { - super.onStart() - appStatusViewModel.refresh(mobileCoreWrapper, true) - } - - private fun setObservers() { - appStatusViewModel.appStatusLiveData.observe(viewLifecycleOwner) { - if (it is AppStatus.NoActionRequired || it is AppStatus.UpdateRecommended) { - setupViewModel.onConfigUpdated() - } - } - setupViewModel.introductionDataLiveData.observe(viewLifecycleOwner) { - findNavControllerSafety()?.navigate( - SetupFragmentDirections.actionOnboarding(it) - ) - } } } From bf0dc0ee2e7bbc72280af18c36c4835630e3c4b4 Mon Sep 17 00:00:00 2001 From: Giorgos Papadopoulos Date: Fri, 1 Dec 2023 15:12:03 +0100 Subject: [PATCH 06/21] remove unnecessary app startup code --- .../ctr/holder/HolderApplication.kt | 24 +------------------ 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/HolderApplication.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/HolderApplication.kt index 244da3621..e59844834 100644 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/HolderApplication.kt +++ b/holder/src/main/java/nl/rijksoverheid/ctr/holder/HolderApplication.kt @@ -1,7 +1,5 @@ package nl.rijksoverheid.ctr.holder -import android.util.Log -import androidx.work.Configuration import androidx.work.WorkerFactory import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -49,12 +47,9 @@ import org.koin.core.module.Module * SPDX-License-Identifier: EUPL-1.2 * */ -open class HolderApplication : SharedApplication(), Configuration.Provider { +open class HolderApplication : SharedApplication() { private val holderDatabase: HolderDatabase by inject() - private val holderWorkerFactory: WorkerFactory by inject() - private val appConfigStorageManager: AppConfigStorageManager by inject() - private val mobileCoreWrapper: MobileCoreWrapper by inject() private val remoteCTBUseCase: RemoveCTBUseCase by inject() private val coroutineScope = CoroutineScope(Dispatchers.IO) @@ -115,26 +110,9 @@ open class HolderApplication : SharedApplication(), Configuration.Provider { } remoteCTBUseCase.execute() } - - if (appConfigStorageManager.areConfigFilesPresentInFilesFolder()) { - mobileCoreWrapper.initializeHolder(applicationContext.filesDir.path) - } } override fun getAdditionalModules(): List { return listOf(holderPreferenceModule, holderMobileCoreModule) } - - override fun getWorkManagerConfiguration(): Configuration { - return Configuration.Builder().apply { - setMinimumLoggingLevel( - if (BuildConfig.DEBUG) { - Log.DEBUG - } else { - Log.ERROR - } - ) - setWorkerFactory(holderWorkerFactory) - }.build() - } } From 20d265e918c590c173ffe048e0b529354b79c8c0 Mon Sep 17 00:00:00 2001 From: Giorgos Papadopoulos Date: Fri, 1 Dec 2023 15:33:28 +0100 Subject: [PATCH 07/21] delete part 1 --- .../rijksoverheid/ctr/holder/BaseFragment.kt | 152 ---- .../ctr/holder/HolderApplication.kt | 26 - .../ctr/holder/HolderMainActivityViewModel.kt | 35 - .../ctr/holder/HolderMainFragment.kt | 102 --- .../ctr/holder/api/HolderApiClient.kt | 35 - .../ctr/holder/api/HolderApiClientUtil.kt | 78 -- .../ctr/holder/api/MijnCnApiClient.kt | 31 - .../ctr/holder/api/OriginTypeJsonAdapter.kt | 13 - .../ctr/holder/api/RemoteConfigApiClient.kt | 11 - .../api/RemoteCouplingStatusJsonAdapter.kt | 19 - .../holder/api/RemoteTestStatusJsonAdapter.kt | 19 - .../ctr/holder/api/TestProviderApiClient.kt | 53 -- .../holder/api/TestProviderApiClientUtil.kt | 87 -- .../api/models/SignedResponseWithModel.kt | 14 - .../ctr/holder/api/post/GetCouplingData.kt | 13 - .../holder/api/post/GetCredentialsPostData.kt | 15 - .../ctr/holder/api/post/GetTestIsmPostData.kt | 18 - .../holder/api/post/GetTestResultPostData.kt | 15 - .../api/repositories/CoronaCheckRepository.kt | 177 ---- .../repositories/EventProviderRepository.kt | 126 --- .../repositories/TestProviderRepository.kt | 81 -- .../CertificateCreatedFragment.kt | 46 - .../ChooseProofTypeFragment.kt | 72 -- .../choose_provider/ChooseProviderFragment.kt | 81 -- .../CouldNotCreateQrFragment.kt | 41 - .../ctr/holder/dashboard/DashboardFragment.kt | 318 ------- .../ctr/holder/dashboard/DashboardModule.kt | 16 - .../holder/dashboard/DashboardPageFragment.kt | 252 ----- .../holder/dashboard/DashboardPagerAdapter.kt | 51 -- .../holder/dashboard/DashboardViewModel.kt | 256 ------ .../DashboardTabsItemDataMapper.kt | 40 - .../items/DashboardAddQrCardAdapterItem.kt | 30 - .../items/DashboardGreenCardAdapterItem.kt | 249 ----- ...boardGreenCardAdapterItemBindingWrapper.kt | 38 - ...DashboardGreenCardAdapterItemExpiryUtil.kt | 198 ---- .../DashboardGreenCardAdapterItemUtil.kt | 313 ------- ...ashboardGreenCardPlaceHolderAdapterItem.kt | 48 - .../items/DashboardHeaderAdapterItem.kt | 58 -- .../items/DashboardHeaderAdapterItemUtil.kt | 67 -- .../items/DashboardInfoCardAdapterItem.kt | 104 --- .../items/DashboardInfoCardAdapterItemUtil.kt | 65 -- .../holder/dashboard/models/DashboardItem.kt | 98 -- .../holder/dashboard/models/DashboardItems.kt | 13 - .../dashboard/models/DashboardSyncState.kt | 14 - .../dashboard/models/DashboardTabItem.kt | 17 - .../dashboard/models/GreenCardEnabledState.kt | 15 - .../usecases/GetDashboardItemsUseCase.kt | 278 ------ .../RemoveExpiredGreenCardsUseCase.kt | 44 - .../ShowBlockedEventsDialogUseCase.kt | 37 - .../usecases/SortGreenCardItemsUseCase.kt | 48 - .../ctr/holder/dashboard/util/CardItemUtil.kt | 55 -- .../holder/dashboard/util/CredentialUtil.kt | 172 ---- .../util/DashboardItemEmptyStateUtil.kt | 29 - .../dashboard/util/DashboardItemUtil.kt | 140 --- .../util/DashboardPageInfoItemHandlerUtil.kt | 196 ---- .../dashboard/util/GreenCardRefreshUtil.kt | 136 --- .../holder/dashboard/util/GreenCardUtil.kt | 100 -- .../ctr/holder/dashboard/util/OriginUtil.kt | 56 -- .../util/RemovedEventsBottomSheetUtil.kt | 148 --- .../FuzzyMatchingBaseViewModel.kt | 40 - .../fuzzy_matching/FuzzyMatchingModule.kt | 52 -- .../FuzzyMatchingOnboardingFragment.kt | 187 ---- .../FuzzyMatchingOnboardingViewModel.kt | 16 - .../FuzzyMatchingSyncFragment.kt | 99 -- .../HolderNameSelectionFooterAdapterItem.kt | 32 - .../HolderNameSelectionFragment.kt | 201 ---- .../HolderNameSelectionHeaderAdapterItem.kt | 26 - .../fuzzy_matching/HolderNameSelectionItem.kt | 23 - .../HolderNameSelectionViewAdapterItem.kt | 56 -- .../HolderNameSelectionViewModel.kt | 114 --- .../fuzzy_matching/MatchedEventsUseCase.kt | 47 - .../holder/fuzzy_matching/MatchingBlobIds.kt | 14 - .../fuzzy_matching/SelectionDataUtil.kt | 108 --- ...lectionDetailBottomSheetDescriptionUtil.kt | 34 - .../fuzzy_matching/SelectionDetailData.kt | 14 - .../fuzzy_matching/ToolbarButtonsState.kt | 10 - .../ctr/holder/get_events/DigiDFragment.kt | 237 ----- .../holder/get_events/GetEventsFragment.kt | 185 ---- .../holder/get_events/GetEventsViewModel.kt | 95 -- .../ctr/holder/get_events/LoginResult.kt | 17 - .../ctr/holder/get_events/LoginViewModel.kt | 29 - .../holder/get_events/models/EventProvider.kt | 14 - .../holder/get_events/models/EventsResult.kt | 84 -- .../ctr/holder/get_events/models/Holder.kt | 21 - .../ctr/holder/get_events/models/LoginType.kt | 13 - .../get_events/models/MijnCNTokenResponse.kt | 20 - .../get_events/models/RemoteAccessTokens.kt | 30 - .../models/RemoteConfigProviders.kt | 115 --- .../holder/get_events/models/RemoteEvent.kt | 28 - .../models/RemoteEventNegativeTest.kt | 40 - .../models/RemoteEventPositiveTest.kt | 40 - .../get_events/models/RemoteEventRecovery.kt | 39 - .../models/RemoteEventVaccination.kt | 63 -- .../get_events/models/RemoteOriginType.kt | 37 - .../get_events/models/RemoteProtocol.kt | 57 -- .../holder/get_events/models/RemoteUnomi.kt | 17 - .../usecases/ConfigProvidersUseCase.kt | 71 -- .../GetEventProvidersWithTokensUseCase.kt | 115 --- .../get_events/usecases/GetEventsUseCase.kt | 218 ----- .../usecases/GetMijnCnEventsUsecase.kt | 150 --- .../usecases/GetRemoteEventsUseCase.kt | 65 -- .../GetRemoteProtocolFromEventGroupUseCase.kt | 40 - .../usecases/PersistBlockedEventsUseCase.kt | 44 - .../holder/get_events/utils/LoginTypeUtil.kt | 53 -- .../ctr/holder/get_events/utils/ScopeUtil.kt | 52 -- .../CommercialTestInputTokenFragment.kt | 54 -- .../holder/input_token/InputTokenFragment.kt | 231 ----- .../input_token/InputTokenFragmentData.kt | 55 -- .../holder/input_token/InputTokenViewModel.kt | 121 --- .../input_token/usecases/TestResultUseCase.kt | 151 --- .../ctr/holder/menu/AboutThisAppDataModel.kt | 80 -- .../ctr/holder/menu/HelpMenuDataModel.kt | 113 --- .../ctr/holder/menu/MenuViewModel.kt | 142 --- .../ctr/holder/models/HolderFlow.kt | 4 - .../ctr/holder/modules/AppModules.kt | 5 - .../ctr/holder/modules/CardUtilsModule.kt | 49 - .../holder/modules/EventsUseCasesModule.kt | 92 -- .../holder/modules/GreenCardUseCasesModule.kt | 58 -- .../ctr/holder/modules/QrsModule.kt | 28 - .../ctr/holder/modules/RepositoriesModules.kt | 43 - .../ctr/holder/modules/ResponsesModule.kt | 76 -- .../ctr/holder/modules/RetrofitModules.kt | 46 - .../ctr/holder/modules/StorageModule.kt | 24 - .../modules/TestProvidersUseCasesModule.kt | 28 - .../ctr/holder/modules/UtilsModule.kt | 105 --- .../ctr/holder/modules/ViewModels.kt | 36 - .../ctr/holder/no_digid/NoDigidFragment.kt | 99 -- .../no_digid/NoDigidFragmentArguments.kt | 62 -- .../holder/no_digid/NoDigidScreenDataUtil.kt | 126 --- .../ctr/holder/no_digid/PapFragment.kt | 247 ----- .../models/PaperProofDomesticCodeResult.kt | 22 - .../models/PaperProofDomesticResult.kt | 42 - .../paper_proof/models/PaperProofType.kt | 41 - .../models/RemoteCouplingResponse.kt | 15 - .../models/RemoteCouplingStatus.kt | 23 - .../GetDccFromEuropeanCredentialUseCase.kt | 25 - .../GetEventsFromPaperProofQrUseCase.kt | 54 -- .../usecases/GetPaperProofTypeUseCase.kt | 46 - ...idatePaperProofDomesticInputCodeUseCase.kt | 35 - .../ValidatePaperProofDomesticUseCase.kt | 71 -- .../paper_proof/utils/PaperProofUtil.kt | 66 -- .../ctr/holder/pdf/EUPrintAttributes.kt | 23 - .../holder/pdf/ExportIntroductionFragment.kt | 37 - .../ctr/holder/pdf/PDfPreviewInfo.kt | 10 - .../ctr/holder/pdf/PdfExportedFragment.kt | 54 -- .../ctr/holder/pdf/PdfPreview.kt | 13 - .../ctr/holder/pdf/PdfPreviewFragment.kt | 66 -- .../ctr/holder/pdf/PdfPreviewViewModel.kt | 35 - .../ctr/holder/pdf/PdfWebViewFragment.kt | 121 --- .../ctr/holder/pdf/PdfWebViewModel.kt | 84 -- .../ctr/holder/pdf/PreviewPdfUseCase.kt | 67 -- .../ctr/holder/pdf/PrintExportDccUseCase.kt | 37 - .../holder/qrcodes/QrCodeAnimationWidget.kt | 43 - .../ctr/holder/qrcodes/QrCodePagerAdapter.kt | 166 ---- .../ctr/holder/qrcodes/QrCodesFragment.kt | 446 --------- .../ctr/holder/qrcodes/QrCodesViewModel.kt | 66 -- .../holder/qrcodes/models/QrCodeAnimation.kt | 18 - .../ctr/holder/qrcodes/models/QrCodeData.kt | 32 - .../qrcodes/models/QrCodeFragmentData.kt | 25 - .../holder/qrcodes/models/QrCodesResult.kt | 11 - .../models/ReadEuropeanCredentialUtil.kt | 61 -- .../usecases/QrCodeAnimationUseCase.kt | 47 - .../holder/qrcodes/usecases/QrCodeUseCase.kt | 55 -- .../qrcodes/usecases/QrCodesResultUseCase.kt | 172 ---- .../qrcodes/utils/LastVaccinationDoseUtil.kt | 38 - .../qrcodes/utils/MultipleQrCodesUtil.kt | 26 - .../ctr/holder/qrcodes/utils/QrCodeUtil.kt | 75 -- .../qrcodes/utils/QrCodesFragmentUtil.kt | 34 - .../holder/qrcodes/utils/QrInfoScreenUtil.kt | 406 --------- .../ctr/holder/saved_events/SavedEvents.kt | 23 - .../saved_events/SavedEventsFragment.kt | 116 --- .../SavedEventsSyncGreenCardsFragment.kt | 59 -- .../saved_events/SavedEventsViewModel.kt | 46 - .../items/SavedEventAdapterItem.kt | 51 -- .../items/SavedEventsClearDataAdapterItem.kt | 34 - .../items/SavedEventsHeaderAdapterItem.kt | 40 - .../items/SavedEventsNoSavedEventsItem.kt | 27 - .../items/SavedEventsSectionAdapterItem.kt | 85 -- .../usecases/GetSavedEventsUseCase.kt | 127 --- .../SyncGreenCardsViewModel.kt | 58 -- .../ctr/holder/workers/ConfigFetchWorker.kt | 58 -- .../holder/workers/CredentialRefreshWorker.kt | 56 -- .../ctr/holder/workers/HolderWorkerFactory.kt | 49 - .../ctr/holder/workers/WorkerManagerUtil.kt | 84 -- .../YourEventExplanationFragment.kt | 69 -- .../holder/your_events/YourEventsFragment.kt | 739 --------------- .../your_events/YourEventsFragmentType.kt | 53 -- .../holder/your_events/YourEventsViewModel.kt | 121 --- .../models/ConflictingEventResult.kt | 7 - .../your_events/models/RemoteGreenCards.kt | 50 - .../holder/your_events/models/RemoteNonce.kt | 17 - .../your_events/models/RemotePrepareIssue.kt | 38 - .../your_events/models/YourEventsEndState.kt | 48 - .../your_events/usecases/SaveEventsUseCase.kt | 121 --- .../your_events/utils/CreateInfoLineUtil.kt | 23 - .../your_events/utils/EventGroupEntityUtil.kt | 29 - .../your_events/utils/InfoScreenUtil.kt | 98 -- .../utils/RecoveryInfoScreenUtil.kt | 134 --- .../utils/RemoteEventHolderUtil.kt | 90 -- .../utils/RemoteEventStringUtil.kt | 34 - .../your_events/utils/RemoteEventUtil.kt | 157 ---- .../your_events/utils/RemoteProtocol3Util.kt | 78 -- .../your_events/utils/TestInfoScreenUtil.kt | 269 ------ .../utils/VaccinationInfoScreenUtil.kt | 205 ----- .../utils/YourEventsEndStateUtil.kt | 157 ---- .../utils/YourEventsFragmentUtil.kt | 154 ---- .../your_events/widgets/YourEventWidget.kt | 55 -- .../widgets/YourEventWidgetUtil.kt | 70 -- .../database/HolderDatabaseSyncer.kt | 206 ----- .../usecases/CreateEuGreenCardsUseCase.kt | 75 -- .../database/usecases/DraftEventUseCase.kt | 30 - .../usecases/GetRemoteGreenCardsUseCase.kt | 124 --- .../database/usecases/RemoveCTBUseCase.kt | 52 -- .../usecases/RemoveExpiredEventsUseCase.kt | 30 - .../usecases/SyncRemoteGreenCardsUseCase.kt | 53 -- .../usecases/UpdateEventExpirationUseCase.kt | 29 - holder/src/main/res/layout/fragment_main.xml | 44 - .../res/navigation/holder_fuzzy_matching.xml | 86 -- .../res/navigation/holder_nav_graph_main.xml | 857 ------------------ .../res/navigation/holder_nav_graph_root.xml | 44 - 220 files changed, 18263 deletions(-) delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/BaseFragment.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/HolderMainActivityViewModel.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/HolderMainFragment.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/api/HolderApiClient.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/api/HolderApiClientUtil.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/api/MijnCnApiClient.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/api/OriginTypeJsonAdapter.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/api/RemoteConfigApiClient.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/api/RemoteCouplingStatusJsonAdapter.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/api/RemoteTestStatusJsonAdapter.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/api/TestProviderApiClient.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/api/TestProviderApiClientUtil.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/api/models/SignedResponseWithModel.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/api/post/GetCouplingData.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/api/post/GetCredentialsPostData.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/api/post/GetTestIsmPostData.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/api/post/GetTestResultPostData.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/api/repositories/CoronaCheckRepository.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/api/repositories/EventProviderRepository.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/api/repositories/TestProviderRepository.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/certificate_created/CertificateCreatedFragment.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/choose_proof_type/ChooseProofTypeFragment.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/choose_provider/ChooseProviderFragment.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/could_not_create_qr/CouldNotCreateQrFragment.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/DashboardFragment.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/DashboardModule.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/DashboardPageFragment.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/DashboardPagerAdapter.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/DashboardViewModel.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/datamappers/DashboardTabsItemDataMapper.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/items/DashboardAddQrCardAdapterItem.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/items/DashboardGreenCardAdapterItem.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/items/DashboardGreenCardAdapterItemBindingWrapper.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/items/DashboardGreenCardAdapterItemExpiryUtil.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/items/DashboardGreenCardAdapterItemUtil.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/items/DashboardGreenCardPlaceHolderAdapterItem.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/items/DashboardHeaderAdapterItem.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/items/DashboardHeaderAdapterItemUtil.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/items/DashboardInfoCardAdapterItem.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/items/DashboardInfoCardAdapterItemUtil.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/models/DashboardItem.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/models/DashboardItems.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/models/DashboardSyncState.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/models/DashboardTabItem.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/models/GreenCardEnabledState.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/usecases/GetDashboardItemsUseCase.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/usecases/RemoveExpiredGreenCardsUseCase.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/usecases/ShowBlockedEventsDialogUseCase.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/usecases/SortGreenCardItemsUseCase.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/util/CardItemUtil.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/util/CredentialUtil.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/util/DashboardItemEmptyStateUtil.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/util/DashboardItemUtil.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/util/DashboardPageInfoItemHandlerUtil.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/util/GreenCardRefreshUtil.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/util/GreenCardUtil.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/util/OriginUtil.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/util/RemovedEventsBottomSheetUtil.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/FuzzyMatchingBaseViewModel.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/FuzzyMatchingModule.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/FuzzyMatchingOnboardingFragment.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/FuzzyMatchingOnboardingViewModel.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/FuzzyMatchingSyncFragment.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/HolderNameSelectionFooterAdapterItem.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/HolderNameSelectionFragment.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/HolderNameSelectionHeaderAdapterItem.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/HolderNameSelectionItem.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/HolderNameSelectionViewAdapterItem.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/HolderNameSelectionViewModel.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/MatchedEventsUseCase.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/MatchingBlobIds.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/SelectionDataUtil.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/SelectionDetailBottomSheetDescriptionUtil.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/SelectionDetailData.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/ToolbarButtonsState.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/DigiDFragment.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/GetEventsFragment.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/GetEventsViewModel.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/LoginResult.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/LoginViewModel.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/EventProvider.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/EventsResult.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/Holder.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/LoginType.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/MijnCNTokenResponse.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/RemoteAccessTokens.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/RemoteConfigProviders.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/RemoteEvent.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/RemoteEventNegativeTest.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/RemoteEventPositiveTest.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/RemoteEventRecovery.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/RemoteEventVaccination.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/RemoteOriginType.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/RemoteProtocol.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/RemoteUnomi.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/usecases/ConfigProvidersUseCase.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/usecases/GetEventProvidersWithTokensUseCase.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/usecases/GetEventsUseCase.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/usecases/GetMijnCnEventsUsecase.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/usecases/GetRemoteEventsUseCase.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/usecases/GetRemoteProtocolFromEventGroupUseCase.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/usecases/PersistBlockedEventsUseCase.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/utils/LoginTypeUtil.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/utils/ScopeUtil.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/input_token/CommercialTestInputTokenFragment.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/input_token/InputTokenFragment.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/input_token/InputTokenFragmentData.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/input_token/InputTokenViewModel.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/input_token/usecases/TestResultUseCase.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/menu/AboutThisAppDataModel.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/menu/HelpMenuDataModel.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/menu/MenuViewModel.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/CardUtilsModule.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/EventsUseCasesModule.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/GreenCardUseCasesModule.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/QrsModule.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/ResponsesModule.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/RetrofitModules.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/TestProvidersUseCasesModule.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/no_digid/NoDigidFragment.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/no_digid/NoDigidFragmentArguments.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/no_digid/NoDigidScreenDataUtil.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/no_digid/PapFragment.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/paper_proof/models/PaperProofDomesticCodeResult.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/paper_proof/models/PaperProofDomesticResult.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/paper_proof/models/PaperProofType.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/paper_proof/models/RemoteCouplingResponse.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/paper_proof/models/RemoteCouplingStatus.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/paper_proof/usecases/GetDccFromEuropeanCredentialUseCase.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/paper_proof/usecases/GetEventsFromPaperProofQrUseCase.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/paper_proof/usecases/GetPaperProofTypeUseCase.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/paper_proof/usecases/ValidatePaperProofDomesticInputCodeUseCase.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/paper_proof/usecases/ValidatePaperProofDomesticUseCase.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/paper_proof/utils/PaperProofUtil.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/pdf/EUPrintAttributes.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/pdf/ExportIntroductionFragment.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/pdf/PDfPreviewInfo.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/pdf/PdfExportedFragment.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/pdf/PdfPreview.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/pdf/PdfPreviewFragment.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/pdf/PdfPreviewViewModel.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/pdf/PdfWebViewFragment.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/pdf/PdfWebViewModel.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/pdf/PreviewPdfUseCase.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/pdf/PrintExportDccUseCase.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/QrCodeAnimationWidget.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/QrCodePagerAdapter.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/QrCodesFragment.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/QrCodesViewModel.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/models/QrCodeAnimation.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/models/QrCodeData.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/models/QrCodeFragmentData.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/models/QrCodesResult.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/models/ReadEuropeanCredentialUtil.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/usecases/QrCodeAnimationUseCase.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/usecases/QrCodeUseCase.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/usecases/QrCodesResultUseCase.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/utils/LastVaccinationDoseUtil.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/utils/MultipleQrCodesUtil.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/utils/QrCodeUtil.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/utils/QrCodesFragmentUtil.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/utils/QrInfoScreenUtil.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/saved_events/SavedEvents.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/saved_events/SavedEventsFragment.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/saved_events/SavedEventsSyncGreenCardsFragment.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/saved_events/SavedEventsViewModel.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/saved_events/items/SavedEventAdapterItem.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/saved_events/items/SavedEventsClearDataAdapterItem.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/saved_events/items/SavedEventsHeaderAdapterItem.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/saved_events/items/SavedEventsNoSavedEventsItem.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/saved_events/items/SavedEventsSectionAdapterItem.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/saved_events/usecases/GetSavedEventsUseCase.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/sync_greencards/SyncGreenCardsViewModel.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/workers/ConfigFetchWorker.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/workers/CredentialRefreshWorker.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/workers/HolderWorkerFactory.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/workers/WorkerManagerUtil.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/YourEventExplanationFragment.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/YourEventsFragment.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/YourEventsFragmentType.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/YourEventsViewModel.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/models/ConflictingEventResult.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/models/RemoteGreenCards.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/models/RemoteNonce.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/models/RemotePrepareIssue.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/models/YourEventsEndState.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/usecases/SaveEventsUseCase.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/CreateInfoLineUtil.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/EventGroupEntityUtil.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/InfoScreenUtil.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/RecoveryInfoScreenUtil.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/RemoteEventHolderUtil.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/RemoteEventStringUtil.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/RemoteEventUtil.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/RemoteProtocol3Util.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/TestInfoScreenUtil.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/VaccinationInfoScreenUtil.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/YourEventsEndStateUtil.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/YourEventsFragmentUtil.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/widgets/YourEventWidget.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/widgets/YourEventWidgetUtil.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/persistence/database/HolderDatabaseSyncer.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/persistence/database/usecases/CreateEuGreenCardsUseCase.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/persistence/database/usecases/DraftEventUseCase.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/persistence/database/usecases/GetRemoteGreenCardsUseCase.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/persistence/database/usecases/RemoveCTBUseCase.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/persistence/database/usecases/RemoveExpiredEventsUseCase.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/persistence/database/usecases/SyncRemoteGreenCardsUseCase.kt delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/persistence/database/usecases/UpdateEventExpirationUseCase.kt delete mode 100644 holder/src/main/res/layout/fragment_main.xml delete mode 100644 holder/src/main/res/navigation/holder_fuzzy_matching.xml delete mode 100644 holder/src/main/res/navigation/holder_nav_graph_main.xml diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/BaseFragment.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/BaseFragment.kt deleted file mode 100644 index 47e553477..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/BaseFragment.kt +++ /dev/null @@ -1,152 +0,0 @@ -package nl.rijksoverheid.ctr.holder - -import androidx.fragment.app.Fragment -import nl.rijksoverheid.ctr.design.fragments.ErrorResultFragment -import nl.rijksoverheid.ctr.design.utils.DialogUtil -import nl.rijksoverheid.ctr.holder.models.MissingOriginErrorResult -import nl.rijksoverheid.ctr.shared.ext.navigateSafety -import nl.rijksoverheid.ctr.shared.factories.ErrorCodeStringFactory -import nl.rijksoverheid.ctr.shared.models.ErrorResult -import nl.rijksoverheid.ctr.shared.models.ErrorResultFragmentData -import nl.rijksoverheid.ctr.shared.models.Flow -import nl.rijksoverheid.ctr.shared.models.NetworkRequestResult -import nl.rijksoverheid.ctr.shared.models.OpenIdErrorResult -import org.koin.android.ext.android.inject - -/** - * BaseFragment that should be used by all fragments that require error handling - */ -abstract class BaseFragment(contentLayoutId: Int) : Fragment(contentLayoutId) { - - protected val errorCodeStringFactory: ErrorCodeStringFactory by inject() - private val dialogUtil: DialogUtil by inject() - - /** - * Function that is also called when a network requests fails and a user presses the "retry" button - */ - abstract fun onButtonClickWithRetryAction() - - /** - * Function that is also called when a network requests fails and a user presses the "close" button - */ - open fun onButtonClickClose() { - } - - open fun onButtonClickWithRetryTitle(): Int { - return R.string.dialog_retry - } - - /** - * Get the current [Flow] for this screen - */ - abstract fun getFlow(): Flow - - fun presentError(errorResult: ErrorResult, customerErrorDescription: String? = null) { - when (errorResult) { - is NetworkRequestResult.Failed.ClientNetworkError -> { - dialogUtil.presentDialog( - context = requireContext(), - title = R.string.dialog_no_internet_connection_title, - message = getString(R.string.dialog_no_internet_connection_description), - positiveButtonText = onButtonClickWithRetryTitle(), - positiveButtonCallback = { - onButtonClickWithRetryAction() - }, - negativeButtonText = R.string.dialog_close, - negativeButtonCallback = this::onButtonClickClose - ) - } - is NetworkRequestResult.Failed.ServerNetworkError -> { - val errorCodeString = errorCodeStringFactory.get( - flow = getFlow(), - errorResults = listOf(errorResult) - ) - - presentError( - data = ErrorResultFragmentData( - title = getString(R.string.dialog_no_internet_connection_title), - description = getString( - R.string.dialog_no_internet_connection_description_errorcode, - errorCodeString - ), - buttonTitle = getString(R.string.back_to_overview), - buttonAction = ErrorResultFragmentData.ButtonAction.Destination(R.id.action_my_overview), - urlData = ErrorResultFragmentData.UrlData( - urlButtonTitle = getString(R.string.error_something_went_wrong_outage_button), - urlButtonUrl = getString(R.string.error_something_went_wrong_outage_button_url) - ) - ) - ) - } - is MissingOriginErrorResult -> { - val errorCodeString = getString( - R.string.holder_event_missingorigin_error_description, - errorCodeStringFactory.get(getFlow(), listOf(errorResult)) - ) - presentError( - data = ErrorResultFragmentData( - title = getString(R.string.rule_engine_no_origin_title), - description = "$customerErrorDescription$errorCodeString", - buttonTitle = getString(R.string.back_to_overview), - buttonAction = ErrorResultFragmentData.ButtonAction.Destination(R.id.action_my_overview) - ) - ) - } - else -> { - val errorCodeString = errorCodeStringFactory.get( - flow = getFlow(), - errorResults = listOf(errorResult) - ) - if (is429HttpError(errorResult) || errorResult is OpenIdErrorResult.ServerBusy) { - // On HTTP 429 or server busy error we make an exception and show a too busy screen - presentError( - data = ErrorResultFragmentData( - title = getString(R.string.error_too_busy_title), - description = getString( - R.string.error_too_busy_description, - errorCodeString - ), - buttonTitle = getString(R.string.back_to_overview), - buttonAction = ErrorResultFragmentData.ButtonAction.Destination(R.id.action_my_overview) - ) - ) - } else { - val errorDescription = customerErrorDescription - ?: if (errorResult is NetworkRequestResult.Failed.CoronaCheckHttpError) { - getString( - R.string.error_something_went_wrong_http_error_description, - errorCodeString - ) - } else { - getString( - R.string.error_something_went_wrong_making_proof_description, - errorCodeString - ) - } - - val data = ErrorResultFragmentData( - title = getString(R.string.error_something_went_wrong_title), - description = errorDescription, - urlData = ErrorResultFragmentData.UrlData( - urlButtonTitle = getString(R.string.error_something_went_wrong_outage_button), - urlButtonUrl = getString(R.string.error_something_went_wrong_outage_button_url) - ), - buttonTitle = getString(R.string.back_to_overview), - buttonAction = ErrorResultFragmentData.ButtonAction.Destination(R.id.action_my_overview) - ) - presentError(data) - } - } - } - } - - private fun is429HttpError(errorResult: ErrorResult) = - errorResult is NetworkRequestResult.Failed.CoronaCheckHttpError && errorResult.e.code() == 429 - - fun presentError(data: ErrorResultFragmentData) { - navigateSafety( - R.id.action_error_result, - ErrorResultFragment.getBundle(data) - ) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/HolderApplication.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/HolderApplication.kt index e59844834..234ae8991 100644 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/HolderApplication.kt +++ b/holder/src/main/java/nl/rijksoverheid/ctr/holder/HolderApplication.kt @@ -1,37 +1,23 @@ package nl.rijksoverheid.ctr.holder -import androidx.work.WorkerFactory import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import nl.rijksoverheid.ctr.api.apiModule import nl.rijksoverheid.ctr.appconfig.appConfigModule -import nl.rijksoverheid.ctr.appconfig.persistence.AppConfigStorageManager import nl.rijksoverheid.ctr.design.designModule -import nl.rijksoverheid.ctr.holder.dashboard.dashboardModule -import nl.rijksoverheid.ctr.holder.fuzzy_matching.fuzzyMatchingModule import nl.rijksoverheid.ctr.holder.modules.appModule -import nl.rijksoverheid.ctr.holder.modules.cardUtilsModule import nl.rijksoverheid.ctr.holder.modules.errorsModule -import nl.rijksoverheid.ctr.holder.modules.eventsUseCasesModule -import nl.rijksoverheid.ctr.holder.modules.greenCardUseCasesModule import nl.rijksoverheid.ctr.holder.modules.holderAppStatusModule -import nl.rijksoverheid.ctr.holder.modules.holderIntroductionModule import nl.rijksoverheid.ctr.holder.modules.holderMobileCoreModule import nl.rijksoverheid.ctr.holder.modules.holderPreferenceModule -import nl.rijksoverheid.ctr.holder.modules.qrsModule import nl.rijksoverheid.ctr.holder.modules.repositoriesModule -import nl.rijksoverheid.ctr.holder.modules.responsesModule -import nl.rijksoverheid.ctr.holder.modules.retrofitModule import nl.rijksoverheid.ctr.holder.modules.storageModule -import nl.rijksoverheid.ctr.holder.modules.testProvidersUseCasesModule import nl.rijksoverheid.ctr.holder.modules.utilsModule import nl.rijksoverheid.ctr.holder.modules.viewModels import nl.rijksoverheid.ctr.introduction.introductionModule import nl.rijksoverheid.ctr.persistence.database.HolderDatabase import nl.rijksoverheid.ctr.persistence.database.entities.WalletEntity -import nl.rijksoverheid.ctr.persistence.database.usecases.RemoveCTBUseCase -import nl.rijksoverheid.ctr.shared.MobileCoreWrapper import nl.rijksoverheid.ctr.shared.SharedApplication import nl.rijksoverheid.ctr.shared.sharedModule import okhttp3.HttpUrl.Companion.toHttpUrl @@ -50,7 +36,6 @@ import org.koin.core.module.Module open class HolderApplication : SharedApplication() { private val holderDatabase: HolderDatabase by inject() - private val remoteCTBUseCase: RemoveCTBUseCase by inject() private val coroutineScope = CoroutineScope(Dispatchers.IO) open fun coroutineScopeBlock(block: suspend () -> Unit) { @@ -59,20 +44,11 @@ open class HolderApplication : SharedApplication() { private val holderModules = listOf( storageModule, - greenCardUseCasesModule, - eventsUseCasesModule, - testProvidersUseCasesModule, utilsModule, viewModels, - cardUtilsModule, repositoriesModule, - qrsModule, appModule, errorsModule(BuildConfig.FLAVOR), - retrofitModule(BuildConfig.BASE_API_URL, BuildConfig.CDN_API_URL), - responsesModule, - fuzzyMatchingModule, - dashboardModule ).toTypedArray() override fun onCreate() { @@ -82,7 +58,6 @@ open class HolderApplication : SharedApplication() { androidContext(this@HolderApplication) modules( *holderModules, - holderIntroductionModule, holderAppStatusModule, apiModule( BuildConfig.BASE_API_URL.toHttpUrl(), @@ -108,7 +83,6 @@ open class HolderApplication : SharedApplication() { ) ) } - remoteCTBUseCase.execute() } } diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/HolderMainActivityViewModel.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/HolderMainActivityViewModel.kt deleted file mode 100644 index 0ab4d48ab..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/HolderMainActivityViewModel.kt +++ /dev/null @@ -1,35 +0,0 @@ -package nl.rijksoverheid.ctr.holder - -import android.os.Bundle -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import androidx.navigation.NavDirections -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch -import nl.rijksoverheid.ctr.shared.livedata.Event - -abstract class HolderMainActivityViewModel : ViewModel() { - val navigateLiveData: LiveData> = MutableLiveData() - val navigateWithBundleLiveData: LiveData>> = MutableLiveData() - abstract fun navigate(navDirections: NavDirections, delayMillis: Long = 0) - - abstract fun navigateWithBundle(actionId: Int, bundle: Bundle) -} - -class HolderMainActivityViewModelImpl : HolderMainActivityViewModel() { - - override fun navigate(navDirections: NavDirections, delayMillis: Long) { - viewModelScope.launch { - delay(delayMillis) - (navigateLiveData as MutableLiveData).postValue(Event(navDirections)) - } - } - - override fun navigateWithBundle(actionId: Int, bundle: Bundle) { - viewModelScope.launch { - (navigateWithBundleLiveData as MutableLiveData).postValue(Event(Pair(actionId, bundle))) - } - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/HolderMainFragment.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/HolderMainFragment.kt deleted file mode 100644 index 4c23f97d9..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/HolderMainFragment.kt +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ - -package nl.rijksoverheid.ctr.holder - -import android.graphics.drawable.Drawable -import android.os.Bundle -import android.view.View -import androidx.appcompat.widget.Toolbar -import androidx.fragment.app.Fragment -import androidx.navigation.NavController -import androidx.navigation.fragment.NavHostFragment -import androidx.navigation.ui.NavigationUI -import androidx.navigation.ui.setupWithNavController -import nl.rijksoverheid.ctr.holder.databinding.FragmentMainBinding -import nl.rijksoverheid.ctr.shared.ext.getNavigationIconView -import nl.rijksoverheid.ctr.shared.utils.Accessibility.makeIndeterminateAccessible -import nl.rijksoverheid.ctr.shared.utils.Accessibility.setAccessibilityFocus - -class HolderMainFragment : Fragment(R.layout.fragment_main) { - - private var _binding: FragmentMainBinding? = null - private val binding get() = _binding!! - private var _navController: NavController? = null - private val navController get() = _navController!! - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - _binding = FragmentMainBinding.bind(view) - - val navHostFragment = - childFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment - _navController = navHostFragment.navController - - val defaultToolbarElevation = resources.getDimension(R.dimen.toolbar_elevation) - navController.addOnDestinationChangedListener { _, destination, _ -> - // loading a new screen should automatically update the accessibility tree so Talkback knows what is on the screen. - binding.toolbar.getNavigationIconView()?.setAccessibilityFocus() - - binding.toolbar.elevation = if (destination.id == R.id.nav_dashboard) { - 0f - } else { - defaultToolbarElevation - } - } - binding.toolbar.setupWithNavController(navController) - - binding.toolbar.setNavigationOnClickListener { - when (navController.currentDestination?.id) { - R.id.nav_your_events -> { - // Trigger custom dispatcher in destination - requireActivity().onBackPressedDispatcher.onBackPressed() - return@setNavigationOnClickListener - } - R.id.nav_fuzzy_matching_onboarding -> { - // Trigger custom dispatcher in destination - requireActivity().onBackPressedDispatcher.onBackPressed() - return@setNavigationOnClickListener - } - } - - NavigationUI.navigateUp(navController, null) - } - } - - fun presentLoading(loading: Boolean) { - binding.loading.makeIndeterminateAccessible( - context = requireContext(), - isLoading = loading - ) - binding.loading.visibility = if (loading) View.VISIBLE else View.GONE - } - - fun getToolbar(): Toolbar { - return binding.toolbar - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } - - fun resetMenuItemListener() { - binding.toolbar.setOnMenuItemClickListener { - NavigationUI.onNavDestinationSelected(it, navController) - } - } -} - -fun Fragment.hideNavigationIcon() { - (parentFragment?.parentFragment as? HolderMainFragment)?.getToolbar()?.navigationIcon = null -} - -fun Fragment.showNavigationIcon(icon: Drawable) { - (parentFragment?.parentFragment as? HolderMainFragment)?.getToolbar()?.navigationIcon = icon -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/HolderApiClient.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/HolderApiClient.kt deleted file mode 100644 index c68ae5706..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/HolderApiClient.kt +++ /dev/null @@ -1,35 +0,0 @@ -package nl.rijksoverheid.ctr.holder.api - -import nl.rijksoverheid.ctr.holder.api.post.GetCouplingData -import nl.rijksoverheid.ctr.holder.api.post.GetCredentialsPostData -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteAccessTokens -import nl.rijksoverheid.ctr.holder.paper_proof.models.RemoteCouplingResponse -import nl.rijksoverheid.ctr.holder.your_events.models.RemoteGreenCards -import nl.rijksoverheid.ctr.holder.your_events.models.RemotePrepareIssue -import retrofit2.http.Body -import retrofit2.http.GET -import retrofit2.http.Header -import retrofit2.http.POST - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -interface HolderApiClient { - @GET("holder/prepare_issue") - suspend fun getPrepareIssue(): RemotePrepareIssue - - @POST("holder/get_credentials") - suspend fun getCredentials( - @Body data: GetCredentialsPostData - ): RemoteGreenCards - - @POST("holder/access_tokens") - suspend fun getAccessTokens(@Header("Authorization") authorization: String): RemoteAccessTokens - - @POST("holder/coupling") - suspend fun getCoupling(@Body data: GetCouplingData): RemoteCouplingResponse -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/HolderApiClientUtil.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/HolderApiClientUtil.kt deleted file mode 100644 index db34a5f5b..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/HolderApiClientUtil.kt +++ /dev/null @@ -1,78 +0,0 @@ -package nl.rijksoverheid.ctr.holder.api - -import android.util.Base64 -import com.appmattus.certificatetransparency.CTLogger -import com.appmattus.certificatetransparency.VerificationResult -import com.appmattus.certificatetransparency.certificateTransparencyTrustManager -import com.appmattus.certificatetransparency.loglist.LogListDataSourceFactory -import java.io.ByteArrayInputStream -import java.security.cert.CertificateFactory -import java.security.cert.X509Certificate -import javax.net.ssl.X509TrustManager -import nl.rijksoverheid.ctr.holder.BuildConfig -import okhttp3.OkHttpClient -import okhttp3.tls.HandshakeCertificates -import retrofit2.Retrofit -import timber.log.Timber - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -interface HolderApiClientUtil { - fun client(certificateBytes: List): HolderApiClient -} - -class HolderApiClientUtilImpl( - private val okHttpClient: OkHttpClient, - private val retrofit: Retrofit -) : HolderApiClientUtil { - - private fun transparentTrustManager(trustManager: X509TrustManager) = - certificateTransparencyTrustManager(trustManager) { - if (BuildConfig.DEBUG) { - setLogger(object : CTLogger { - override fun log(host: String, result: VerificationResult) { - Timber.tag("certificate transparency") - .d("host: $host, verification result: $result") - } - }) - } - - setLogListService(LogListDataSourceFactory.createLogListService( - baseUrl = "https://www.gstatic.com/ct/log_list/v3/" - )) - } - - override fun client(certificateBytes: List): HolderApiClient { - val okHttpClient = okHttpClient - .newBuilder() - .apply { - if (BuildConfig.FEATURE_TEST_PROVIDER_API_CHECKS) { - val handshakeCertificates = HandshakeCertificates.Builder() - .apply { - certificateBytes.forEach { - val base64Decoded = Base64.decode(it, Base64.DEFAULT) - val certificateFactory = CertificateFactory.getInstance("X.509") - val x509Certificate = certificateFactory.generateCertificate( - ByteArrayInputStream(base64Decoded) - ) as X509Certificate - addTrustedCertificate(x509Certificate) - } - } - .build() - - sslSocketFactory( - handshakeCertificates.sslSocketFactory(), - transparentTrustManager(handshakeCertificates.trustManager) - ) - } - }.build() - - return retrofit.newBuilder().client(okHttpClient) - .build().create(HolderApiClient::class.java) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/MijnCnApiClient.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/MijnCnApiClient.kt deleted file mode 100644 index 078df863e..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/MijnCnApiClient.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ - -package nl.rijksoverheid.ctr.holder.api - -import nl.rijksoverheid.ctr.holder.get_events.models.MijnCNTokenResponse -import retrofit2.http.Field -import retrofit2.http.FormUrlEncoded -import retrofit2.http.Headers -import retrofit2.http.POST -import retrofit2.http.Url - -interface MijnCnApiClient { - - @POST - @Headers("Content-Type: application/x-www-form-urlencoded", "Accept: application/json") - @FormUrlEncoded - suspend fun getAccessToken( - @Url url: String, - @Field("code") code: String, - @Field("grant_type") grantType: String, - @Field("redirect_uri") redirectUri: String, - @Field("code_verifier") codeVerifier: String, - @Field("client_id") clientId: String - ): MijnCNTokenResponse -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/OriginTypeJsonAdapter.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/OriginTypeJsonAdapter.kt deleted file mode 100644 index b4141ddf6..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/OriginTypeJsonAdapter.kt +++ /dev/null @@ -1,13 +0,0 @@ -package nl.rijksoverheid.ctr.holder.api - -import com.squareup.moshi.FromJson -import com.squareup.moshi.ToJson -import nl.rijksoverheid.ctr.persistence.database.entities.OriginType - -class OriginTypeJsonAdapter { - @FromJson - fun fromJson(value: String?): OriginType = OriginType.fromTypeString(value ?: error("OriginType not known")) - - @ToJson - fun toJson(value: OriginType): String = value.getTypeString() -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/RemoteConfigApiClient.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/RemoteConfigApiClient.kt deleted file mode 100644 index 019dd8178..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/RemoteConfigApiClient.kt +++ /dev/null @@ -1,11 +0,0 @@ -package nl.rijksoverheid.ctr.holder.api - -import nl.rijksoverheid.ctr.api.signing.http.SignedRequest -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteConfigProviders -import retrofit2.http.GET - -interface RemoteConfigApiClient { - @GET("holder/config_providers") - @SignedRequest - suspend fun getConfigCtp(): RemoteConfigProviders -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/RemoteCouplingStatusJsonAdapter.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/RemoteCouplingStatusJsonAdapter.kt deleted file mode 100644 index b50ab5bb3..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/RemoteCouplingStatusJsonAdapter.kt +++ /dev/null @@ -1,19 +0,0 @@ -package nl.rijksoverheid.ctr.holder.api - -import com.squareup.moshi.FromJson -import com.squareup.moshi.ToJson -import nl.rijksoverheid.ctr.holder.paper_proof.models.RemoteCouplingStatus - -class RemoteCouplingStatusJsonAdapter { - @FromJson - fun fromJson(value: String?): RemoteCouplingStatus = when (value) { - RemoteCouplingStatus.TYPE_EXPIRED -> RemoteCouplingStatus.Expired - RemoteCouplingStatus.TYPE_BLOCKED -> RemoteCouplingStatus.Blocked - RemoteCouplingStatus.TYPE_REJECTED -> RemoteCouplingStatus.Rejected - RemoteCouplingStatus.TYPE_ACCEPTED -> RemoteCouplingStatus.Accepted - else -> RemoteCouplingStatus.Rejected - } - - @ToJson - fun toJson(value: RemoteCouplingStatus): String = value.typeString -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/RemoteTestStatusJsonAdapter.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/RemoteTestStatusJsonAdapter.kt deleted file mode 100644 index cb00c7eab..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/RemoteTestStatusJsonAdapter.kt +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2020 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ -package nl.rijksoverheid.ctr.holder.api - -import com.squareup.moshi.FromJson -import com.squareup.moshi.ToJson -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteProtocol - -class RemoteTestStatusJsonAdapter { - @FromJson - fun fromJson(value: String?): RemoteProtocol.Status = RemoteProtocol.Status.fromValue(value) - - @ToJson - fun toJson(value: RemoteProtocol.Status): String = value.apiStatus -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/TestProviderApiClient.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/TestProviderApiClient.kt deleted file mode 100644 index da190d0a8..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/TestProviderApiClient.kt +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ - -package nl.rijksoverheid.ctr.holder.api - -import nl.rijksoverheid.ctr.api.interceptors.SigningCertificate -import nl.rijksoverheid.ctr.api.signing.http.SignedRequest -import nl.rijksoverheid.ctr.holder.api.models.SignedResponseWithModel -import nl.rijksoverheid.ctr.holder.api.post.GetTestResultPostData -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteProtocol -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteUnomi -import retrofit2.http.Body -import retrofit2.http.Header -import retrofit2.http.POST -import retrofit2.http.Tag -import retrofit2.http.Url - -interface TestProviderApiClient { - @POST - @SignedRequest - suspend fun getTestResult( - @Url url: String, - @Header("Authorization") authorization: String, - @Header("CoronaCheck-Protocol-Version") protocolVersion: String = "3.0", - @Body data: GetTestResultPostData?, - @Tag certificate: SigningCertificate - ): SignedResponseWithModel - - @POST - @SignedRequest - suspend fun getUnomi( - @Url url: String, - @Header("Authorization") authorization: String, - @Header("CoronaCheck-Protocol-Version") protocolVersion: String = "3.0", - @Body params: Map, - @Tag certificate: SigningCertificate - ): SignedResponseWithModel - - @POST - @SignedRequest - suspend fun getEvents( - @Url url: String, - @Header("Authorization") authorization: String, - @Header("CoronaCheck-Protocol-Version") protocolVersion: String = "3.0", - @Body params: Map, - @Tag certificate: SigningCertificate - ): SignedResponseWithModel -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/TestProviderApiClientUtil.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/TestProviderApiClientUtil.kt deleted file mode 100644 index 73d1c1353..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/TestProviderApiClientUtil.kt +++ /dev/null @@ -1,87 +0,0 @@ -package nl.rijksoverheid.ctr.holder.api - -import com.appmattus.certificatetransparency.CTLogger -import com.appmattus.certificatetransparency.VerificationResult -import com.appmattus.certificatetransparency.certificateTransparencyTrustManager -import com.appmattus.certificatetransparency.loglist.LogListDataSourceFactory -import com.squareup.moshi.Moshi -import java.io.ByteArrayInputStream -import java.security.cert.CertificateFactory -import java.security.cert.X509Certificate -import javax.net.ssl.X509TrustManager -import nl.rijksoverheid.ctr.holder.BuildConfig -import okhttp3.OkHttpClient -import okhttp3.tls.HandshakeCertificates -import retrofit2.Retrofit -import retrofit2.converter.moshi.MoshiConverterFactory -import timber.log.Timber - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -interface TestProviderApiClientUtil { - fun client( - tlsCertificateBytes: List, - cmsCertificateBytes: List - ): TestProviderApiClient -} - -class TestProviderApiClientUtilImpl( - private val moshi: Moshi, - private val okHttpClient: OkHttpClient, - private val retrofit: Retrofit -) : TestProviderApiClientUtil { - - private fun transparentTrustManager(trustManager: X509TrustManager) = - certificateTransparencyTrustManager(trustManager) { - if (BuildConfig.DEBUG) { - setLogger(object : CTLogger { - override fun log(host: String, result: VerificationResult) { - Timber.tag("certificate transparency") - .d("host: $host, verification result: $result") - } - }) - } - - setLogListService(LogListDataSourceFactory.createLogListService( - baseUrl = "https://www.gstatic.com/ct/log_list/v3/" - )) - } - - override fun client( - tlsCertificateBytes: List, - cmsCertificateBytes: List - ): TestProviderApiClient { - val okHttpClient = okHttpClient - .newBuilder() - .apply { - if (BuildConfig.FEATURE_TEST_PROVIDER_API_CHECKS) { - val handshakeCertificates = HandshakeCertificates.Builder() - .apply { - val certificateBytes = tlsCertificateBytes + cmsCertificateBytes - certificateBytes.forEach { - val certificateFactory = CertificateFactory.getInstance("X.509") - val x509Certificate = certificateFactory.generateCertificate( - ByteArrayInputStream(it) - ) as X509Certificate - addTrustedCertificate(x509Certificate) - } - } - .build() - - sslSocketFactory( - handshakeCertificates.sslSocketFactory(), - transparentTrustManager(handshakeCertificates.trustManager) - ) - } - }.build() - - return retrofit.newBuilder().client(okHttpClient) - .addConverterFactory(MoshiConverterFactory.create(moshi)) - .build().create(TestProviderApiClient::class.java) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/models/SignedResponseWithModel.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/models/SignedResponseWithModel.kt deleted file mode 100644 index 123a97bc7..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/models/SignedResponseWithModel.kt +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ - -package nl.rijksoverheid.ctr.holder.api.models - -import com.squareup.moshi.JsonClass - -@JsonClass(generateAdapter = true) -class SignedResponseWithModel(val rawResponse: ByteArray, val model: T) diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/post/GetCouplingData.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/post/GetCouplingData.kt deleted file mode 100644 index 343fa79ba..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/post/GetCouplingData.kt +++ /dev/null @@ -1,13 +0,0 @@ -package nl.rijksoverheid.ctr.holder.api.post - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -data class GetCouplingData( - val credential: String, - val couplingCode: String -) diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/post/GetCredentialsPostData.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/post/GetCredentialsPostData.kt deleted file mode 100644 index 9f8195fcd..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/post/GetCredentialsPostData.kt +++ /dev/null @@ -1,15 +0,0 @@ -package nl.rijksoverheid.ctr.holder.api.post - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -data class GetCredentialsPostData( - val stoken: String, - val events: List, - val issueCommitmentMessage: String, - val flows: List -) diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/post/GetTestIsmPostData.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/post/GetTestIsmPostData.kt deleted file mode 100644 index d26d58426..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/post/GetTestIsmPostData.kt +++ /dev/null @@ -1,18 +0,0 @@ -package nl.rijksoverheid.ctr.holder.api.post - -import com.squareup.moshi.Json -import com.squareup.moshi.JsonClass - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -@JsonClass(generateAdapter = true) -data class GetTestIsmPostData( - @Json(name = "stoken") val sToken: String, - val test: String, - val icm: String -) diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/post/GetTestResultPostData.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/post/GetTestResultPostData.kt deleted file mode 100644 index b19523f49..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/post/GetTestResultPostData.kt +++ /dev/null @@ -1,15 +0,0 @@ -package nl.rijksoverheid.ctr.holder.api.post - -import com.squareup.moshi.JsonClass - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -@JsonClass(generateAdapter = true) -data class GetTestResultPostData( - val verificationCode: String -) diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/repositories/CoronaCheckRepository.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/repositories/CoronaCheckRepository.kt deleted file mode 100644 index bfbf02c22..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/repositories/CoronaCheckRepository.kt +++ /dev/null @@ -1,177 +0,0 @@ -package nl.rijksoverheid.ctr.holder.api.repositories - -import android.util.Base64 -import nl.rijksoverheid.ctr.api.factory.NetworkRequestResultFactory -import nl.rijksoverheid.ctr.holder.api.HolderApiClient -import nl.rijksoverheid.ctr.holder.api.HolderApiClientUtil -import nl.rijksoverheid.ctr.holder.api.RemoteConfigApiClient -import nl.rijksoverheid.ctr.holder.api.post.GetCouplingData -import nl.rijksoverheid.ctr.holder.api.post.GetCredentialsPostData -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteAccessTokens -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteConfigProviders -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEventNegativeTest -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEventPositiveTest -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEventVaccination -import nl.rijksoverheid.ctr.holder.models.HolderFlow -import nl.rijksoverheid.ctr.holder.models.HolderStep -import nl.rijksoverheid.ctr.holder.paper_proof.models.RemoteCouplingResponse -import nl.rijksoverheid.ctr.holder.your_events.models.RemoteGreenCards -import nl.rijksoverheid.ctr.holder.your_events.models.RemotePrepareIssue -import nl.rijksoverheid.ctr.persistence.HolderCachedAppConfigUseCase -import nl.rijksoverheid.ctr.shared.models.CoronaCheckErrorResponse -import nl.rijksoverheid.ctr.shared.models.Flow -import nl.rijksoverheid.ctr.shared.models.NetworkRequestResult -import okhttp3.ResponseBody -import okhttp3.ResponseBody.Companion.asResponseBody -import retrofit2.Converter - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ - -interface CoronaCheckRepository { - suspend fun configProviders(useCache: Boolean = true): NetworkRequestResult - suspend fun accessTokens(jwt: String): NetworkRequestResult - suspend fun getGreenCards( - stoken: String, - events: List, - issueCommitmentMessage: String, - flow: Flow - ): NetworkRequestResult - - suspend fun getPrepareIssue(): NetworkRequestResult - suspend fun getCoupling( - credential: String, - couplingCode: String - ): NetworkRequestResult -} - -private const val FUZZY_MATCHING_ERROR = 99790 -private const val VACCINATION_BACKEND_FLOW = "vaccination" -private const val POSITIVE_TEST_BACKEND_FLOW = "positivetest" -private const val NEGATIVE_TEST_BACKEND_FLOW = "negativetest" -private const val REFRESH_BACKEND_FLOW = "refresh" - -open class CoronaCheckRepositoryImpl( - private val cachedAppConfigUseCase: HolderCachedAppConfigUseCase, - private val holderApiClientUtil: HolderApiClientUtil, - private val remoteConfigApiClient: RemoteConfigApiClient, - private val errorResponseBodyConverter: Converter, - private val responseBodyConverter: Converter, - private val networkRequestResultFactory: NetworkRequestResultFactory -) : CoronaCheckRepository { - - private var cachedConfigProvidersResult: NetworkRequestResult? = null - - private fun getHolderApiClient(): HolderApiClient { - val backendTlsCertificates = - cachedAppConfigUseCase.getCachedAppConfig().backendTLSCertificates - val certificateBytes = backendTlsCertificates.map { it.toByteArray() } - return holderApiClientUtil.client(certificateBytes) - } - - override suspend fun configProviders(useCache: Boolean): NetworkRequestResult { - if (useCache) { - cachedConfigProvidersResult?.takeIf { - it is NetworkRequestResult.Success - }?.let { return it } - } - - val result = networkRequestResultFactory.createResult(HolderStep.ConfigProvidersNetworkRequest) { - remoteConfigApiClient.getConfigCtp() - } - cachedConfigProvidersResult = result - return result - } - - override suspend fun accessTokens(jwt: String): NetworkRequestResult { - return networkRequestResultFactory.createResult(HolderStep.AccessTokensNetworkRequest) { - getHolderApiClient().getAccessTokens(authorization = "Bearer $jwt") - } - } - - override suspend fun getGreenCards( - stoken: String, - events: List, - issueCommitmentMessage: String, - flow: Flow - ): NetworkRequestResult { - return networkRequestResultFactory.createResult( - step = HolderStep.GetCredentialsNetworkRequest, - networkCall = { - getHolderApiClient().getCredentials( - data = GetCredentialsPostData( - stoken = stoken, - events = events, - issueCommitmentMessage = Base64.encodeToString( - issueCommitmentMessage.toByteArray(), - Base64.NO_WRAP - ), - flows = when (flow) { - is HolderFlow.Vaccination -> listOf(VACCINATION_BACKEND_FLOW) - is HolderFlow.Recovery -> listOf(POSITIVE_TEST_BACKEND_FLOW) - is HolderFlow.CommercialTest, is HolderFlow.DigidTest -> listOf( - NEGATIVE_TEST_BACKEND_FLOW - ) - is HolderFlow.VaccinationAndPositiveTest -> listOf( - VACCINATION_BACKEND_FLOW, - POSITIVE_TEST_BACKEND_FLOW - ) - is HolderFlow.Refresh -> listOf(REFRESH_BACKEND_FLOW) - is HolderFlow.HkviScanned -> { - // Hkvi is a flow where you scanned a paper qr which holds one event. That event determines the backend flow. - when (flow.remoteProtocol.events?.first()) { - is RemoteEventVaccination -> listOf(VACCINATION_BACKEND_FLOW) - is RemoteEventNegativeTest -> listOf(NEGATIVE_TEST_BACKEND_FLOW) - is RemoteEventPositiveTest -> listOf(POSITIVE_TEST_BACKEND_FLOW) - else -> listOf(REFRESH_BACKEND_FLOW) - } - } - else -> listOf() - } - ) - ) - }, - interceptHttpError = { - it.response()?.errorBody()?.let { errorBody -> - val errorBodyBuffer = errorBody.source().buffer.clone() - errorResponseBodyConverter.convert(errorBody)?.let { coronaErrorResponse -> - if (coronaErrorResponse.code == FUZZY_MATCHING_ERROR) { - val errorBodyClone = errorBodyBuffer.asResponseBody( - errorBody.contentType(), - errorBody.contentLength() - ) - responseBodyConverter.convert(errorBodyClone) - } else { - null - } - } - } - } - ) - } - - override suspend fun getPrepareIssue(): NetworkRequestResult { - return networkRequestResultFactory.createResult(HolderStep.PrepareIssueNetworkRequest) { - getHolderApiClient().getPrepareIssue() - } - } - - override suspend fun getCoupling( - credential: String, - couplingCode: String - ): NetworkRequestResult { - return networkRequestResultFactory.createResult(HolderStep.CouplingNetworkRequest) { - getHolderApiClient().getCoupling( - data = GetCouplingData( - credential = credential, - couplingCode = couplingCode - ) - ) - } - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/repositories/EventProviderRepository.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/repositories/EventProviderRepository.kt deleted file mode 100644 index 3305305dc..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/repositories/EventProviderRepository.kt +++ /dev/null @@ -1,126 +0,0 @@ -package nl.rijksoverheid.ctr.holder.api.repositories - -import nl.rijksoverheid.ctr.api.factory.NetworkRequestResultFactory -import nl.rijksoverheid.ctr.api.interceptors.SigningCertificate -import nl.rijksoverheid.ctr.holder.api.TestProviderApiClient -import nl.rijksoverheid.ctr.holder.api.TestProviderApiClientUtil -import nl.rijksoverheid.ctr.holder.api.models.SignedResponseWithModel -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteOriginType -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteProtocol -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteUnomi -import nl.rijksoverheid.ctr.holder.models.HolderStep -import nl.rijksoverheid.ctr.shared.models.NetworkRequestResult - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -interface EventProviderRepository { - companion object { - /** - * Get filter for backend endpoints - */ - fun getFilter(originType: RemoteOriginType): String { - return when (originType) { - is RemoteOriginType.Vaccination -> { - "vaccination" - } - is RemoteOriginType.Recovery -> { - "positivetest" - } - is RemoteOriginType.Test -> { - "negativetest" - } - } - } - } - - suspend fun getUnomi( - url: String, - token: String, - filter: String, - scope: String?, - signingCertificateBytes: List, - provider: String, - tlsCertificateBytes: List - ): NetworkRequestResult - - suspend fun getEvents( - url: String, - token: String, - signingCertificateBytes: List, - filter: String, - scope: String?, - provider: String, - tlsCertificateBytes: List - ): NetworkRequestResult> -} - -class EventProviderRepositoryImpl( - private val testProviderApiClientUtil: TestProviderApiClientUtil, - private val networkRequestResultFactory: NetworkRequestResultFactory -) : EventProviderRepository { - - private fun getTestProviderApiClient(tlsCertificateBytes: List, cmsCertificateBytes: List): TestProviderApiClient { - return testProviderApiClientUtil.client(tlsCertificateBytes, cmsCertificateBytes) - } - - override suspend fun getUnomi( - url: String, - token: String, - filter: String, - scope: String?, - signingCertificateBytes: List, - provider: String, - tlsCertificateBytes: List - ): NetworkRequestResult { - val params = mutableMapOf() - params["filter"] = filter - scope?.let { - params["scope"] = scope - } - - return networkRequestResultFactory.createResult( - step = HolderStep.UnomiNetworkRequest, - provider = provider - ) { - getTestProviderApiClient(tlsCertificateBytes, signingCertificateBytes).getUnomi( - url = url, - authorization = "Bearer $token", - params = params, - certificate = SigningCertificate(signingCertificateBytes) - ).model - } - } - - override suspend fun getEvents( - url: String, - token: String, - signingCertificateBytes: List, - filter: String, - scope: String?, - provider: String, - tlsCertificateBytes: List - ): NetworkRequestResult> { - val params = mutableMapOf() - params["filter"] = filter - scope?.let { - params["scope"] = scope - } - - return networkRequestResultFactory.createResult( - step = HolderStep.EventNetworkRequest, - provider = provider - ) { - getTestProviderApiClient(tlsCertificateBytes, signingCertificateBytes).getEvents( - url = url, - authorization = "Bearer $token", - params = params, - certificate = SigningCertificate(signingCertificateBytes) - ) - } - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/repositories/TestProviderRepository.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/repositories/TestProviderRepository.kt deleted file mode 100644 index 053219251..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/api/repositories/TestProviderRepository.kt +++ /dev/null @@ -1,81 +0,0 @@ -package nl.rijksoverheid.ctr.holder.api.repositories - -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import nl.rijksoverheid.ctr.api.factory.NetworkRequestResultFactory -import nl.rijksoverheid.ctr.api.interceptors.SigningCertificate -import nl.rijksoverheid.ctr.holder.api.TestProviderApiClient -import nl.rijksoverheid.ctr.holder.api.TestProviderApiClientUtil -import nl.rijksoverheid.ctr.holder.api.models.SignedResponseWithModel -import nl.rijksoverheid.ctr.holder.api.post.GetTestResultPostData -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteProtocol -import nl.rijksoverheid.ctr.holder.models.HolderStep -import nl.rijksoverheid.ctr.shared.models.NetworkRequestResult -import okhttp3.ResponseBody -import retrofit2.Converter - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -interface TestProviderRepository { - suspend fun remoteTestResult( - url: String, - token: String, - provider: String, - verifierCode: String?, - signingCertificateBytes: List, - tlsCertificateBytes: List - ): NetworkRequestResult> -} - -class TestProviderRepositoryImpl( - private val testProviderApiClientUtil: TestProviderApiClientUtil, - private val networkRequestResultFactory: NetworkRequestResultFactory, - private val responseConverter: Converter> -) : TestProviderRepository { - - private fun getTestProviderApiClient(tlsCertificateBytes: List, cmsCertificateBytes: List): TestProviderApiClient { - return testProviderApiClientUtil.client(tlsCertificateBytes, cmsCertificateBytes) - } - - @Suppress("BlockingMethodInNonBlockingContext") - override suspend fun remoteTestResult( - url: String, - token: String, - provider: String, - verifierCode: String?, - signingCertificateBytes: List, - tlsCertificateBytes: List - ): NetworkRequestResult> { - return networkRequestResultFactory.createResult( - step = HolderStep.TestResultNetworkRequest, - provider = provider, - networkCall = { - getTestProviderApiClient(tlsCertificateBytes, signingCertificateBytes).getTestResult( - url = url, - authorization = "Bearer $token", - data = verifierCode?.let { - GetTestResultPostData( - it - ) - }, - certificate = SigningCertificate(signingCertificateBytes) - ) - }, - interceptHttpError = { - val errorBody = it.response()?.errorBody() - if ((it.code() == 401 || it.code() == 403) && errorBody != null) { - withContext(Dispatchers.IO) { - responseConverter.convert(errorBody) - } - } else { - null - } - } - ) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/certificate_created/CertificateCreatedFragment.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/certificate_created/CertificateCreatedFragment.kt deleted file mode 100644 index cc4346e1c..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/certificate_created/CertificateCreatedFragment.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.certificate_created - -import android.os.Bundle -import android.view.View -import androidx.activity.OnBackPressedCallback -import androidx.fragment.app.Fragment -import androidx.navigation.fragment.navArgs -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.databinding.FragmentCertificateCreatedBinding -import nl.rijksoverheid.ctr.shared.ext.findNavControllerSafety - -class CertificateCreatedFragment : - Fragment(R.layout.fragment_certificate_created) { - - private val args: CertificateCreatedFragmentArgs by navArgs() - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - val binding = FragmentCertificateCreatedBinding.bind(view) - binding.bottom.setButtonClick { backToOverview() } - with(args) { - binding.title.text = title - binding.description.setHtmlText( - htmlText = description, - htmlLinksEnabled = true - ) - } - requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, object : - OnBackPressedCallback(true) { - override fun handleOnBackPressed() { - backToOverview() - } - }) - } - - private fun backToOverview() { - findNavControllerSafety()?.popBackStack() - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/choose_proof_type/ChooseProofTypeFragment.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/choose_proof_type/ChooseProofTypeFragment.kt deleted file mode 100644 index a64763567..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/choose_proof_type/ChooseProofTypeFragment.kt +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.choose_proof_type - -import android.os.Bundle -import android.view.View -import androidx.fragment.app.Fragment -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.databinding.FragmentChooseProofTypeBinding -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteOriginType -import nl.rijksoverheid.ctr.holder.ui.create_qr.bind -import nl.rijksoverheid.ctr.holder.usecases.HolderFeatureFlagUseCase -import nl.rijksoverheid.ctr.shared.ext.navigateSafety -import org.koin.android.ext.android.inject - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -class ChooseProofTypeFragment : Fragment(R.layout.fragment_choose_proof_type) { - - private val featureFlagUseCase: HolderFeatureFlagUseCase by inject() - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - val binding = FragmentChooseProofTypeBinding.bind(view) - - binding.negativeTestButton.bind( - R.string.qr_code_type_negative_test_title, - getString(R.string.qr_code_type_negative_test_description) - ) { - if (featureFlagUseCase.getGgdEnabled()) { - navigateSafety(ChooseProofTypeFragmentDirections.actionChooseProvider()) - } else { - navigateSafety(ChooseProofTypeFragmentDirections.actionInputToken()) - } - } - - binding.recoveryButton.bind( - R.string.qr_code_type_recovery_title, - getString(R.string.qr_code_type_recovery_description) - ) { - navigateSafety( - ChooseProofTypeFragmentDirections.actionGetEvents( - originType = RemoteOriginType.Recovery, - toolbarTitle = resources.getString(R.string.choose_provider_toolbar) - ) - ) - } - - binding.vaccinationButton.bind( - R.string.qr_code_type_vaccination_title, - getString(R.string.qr_code_type_vaccination_description) - ) { - navigateSafety( - ChooseProofTypeFragmentDirections.actionGetEvents( - originType = RemoteOriginType.Vaccination, - toolbarTitle = resources.getString(R.string.choose_provider_toolbar) - ) - ) - } - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/choose_provider/ChooseProviderFragment.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/choose_provider/ChooseProviderFragment.kt deleted file mode 100644 index 48c454fb6..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/choose_provider/ChooseProviderFragment.kt +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.choose_provider - -import android.os.Bundle -import android.view.View -import androidx.fragment.app.Fragment -import androidx.navigation.fragment.findNavController -import nl.rijksoverheid.ctr.design.fragments.info.ButtonData -import nl.rijksoverheid.ctr.design.fragments.info.DescriptionData -import nl.rijksoverheid.ctr.design.fragments.info.InfoFragmentData -import nl.rijksoverheid.ctr.design.utils.InfoFragmentUtil -import nl.rijksoverheid.ctr.holder.HolderMainFragment -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.databinding.FragmentChooseProviderBinding -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteOriginType -import nl.rijksoverheid.ctr.holder.ui.create_qr.bind -import nl.rijksoverheid.ctr.shared.ext.navigateSafety -import nl.rijksoverheid.ctr.shared.utils.Accessibility.setAsAccessibilityButton -import org.koin.android.ext.android.inject - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -class ChooseProviderFragment : Fragment(R.layout.fragment_choose_provider) { - - private val infoFragmentUtil: InfoFragmentUtil by inject() - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - val binding = FragmentChooseProviderBinding.bind(view) - - binding.providerCommercial.bind( - R.string.choose_provider_commercial_title, - null - ) { - findNavController().navigate(ChooseProviderFragmentDirections.actionInputToken()) - } - - binding.providerGgd.bind( - R.string.choose_provider_ggd_title, - null - ) { - navigateSafety( - ChooseProviderFragmentDirections.actionGetEvents( - originType = RemoteOriginType.Test, - toolbarTitle = getString(R.string.choose_provider_toolbar) - ) - ) - } - - binding.notYetTested.setOnClickListener { - infoFragmentUtil.presentAsBottomSheet( - childFragmentManager, InfoFragmentData.TitleDescriptionWithButton( - title = getString(R.string.not_yet_tested_title), - descriptionData = DescriptionData(R.string.not_yet_tested_description), - secondaryButtonData = ButtonData.LinkButton( - getString(R.string.not_yet_tested_button), - getString(R.string.url_make_appointment) - ) - ) - ) - } - - binding.providerCommercial.root.setAsAccessibilityButton() - } - - override fun onDestroyView() { - super.onDestroyView() - (parentFragment?.parentFragment as? HolderMainFragment)?.presentLoading(false) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/could_not_create_qr/CouldNotCreateQrFragment.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/could_not_create_qr/CouldNotCreateQrFragment.kt deleted file mode 100644 index e6a2aff94..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/could_not_create_qr/CouldNotCreateQrFragment.kt +++ /dev/null @@ -1,41 +0,0 @@ -package nl.rijksoverheid.ctr.holder.could_not_create_qr - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.fragment.app.Fragment -import androidx.navigation.fragment.findNavController -import androidx.navigation.fragment.navArgs -import nl.rijksoverheid.ctr.holder.databinding.FragmentCouldNotCreateQrBinding - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -class CouldNotCreateQrFragment : Fragment() { - - private val args: CouldNotCreateQrFragmentArgs by navArgs() - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View { - return FragmentCouldNotCreateQrBinding.inflate(inflater, container, false).root - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - val binding = FragmentCouldNotCreateQrBinding.bind(view) - binding.title.text = args.title - binding.description.setHtmlText(args.description, htmlLinksEnabled = true) - binding.bottom.setButtonClick { - findNavController().navigate(CouldNotCreateQrFragmentDirections.actionMyOverview()) - } - binding.bottom.setButtonText(args.buttonTitle) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/DashboardFragment.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/DashboardFragment.kt deleted file mode 100644 index bd7cae9c8..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/DashboardFragment.kt +++ /dev/null @@ -1,318 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.dashboard - -import android.graphics.Typeface -import android.os.Bundle -import android.view.View -import android.widget.TextView -import androidx.core.view.children -import androidx.core.view.isVisible -import androidx.fragment.app.Fragment -import androidx.navigation.fragment.navArgs -import androidx.viewpager2.widget.ViewPager2 -import com.google.android.material.tabs.TabLayout -import com.google.android.material.tabs.TabLayoutMediator -import nl.rijksoverheid.ctr.appconfig.AppConfigViewModel -import nl.rijksoverheid.ctr.appconfig.usecases.ClockDeviationUseCase -import nl.rijksoverheid.ctr.design.R.dimen -import nl.rijksoverheid.ctr.design.menu.MenuViewModel -import nl.rijksoverheid.ctr.design.utils.DialogUtil -import nl.rijksoverheid.ctr.holder.HolderMainFragment -import nl.rijksoverheid.ctr.holder.NavGraphOverviewDirections -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.dashboard.models.DashboardItem -import nl.rijksoverheid.ctr.holder.dashboard.models.DashboardSync -import nl.rijksoverheid.ctr.holder.dashboard.models.DashboardTabItem -import nl.rijksoverheid.ctr.holder.databinding.FragmentDashboardBinding -import nl.rijksoverheid.ctr.holder.fuzzy_matching.MatchingBlobIds -import nl.rijksoverheid.ctr.persistence.PersistenceManager -import nl.rijksoverheid.ctr.persistence.database.DatabaseSyncerResult -import nl.rijksoverheid.ctr.shared.ext.navigateSafety -import nl.rijksoverheid.ctr.shared.livedata.EventObserver -import org.koin.android.ext.android.inject -import org.koin.androidx.viewmodel.ext.android.sharedViewModel -import org.koin.androidx.viewmodel.ext.android.viewModel - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -class DashboardFragment : Fragment(R.layout.fragment_dashboard) { - - private var _binding: FragmentDashboardBinding? = null - private val binding get() = _binding!! - private val dashboardViewModel: DashboardViewModel by viewModel() - private val args: DashboardFragmentArgs by navArgs() - private val dialogUtil: DialogUtil by inject() - private val persistenceManager: PersistenceManager by inject() - private val clockDeviationUseCase: ClockDeviationUseCase by inject() - private val appConfigViewModel: AppConfigViewModel by sharedViewModel() - private val menuViewModel: MenuViewModel by viewModel() - - /** count of amount of tabs visible. When tab amount changes on policy change the adapter items need to be reset */ - private var tabItemsCount = 0 - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - _binding = FragmentDashboardBinding.bind(view) - val adapter = DashboardPagerAdapter( - childFragmentManager, - viewLifecycleOwner.lifecycle, - args.returnUri - ) - - setupViewPager(adapter) - observeServerTimeSynced() - observeItems(adapter) - observeSyncErrors() - observeAppConfig() - observeBottomElevation() - observeMenuItem() - observeDialogs() - pendingDialogs() - } - - private fun observeDialogs() { - dashboardViewModel.showMigrationDialogLiveData.observe( - viewLifecycleOwner, - EventObserver { - dialogUtil.presentDialog( - context = requireContext(), - title = R.string.holder_migrationFlow_deleteDetails_dialog_title, - message = getString(R.string.holder_migrationFlow_deleteDetails_dialog_message), - positiveButtonText = R.string.holder_migrationFlow_deleteDetails_dialog_deleteButton, - negativeButtonText = R.string.holder_migrationFlow_deleteDetails_dialog_retainButton, - positiveButtonCallback = { - dashboardViewModel.deleteMigrationData() - } - ) - }) - } - - private fun pendingDialogs() { - dashboardViewModel.showMigrationDialog() - } - - private fun observeBottomElevation() { - dashboardViewModel.bottomButtonElevationLiveData.observe(viewLifecycleOwner) { elevate -> - binding.bottom.elevation = if (elevate) { - resources.getDimensionPixelSize(dimen.scroll_view_button_elevation).toFloat() - } else { - 0f - } - } - } - - private fun observeMenuItem() { - menuViewModel.menuSectionLiveData.observe(viewLifecycleOwner, EventObserver { - navigateSafety( - DashboardFragmentDirections.actionMenu( - toolbarTitle = getString(R.string.general_menu), - menuSections = it - ) - ) - }) - } - - private fun setupViewPager(adapter: DashboardPagerAdapter) { - binding.viewPager.adapter = adapter - } - - /** - * Whenever the server time is synced we want to refresh our dashboard to check - * if we want to inform the user that the clock is not correct - */ - private fun observeServerTimeSynced() { - clockDeviationUseCase.serverTimeSyncedLiveData.observe(viewLifecycleOwner, EventObserver { - dashboardViewModel.refresh( - dashboardSync = DashboardSync.DisableSync - ) - }) - } - - private fun observeItems(adapter: DashboardPagerAdapter) { - dashboardViewModel.dashboardTabItemsLiveData.observe(viewLifecycleOwner) { dashboardTabItems -> - - val init = adapter.itemCount == 0 - - setupTabs( - binding = binding, - items = dashboardTabItems, - init = init - ) - - // Setup adapter only once - if (init || adapter.itemCount != tabItemsCount) { - tabItemsCount = dashboardTabItems.count() - - adapter.setItems(dashboardTabItems) - - // Default select the item that we had selected last - binding.viewPager.setCurrentItem( - persistenceManager.getSelectedDashboardTab(), - false - ) - - // Register listener so that last selected item is saved - binding.viewPager.registerOnPageChangeCallback(object : - ViewPager2.OnPageChangeCallback() { - override fun onPageSelected(position: Int) { - super.onPageSelected(position) - persistenceManager.setSelectedDashboardTab(position) - } - }) - } - - binding.addQrButton.isVisible = dashboardTabItems.any { dashboardTabItem -> - dashboardTabItem.items.any { it is DashboardItem.AddQrButtonItem } - } - binding.addQrButton.setOnClickListener { - navigateSafety( - DashboardFragmentDirections.actionChooseProofType() - ) - } - } - } - - private fun observeSyncErrors() { - dashboardViewModel.databaseSyncerResultLiveData.observe(viewLifecycleOwner, - EventObserver { - when (it) { - is DatabaseSyncerResult.Failed -> { - if (it is DatabaseSyncerResult.Failed.NetworkError && it.hasGreenCardsWithoutCredentials) { - dialogUtil.presentDialog( - context = requireContext(), - title = R.string.dialog_title_no_internet, - message = getString(R.string.dialog_credentials_expired_no_internet), - positiveButtonText = R.string.app_status_internet_required_action, - positiveButtonCallback = { - refresh( - dashboardSync = DashboardSync.ForceSync - ) - }, - negativeButtonText = R.string.dialog_close - ) - } else if (it !is DatabaseSyncerResult.Failed.ServerError) { - dialogUtil.presentDialog( - context = requireContext(), - title = R.string.dialog_title_no_internet, - message = getString(R.string.dialog_update_credentials_no_internet), - positiveButtonText = R.string.app_status_internet_required_action, - positiveButtonCallback = { - refresh( - dashboardSync = DashboardSync.ForceSync - ) - }, - negativeButtonText = R.string.dialog_close - ) - } - } - is DatabaseSyncerResult.FuzzyMatchingError -> { - navigateSafety( - NavGraphOverviewDirections.actionFuzzyMatching( - MatchingBlobIds(it.matchingBlobIds) - ) - ) - } - is DatabaseSyncerResult.Success -> { - // no extra action needed - } - } - } - ) - } - - private fun observeAppConfig() { - appConfigViewModel.appStatusLiveData.observe(viewLifecycleOwner) { - dashboardViewModel.refresh() - } - } - - private fun refresh(dashboardSync: DashboardSync = DashboardSync.CheckSync) { - dashboardViewModel.refresh(dashboardSync) - } - - private fun setupTabs( - binding: FragmentDashboardBinding, - items: List, - init: Boolean - ) { - if (items.size == 1) { - binding.tabs.visibility = View.GONE - binding.tabsSeparator.visibility = View.GONE - } else { - binding.tabs.visibility = View.VISIBLE - binding.tabsSeparator.visibility = View.VISIBLE - - if (init) { - TabLayoutMediator(binding.tabs, binding.viewPager) { tab, position -> - tab.view.setOnLongClickListener { - true - } - tab.text = getString(items[position].title) - }.attach() - - binding.tabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener { - override fun onTabSelected(tab: TabLayout.Tab) { - val textView = tab.view.children.find { it is TextView } as? TextView - textView?.setTypeface(null, Typeface.BOLD) - } - - override fun onTabUnselected(tab: TabLayout.Tab) { - val textView = tab.view.children.find { it is TextView } as? TextView - textView?.setTypeface(null, Typeface.NORMAL) - } - - override fun onTabReselected(tab: TabLayout.Tab) { - val textView = tab.view.children.find { it is TextView } as? TextView - textView?.setTypeface(null, Typeface.BOLD) - } - }) - - // Call selectTab so that styling get's picked up on launch - binding.tabs.selectTab(binding.tabs.getTabAt(0)) - } - } - } - - override fun onPause() { - super.onPause() - - // Do this check because our screenshot fragment tests run in it's own test activity - if (parentFragment != null && requireParentFragment().parentFragment != null) { - (requireParentFragment().requireParentFragment() as HolderMainFragment).getToolbar().menu.clear() - } - } - - override fun onResume() { - super.onResume() - refresh() - - getToolbar().let { toolbar -> - if (toolbar?.menu?.size() == 0) { - toolbar.apply { - inflateMenu(R.menu.menu_toolbar) - menu.findItem(R.id.action_menu).actionView?.setOnClickListener { - menuViewModel.click(requireContext()) - } - } - } - } - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } - - private fun getToolbar() = (parentFragment?.parentFragment as HolderMainFragment?)?.getToolbar() -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/DashboardModule.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/DashboardModule.kt deleted file mode 100644 index b16215138..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/DashboardModule.kt +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.dashboard - -import nl.rijksoverheid.ctr.holder.dashboard.datamappers.DashboardTabsItemDataMapper -import nl.rijksoverheid.ctr.holder.dashboard.datamappers.DashboardTabsItemDataMapperImpl -import org.koin.dsl.module - -val dashboardModule = module { - factory { DashboardTabsItemDataMapperImpl(get()) } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/DashboardPageFragment.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/DashboardPageFragment.kt deleted file mode 100644 index 1460f2c0b..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/DashboardPageFragment.kt +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.dashboard - -import android.os.Bundle -import android.view.View -import androidx.fragment.app.Fragment -import androidx.recyclerview.widget.RecyclerView -import com.xwray.groupie.GroupAdapter -import com.xwray.groupie.GroupieViewHolder -import com.xwray.groupie.Section -import com.xwray.groupie.viewbinding.BindableItem -import nl.rijksoverheid.ctr.design.utils.DialogUtil -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.dashboard.items.DashboardAddQrCardAdapterItem -import nl.rijksoverheid.ctr.holder.dashboard.items.DashboardGreenCardAdapterItem -import nl.rijksoverheid.ctr.holder.dashboard.items.DashboardGreenCardPlaceHolderAdapterItem -import nl.rijksoverheid.ctr.holder.dashboard.items.DashboardHeaderAdapterItem -import nl.rijksoverheid.ctr.holder.dashboard.items.DashboardInfoCardAdapterItem -import nl.rijksoverheid.ctr.holder.dashboard.models.DashboardItem -import nl.rijksoverheid.ctr.holder.dashboard.models.DashboardSync -import nl.rijksoverheid.ctr.holder.dashboard.usecases.ShowBlockedEventsDialogResult -import nl.rijksoverheid.ctr.holder.dashboard.util.CardItemUtil -import nl.rijksoverheid.ctr.holder.dashboard.util.DashboardPageInfoItemHandlerUtil -import nl.rijksoverheid.ctr.holder.dashboard.util.RemovedEventsBottomSheetUtil -import nl.rijksoverheid.ctr.holder.databinding.FragmentDashboardPageBinding -import nl.rijksoverheid.ctr.holder.qrcodes.models.QrCodeFragmentData -import nl.rijksoverheid.ctr.persistence.database.entities.GreenCardType -import nl.rijksoverheid.ctr.shared.ext.findNavControllerSafety -import nl.rijksoverheid.ctr.shared.ext.getParcelableCompat -import nl.rijksoverheid.ctr.shared.ext.navigateSafety -import nl.rijksoverheid.ctr.shared.livedata.EventObserver -import org.koin.android.ext.android.inject -import org.koin.androidx.viewmodel.ext.android.sharedViewModel - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -class DashboardPageFragment : Fragment(R.layout.fragment_dashboard_page) { - - companion object { - const val EXTRA_GREEN_CARD_TYPE = "GREEN_CARD_TYPE" - const val EXTRA_RETURN_URI = "RETURN_URI" - - fun getInstance( - greenCardType: GreenCardType, - returnUri: String? - ): DashboardPageFragment { - val fragment = DashboardPageFragment() - val arguments = Bundle() - arguments.putParcelable(EXTRA_GREEN_CARD_TYPE, greenCardType) - arguments.putString(EXTRA_RETURN_URI, returnUri) - fragment.arguments = arguments - return fragment - } - } - - private val dashboardPageInfoItemHandlerUtil: DashboardPageInfoItemHandlerUtil by inject() - private val removedEventsBottomSheetUtil: RemovedEventsBottomSheetUtil by inject() - private val cardItemUtil: CardItemUtil by inject() - private val dialogUtil: DialogUtil by inject() - val dashboardViewModel: DashboardViewModel by sharedViewModel(owner = { - requireParentFragment() - }) - val section = Section() - private val greenCardType: GreenCardType by lazy { - arguments?.getParcelableCompat( - EXTRA_GREEN_CARD_TYPE - ) ?: error("EXTRA_GREEN_CARD_TYPE should not be null") - } - - override fun onResume() { - super.onResume() - view?.findViewById(R.id.recyclerView)?.let { - dashboardViewModel.scrollUpdate(it.canScrollVertically(RecyclerView.SCROLL_AXIS_VERTICAL), greenCardType) - } - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - val binding = FragmentDashboardPageBinding.bind(view) - initRecyclerView(binding) - observeItem() - observeShowBlockedEventsDialog() - } - - private fun observeItem() { - dashboardViewModel.dashboardTabItemsLiveData.observe(viewLifecycleOwner) { - setItems( - myDashboardItems = it.firstOrNull { items -> items.greenCardType == greenCardType }?.items - ?: listOf() - ) - } - } - - private fun observeShowBlockedEventsDialog() { - dashboardViewModel.showBlockedEventsDialogLiveData.observe( - viewLifecycleOwner, - EventObserver { result -> - when (result) { - is ShowBlockedEventsDialogResult.Show -> { - dialogUtil.presentDialog( - context = requireContext(), - title = R.string.holder_invaliddetailsremoved_alert_title, - message = getString(R.string.holder_invaliddetailsremoved_alert_body), - positiveButtonText = R.string.holder_invaliddetailsremoved_alert_button_close, - positiveButtonCallback = { }, - negativeButtonText = R.string.holder_invaliddetailsremoved_alert_button_moreinfo, - negativeButtonCallback = { removedEventsBottomSheetUtil.presentBlockedEvents(this, result.blockedEvents) } - ) - } - ShowBlockedEventsDialogResult.None -> { - /* nothing */ - } - } - } - ) - } - - private fun initRecyclerView(binding: FragmentDashboardPageBinding) { - val adapter = GroupAdapter().also { - it.add(section) - } - binding.recyclerView.adapter = adapter - binding.recyclerView.itemAnimator = null - binding.recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() { - override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { - super.onScrolled(recyclerView, dx, dy) - dashboardViewModel.scrollUpdate( - canScrollVertically = recyclerView.canScrollVertically(RecyclerView.SCROLL_AXIS_VERTICAL), - greenCardType = greenCardType - ) - } - }) - } - - private fun setItems( - myDashboardItems: List - ) { - val adapterItems = mutableListOf>() - myDashboardItems.forEach { dashboardItem -> - when (dashboardItem) { - is DashboardItem.HeaderItem -> addHeader(adapterItems, dashboardItem) - is DashboardItem.PlaceholderCardItem -> addPlaceHolder(adapterItems, dashboardItem) - is DashboardItem.CardsItem -> addCards(adapterItems, dashboardItem) - is DashboardItem.AddQrButtonItem -> { - // Handled by MyOverviewTabsFragment - } - is DashboardItem.InfoItem -> addInfoCard(adapterItems, dashboardItem) - is DashboardItem.AddQrCardItem -> addAddQrCardItem(adapterItems) - } - } - - section.update(adapterItems) - } - - private fun addAddQrCardItem(adapterItems: MutableList>) { - adapterItems.add( - DashboardAddQrCardAdapterItem( - onButtonClick = { - findNavControllerSafety()?.navigate(DashboardPageFragmentDirections.actionChooseProofType()) - }) - ) - } - - private fun addInfoCard( - adapterItems: MutableList>, - dashboardItem: DashboardItem.InfoItem - ) { - adapterItems.add(DashboardInfoCardAdapterItem( - infoItem = dashboardItem, - onButtonClick = { - dashboardPageInfoItemHandlerUtil.handleButtonClick(this, it) - }, - onDismiss = { infoCardItem, infoItem -> - dashboardPageInfoItemHandlerUtil.handleDismiss( - this, - infoCardItem, - infoItem - ) - } - )) - } - - private fun addCards( - adapterItems: MutableList>, - dashboardItem: DashboardItem.CardsItem - ) { - adapterItems.add( - DashboardGreenCardAdapterItem( - cards = dashboardItem.cards, - onButtonClick = { cardItem, credentialsWithExpirationTime -> - navigateSafety( - DashboardPageFragmentDirections.actionQrCode( - toolbarTitle = when (cardItem.greenCard.greenCardEntity.type) { - is GreenCardType.Eu -> { - getString(R.string.my_overview_test_result_international_title) - } - }, data = QrCodeFragmentData( - shouldDisclose = cardItemUtil.shouldDisclose(cardItem), - credentialsWithExpirationTime = credentialsWithExpirationTime, - type = cardItem.greenCard.greenCardEntity.type, - originType = cardItem.greenCard.origins.first().type - ), returnUri = arguments?.getString(EXTRA_RETURN_URI) - ) - ) - }, - onRetryClick = { - dashboardViewModel.refresh( - dashboardSync = DashboardSync.ForceSync - ) - }, - onCountDownFinished = { - dashboardViewModel.refresh() - } - ) - ) - } - - private fun addPlaceHolder( - adapterItems: MutableList>, - dashboardItem: DashboardItem.PlaceholderCardItem - ) { - adapterItems.add( - DashboardGreenCardPlaceHolderAdapterItem( - greenCardType = dashboardItem.greenCardType - ) - ) - } - - private fun addHeader( - adapterItems: MutableList>, - dashboardItem: DashboardItem.HeaderItem - ) { - adapterItems.add( - DashboardHeaderAdapterItem( - text = dashboardItem.text, - buttonInfo = dashboardItem.buttonInfo - ) - ) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/DashboardPagerAdapter.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/DashboardPagerAdapter.kt deleted file mode 100644 index 0c27a4a8e..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/DashboardPagerAdapter.kt +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.dashboard - -import androidx.fragment.app.Fragment -import androidx.fragment.app.FragmentManager -import androidx.lifecycle.Lifecycle -import androidx.viewpager2.adapter.FragmentStateAdapter -import nl.rijksoverheid.ctr.holder.dashboard.models.DashboardTabItem - -/** - * viewpager adapter to house green card overviews for domestic and European. - * - * @param[fragment] Tabs fragment with viewpager where the overviews are nested within. - * @param[returnToExternalAppUri] Uri used to return to external app from which it was deep linked from. - */ -class DashboardPagerAdapter( - fragmentManager: FragmentManager, - lifecycle: Lifecycle, - private val returnToExternalAppUri: String? -) : - FragmentStateAdapter(fragmentManager, lifecycle) { - - private val items: List = mutableListOf() - - fun setItems(items: List) { - (this.items as MutableList).clear() - this.items.addAll(items) - notifyDataSetChanged() - } - - override fun getItemCount(): Int = items.size - - override fun createFragment(position: Int): Fragment { - return DashboardPageFragment.getInstance( - greenCardType = items[position].greenCardType, - returnUri = returnToExternalAppUri - ) - } - - override fun getItemId(position: Int): Long { - return items[position].title.toLong() - } - - override fun containsItem(itemId: Long): Boolean = items.any { it.title.toLong() == itemId } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/DashboardViewModel.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/DashboardViewModel.kt deleted file mode 100644 index 38a399bde..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/DashboardViewModel.kt +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.dashboard - -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import java.time.OffsetDateTime -import java.util.concurrent.TimeUnit -import kotlinx.coroutines.launch -import nl.rijksoverheid.ctr.dashboard.usecases.RemoveExpiredGreenCardsUseCase -import nl.rijksoverheid.ctr.holder.BuildConfig -import nl.rijksoverheid.ctr.holder.dashboard.datamappers.DashboardTabsItemDataMapper -import nl.rijksoverheid.ctr.holder.dashboard.models.DashboardItem -import nl.rijksoverheid.ctr.holder.dashboard.models.DashboardSync -import nl.rijksoverheid.ctr.holder.dashboard.models.DashboardTabItem -import nl.rijksoverheid.ctr.holder.dashboard.usecases.GetDashboardItemsUseCase -import nl.rijksoverheid.ctr.holder.dashboard.usecases.ShowBlockedEventsDialogResult -import nl.rijksoverheid.ctr.holder.dashboard.usecases.ShowBlockedEventsDialogUseCase -import nl.rijksoverheid.ctr.holder.dashboard.util.GreenCardRefreshUtil -import nl.rijksoverheid.ctr.holder.dashboard.util.GreenCardUtil -import nl.rijksoverheid.ctr.holder.models.HolderFlow -import nl.rijksoverheid.ctr.holder.usecases.HolderFeatureFlagUseCase -import nl.rijksoverheid.ctr.persistence.PersistenceManager -import nl.rijksoverheid.ctr.persistence.database.DatabaseSyncerResult -import nl.rijksoverheid.ctr.persistence.database.HolderDatabase -import nl.rijksoverheid.ctr.persistence.database.HolderDatabaseSyncer -import nl.rijksoverheid.ctr.persistence.database.entities.EventGroupEntity -import nl.rijksoverheid.ctr.persistence.database.entities.GreenCardType -import nl.rijksoverheid.ctr.persistence.database.entities.OriginEntity -import nl.rijksoverheid.ctr.persistence.database.entities.RemovedEventReason -import nl.rijksoverheid.ctr.persistence.database.models.GreenCard -import nl.rijksoverheid.ctr.persistence.database.usecases.DraftEventUseCase -import nl.rijksoverheid.ctr.persistence.database.usecases.RemoveExpiredEventsUseCase -import nl.rijksoverheid.ctr.shared.livedata.Event - -abstract class DashboardViewModel : ViewModel() { - val dashboardTabItemsLiveData: LiveData> = MutableLiveData() - val databaseSyncerResultLiveData: LiveData> = MutableLiveData() - val showBlockedEventsDialogLiveData: LiveData> = - MutableLiveData() - val bottomButtonElevationLiveData: LiveData = MutableLiveData() - val showMigrationDialogLiveData: LiveData> = MutableLiveData() - - abstract fun refresh(dashboardSync: DashboardSync = DashboardSync.CheckSync) - abstract fun removeOrigin(originEntity: OriginEntity) - abstract fun dismissBlockedEventsInfo() - abstract fun dismissFuzzyMatchedEventsInfo() - - /** - * Post scroll updates from recyclerview scrolls and - * when a recyclerview becomes visible again in case of multiple active tabs - * When the current recyclerview can scroll more, we add an elevation to the bottom - * component to indicate the user he can scroll more - * @param canScrollVertically if reached end of scrolling - * @param greenCardType which greencard's type recyclerview interacting with - */ - abstract fun scrollUpdate(canScrollVertically: Boolean, greenCardType: GreenCardType) - abstract fun showMigrationDialog() - abstract fun deleteMigrationData() - - companion object { - val RETRY_FAILED_REQUEST_AFTER_SECONDS = - if (BuildConfig.FLAVOR == "acc") TimeUnit.SECONDS.toSeconds(10) else TimeUnit.MINUTES.toSeconds( - 10 - ) - } -} - -class DashboardViewModelImpl( - private val holderDatabase: HolderDatabase, - private val greenCardUtil: GreenCardUtil, - private val getDashboardItemsUseCase: GetDashboardItemsUseCase, - private val greenCardRefreshUtil: GreenCardRefreshUtil, - private val holderDatabaseSyncer: HolderDatabaseSyncer, - private val persistenceManager: PersistenceManager, - private val removeExpiredGreenCardsUseCase: RemoveExpiredGreenCardsUseCase, - private val dashboardTabsItemDataMapper: DashboardTabsItemDataMapper, - private val removeExpiredEventsUseCase: RemoveExpiredEventsUseCase, - private val draftEventUseCase: DraftEventUseCase, - private val featureFlagUseCase: HolderFeatureFlagUseCase, - private val showBlockedEventsDialogUseCase: ShowBlockedEventsDialogUseCase -) : DashboardViewModel() { - - /** - * Refreshing of database happens every 60 seconds - */ - override fun refresh(dashboardSync: DashboardSync) { - if (loading()) { - return - } - viewModelScope.launch { - refreshCredentials(dashboardSync) - } - } - - private fun loading(): Boolean { - val cardItems = dashboardTabItemsLiveData.value?.flatMap { it.items } - ?.filterIsInstance() ?: return false - return cardItems.flatMap { it.cards } - .any { it.credentialState is DashboardItem.CardsItem.CredentialState.LoadingCredential } - } - - private suspend fun refreshCredentials(dashboardSync: DashboardSync) { - val previousSyncResult = databaseSyncerResultLiveData.value?.peekContent() - - // Check if we need to load new credentials - val shouldLoadNewCredentials = when (dashboardSync) { - is DashboardSync.ForceSync -> { - // Load new credentials if we force it. For example on a retry button click - true - } - is DashboardSync.DisableSync -> { - // Never load new credentials when we don't want to. For example if we are checking to show the clock skew banner - false - } - is DashboardSync.CheckSync -> { - // Load new credentials if no previous refresh has been executed and we should refresh because a credentials for a green card expired - val shouldRefreshCredentials = greenCardRefreshUtil.shouldRefresh() - - // Load new credentials if we the previous request failed more than once and more than x minutes ago - val shouldRetryFailedRequest = - previousSyncResult is DatabaseSyncerResult.Failed.ServerError.MultipleTimes && OffsetDateTime.now() - .isAfter( - previousSyncResult.failedAt.plusSeconds( - RETRY_FAILED_REQUEST_AFTER_SECONDS - ) - ) - - // Do the actual checks - (shouldRefreshCredentials || shouldRetryFailedRequest) && !featureFlagUseCase.isInArchiveMode() - } - } - - val allGreenCards = greenCardUtil.getAllGreenCards() - val allEventGroupEntities = holderDatabase.eventGroupDao().getAll() - - removeExpiredGreenCardsUseCase.execute( - allGreenCards = allGreenCards - ) - - refreshDashboardTabItems( - allGreenCards = allGreenCards, - databaseSyncerResult = databaseSyncerResultLiveData.value?.peekContent() - ?: DatabaseSyncerResult.Success(listOf()), - isLoadingNewCredentials = shouldLoadNewCredentials, - allEventGroupEntities = allEventGroupEntities - ) - - val databaseSyncerResult = holderDatabaseSyncer.sync( - syncWithRemote = shouldLoadNewCredentials, - previousSyncResult = previousSyncResult, - flow = HolderFlow.Refresh - ) - - if (databaseSyncerResult is DatabaseSyncerResult.Success) { - val result = showBlockedEventsDialogUseCase.execute( - blockedRemoteEvents = databaseSyncerResult.blockedEvents - ) - (showBlockedEventsDialogLiveData as MutableLiveData).postValue(Event(result)) - } - - (databaseSyncerResultLiveData as MutableLiveData).value = Event(databaseSyncerResult) - - // If we loaded new credentials, we want to update our items again - if (shouldLoadNewCredentials) { - refreshDashboardTabItems( - allGreenCards = greenCardUtil.getAllGreenCards(), - allEventGroupEntities = holderDatabase.eventGroupDao().getAll(), - databaseSyncerResult = databaseSyncerResult, - isLoadingNewCredentials = false - ) - } - - draftEventUseCase.remove() - - removeExpiredEventsUseCase.execute( - events = allEventGroupEntities - ) - } - - /** - * Remove the origin from a green card. - */ - override fun removeOrigin(originEntity: OriginEntity) { - viewModelScope.launch { - holderDatabase.originDao().delete(originEntity) - } - } - - private suspend fun refreshDashboardTabItems( - allEventGroupEntities: List, - allGreenCards: List, - databaseSyncerResult: DatabaseSyncerResult, - isLoadingNewCredentials: Boolean - ) { - val items = getDashboardItemsUseCase.getItems( - allGreenCards = allGreenCards, - databaseSyncerResult = databaseSyncerResult, - isLoadingNewCredentials = isLoadingNewCredentials, - allEventGroupEntities = allEventGroupEntities - ) - - val tabItems = dashboardTabsItemDataMapper.transform( - dashboardItems = items - ) - - (dashboardTabItemsLiveData as MutableLiveData>).postValue( - tabItems - ) - } - - override fun dismissBlockedEventsInfo() { - viewModelScope.launch { - holderDatabase.removedEventDao().deleteAll(reason = RemovedEventReason.Blocked) - } - } - - override fun dismissFuzzyMatchedEventsInfo() { - viewModelScope.launch { - holderDatabase.removedEventDao().deleteAll(reason = RemovedEventReason.FuzzyMatched) - } - } - - override fun scrollUpdate(canScrollVertically: Boolean, greenCardType: GreenCardType) { - val currentTab = persistenceManager.getSelectedDashboardTab() - val tabItems = dashboardTabItemsLiveData.value - val currentTabItem = tabItems?.getOrNull(currentTab) ?: return - - if (currentTabItem.greenCardType == greenCardType) { - (bottomButtonElevationLiveData as MutableLiveData).value = canScrollVertically - } - } - - override fun showMigrationDialog() { - if (persistenceManager.getShowMigrationDialog()) { - persistenceManager.setShowMigrationDialog(false) - (showMigrationDialogLiveData as MutableLiveData).postValue(Event(Unit)) - } - } - - override fun deleteMigrationData() { - viewModelScope.launch { - holderDatabase.eventGroupDao().deleteAll() - holderDatabase.greenCardDao().deleteAll() - holderDatabase.removedEventDao().deleteAll() - refresh(DashboardSync.ForceSync) - } - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/datamappers/DashboardTabsItemDataMapper.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/datamappers/DashboardTabsItemDataMapper.kt deleted file mode 100644 index b27d54d00..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/datamappers/DashboardTabsItemDataMapper.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.dashboard.datamappers - -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.dashboard.models.DashboardItems -import nl.rijksoverheid.ctr.holder.dashboard.models.DashboardTabItem -import nl.rijksoverheid.ctr.persistence.HolderCachedAppConfigUseCase -import nl.rijksoverheid.ctr.persistence.database.entities.GreenCardType - -interface DashboardTabsItemDataMapper { - suspend fun transform(dashboardItems: DashboardItems): List -} - -class DashboardTabsItemDataMapperImpl( - private val cachedAppConfigUseCase: HolderCachedAppConfigUseCase -) : DashboardTabsItemDataMapper { - - override suspend fun transform(dashboardItems: DashboardItems): List { - return withContext(Dispatchers.IO) { - val tabItems = mutableListOf() - - val internationalItem = DashboardTabItem( - title = R.string.travel_button_europe, - greenCardType = GreenCardType.Eu, - items = dashboardItems.internationalItems - ) - tabItems.add(internationalItem) - - tabItems - } - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/items/DashboardAddQrCardAdapterItem.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/items/DashboardAddQrCardAdapterItem.kt deleted file mode 100644 index 032d04339..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/items/DashboardAddQrCardAdapterItem.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.dashboard.items - -import android.view.View -import com.xwray.groupie.viewbinding.BindableItem -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.databinding.AdapterItemDashboardAddQrBinding -import org.koin.core.component.KoinComponent - -class DashboardAddQrCardAdapterItem( - private val onButtonClick: () -> Unit -) : BindableItem(R.layout.adapter_item_dashboard_add_qr.toLong()), - KoinComponent { - - override fun bind(viewBinding: AdapterItemDashboardAddQrBinding, position: Int) { - viewBinding.text.setOnClickListener { onButtonClick.invoke() } - } - - override fun getLayout(): Int = R.layout.adapter_item_dashboard_add_qr - - override fun initializeViewBinding(view: View): AdapterItemDashboardAddQrBinding { - return AdapterItemDashboardAddQrBinding.bind(view) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/items/DashboardGreenCardAdapterItem.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/items/DashboardGreenCardAdapterItem.kt deleted file mode 100644 index 99f2426f0..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/items/DashboardGreenCardAdapterItem.kt +++ /dev/null @@ -1,249 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.dashboard.items - -import android.view.View -import android.view.ViewGroup -import androidx.core.content.ContextCompat -import androidx.core.view.ViewCompat -import com.xwray.groupie.viewbinding.BindableItem -import java.time.Clock -import java.time.OffsetDateTime -import nl.rijksoverheid.ctr.appconfig.usecases.CachedAppConfigUseCase -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.dashboard.models.DashboardItem -import nl.rijksoverheid.ctr.holder.dashboard.models.DashboardItem.CardsItem.CredentialState.HasCredential -import nl.rijksoverheid.ctr.holder.dashboard.models.GreenCardEnabledState -import nl.rijksoverheid.ctr.holder.dashboard.util.OriginState -import nl.rijksoverheid.ctr.holder.databinding.AdapterItemDashboardGreenCardBinding -import nl.rijksoverheid.ctr.holder.usecases.HolderFeatureFlagUseCase -import nl.rijksoverheid.ctr.persistence.database.DatabaseSyncerResult -import nl.rijksoverheid.ctr.persistence.database.entities.GreenCardType -import nl.rijksoverheid.ctr.persistence.database.models.GreenCard -import org.koin.core.component.KoinComponent -import org.koin.core.component.inject - -data class AdapterCard( - val greenCard: GreenCard, - val originStates: List -) - -class DashboardGreenCardAdapterItem( - private val cards: List, - private val onButtonClick: (cardItem: DashboardItem.CardsItem.CardItem, credentials: List>) -> Unit, - private val onRetryClick: () -> Unit = {}, - private val onCountDownFinished: () -> Unit = {} -) : - BindableItem(R.layout.adapter_item_dashboard_green_card.toLong()), - KoinComponent { - - private val dashboardGreenCardAdapterItemUtil: DashboardGreenCardAdapterItemUtil by inject() - private val dashboardGreenCardAdapterItemExpiryUtil: DashboardGreenCardAdapterItemExpiryUtil by inject() - private val cachedAppConfigUseCase: CachedAppConfigUseCase by inject() - private val clock: Clock by inject() - private val featureFlagUseCase: HolderFeatureFlagUseCase by inject() - - private val runnable = Runnable { - notifyChanged() - } - - private fun countdown(viewBinding: AdapterItemDashboardGreenCardBinding) { - val (expireDate, type) = cards.flatMap { it.originStates } - .map { Pair(it.origin.expirationTime, it.origin.type) } - .maxByOrNull { it.first } ?: return - - val expireCountDown = - dashboardGreenCardAdapterItemExpiryUtil.getExpireCountdown(expireDate, type) - - if (expireCountDown is DashboardGreenCardAdapterItemExpiryUtil.ExpireCountDown.Show) { - if (expireCountDown.expired()) { - onCountDownFinished() - } else { - viewBinding.expiresIn.postDelayed(runnable, 1000) - } - } - } - - override fun bind(viewBinding: AdapterItemDashboardGreenCardBinding, position: Int) { - applyStyling(viewBinding = viewBinding) - setContent(viewBinding = viewBinding) - initButton( - viewBinding = viewBinding, - card = cards.first() - ) - accessibility( - viewBinding = viewBinding, - greenCardType = cards.first().greenCard.greenCardEntity.type - ) - countdown(viewBinding) - } - - private fun accessibility( - viewBinding: AdapterItemDashboardGreenCardBinding, - greenCardType: GreenCardType - ) { - viewBinding.buttonWithProgressWidgetContainer.accessibility( - viewBinding.title.text.toString() - ) - val imageContentDescription = viewBinding.root.context.getString( - when (greenCardType) { - GreenCardType.Eu -> R.string.validity_type_european_title - } - ) - viewBinding.headerContainer.contentDescription = - "${viewBinding.title.text} $imageContentDescription" - // Mark title of the cards as heading for accessibility - ViewCompat.setAccessibilityHeading(viewBinding.title, true) - } - - private fun initButton( - viewBinding: AdapterItemDashboardGreenCardBinding, - card: DashboardItem.CardsItem.CardItem - ) { - when (card.greenCardEnabledState) { - is GreenCardEnabledState.Enabled -> { - viewBinding.buttonWithProgressWidgetContainer.visibility = View.VISIBLE - viewBinding.disabledState.visibility = View.GONE - viewBinding.buttonWithProgressWidgetContainer.setButtonOnClickListener { - val mainCredentialState = cards.first().credentialState - if (mainCredentialState is HasCredential || featureFlagUseCase.isInArchiveMode()) { - val credentialEntities = cards.mapNotNull { - (it.credentialState as? HasCredential)?.credential - } - onButtonClick.invoke( - cards.first(), - credentialEntities.map { Pair(it.data, it.expirationTime) } - ) - } - } - } - is GreenCardEnabledState.Disabled -> { - viewBinding.buttonWithProgressWidgetContainer.visibility = View.GONE - viewBinding.disabledState.visibility = View.VISIBLE - viewBinding.disabledState.setText(card.greenCardEnabledState.text) - } - } - } - - private fun applyStyling(viewBinding: AdapterItemDashboardGreenCardBinding) { - viewBinding.buttonWithProgressWidgetContainer.setButtonText( - viewBinding.root.context.getString( - if (cards.size > 1) R.string.my_overview_results_button else R.string.my_overview_test_result_button - ) - ) - - val card = cards.first() - - when (card.greenCard.greenCardEntity.type) { - is GreenCardType.Eu -> { - viewBinding.internationalImageContainer.visibility = View.VISIBLE - viewBinding.buttonWithProgressWidgetContainer.setEnabledButtonColor(R.color.link) - } - } - - if (cards.first().credentialState is DashboardItem.CardsItem.CredentialState.LoadingCredential) { - viewBinding.buttonWithProgressWidgetContainer.loading() - } else { - viewBinding.buttonWithProgressWidgetContainer.idle( - isEnabled = cards.first().credentialState is HasCredential || featureFlagUseCase.isInArchiveMode() - ) - } - } - - private fun setContent(viewBinding: AdapterItemDashboardGreenCardBinding) { - // reset layout - viewBinding.run { - (proof2.layoutParams as ViewGroup.MarginLayoutParams).height = 0 - (proof3.layoutParams as ViewGroup.MarginLayoutParams).height = 0 - description.removeAllViews() - errorContainer.visibility = View.GONE - } - - dashboardGreenCardAdapterItemUtil.setContent( - DashboardGreenCardAdapterItemBindingWrapperImpl(viewBinding), - cards.map { AdapterCard(it.greenCard, it.originStates) } - .sortedByDescending { it.originStates.first().origin.eventTime } - ) - - stackAdditionalCards(viewBinding) - - showError(viewBinding) - } - - /** - * Show a border of extra cards when item has additional items of the same type - * - * @param[viewBinding] view binding containing binding of parent view group of green cards - */ - private fun stackAdditionalCards(viewBinding: AdapterItemDashboardGreenCardBinding) { - viewBinding.apply { - if (cards.size >= 2) { - (proof2.layoutParams as ViewGroup.MarginLayoutParams).height = - viewBinding.root.context.resources.getDimensionPixelSize(R.dimen.dashboard_card_additional_card_height) - } - - if (cards.size >= 3) { - (proof3.layoutParams as ViewGroup.MarginLayoutParams).height = - viewBinding.root.context.resources.getDimensionPixelSize(R.dimen.dashboard_card_additional_card_height) - } - } - } - - private fun showError(viewBinding: AdapterItemDashboardGreenCardBinding) { - val context = viewBinding.root.context - val credentialState = cards.first().credentialState - val noCredential = credentialState is DashboardItem.CardsItem.CredentialState.NoCredential - val credentialExpired = - credentialState is DashboardItem.CardsItem.CredentialState.HasCredential && credentialState.credential.expirationTime.isBefore( - OffsetDateTime.now(clock) - ) - if (noCredential || credentialExpired) { - when (cards.first().databaseSyncerResult) { - is DatabaseSyncerResult.Failed.NetworkError -> { - viewBinding.errorText.setHtmlText( - htmlText = context.getString(R.string.my_overview_green_card_internet_error), - htmlTextColor = ContextCompat.getColor(context, R.color.error), - htmlTextColorLink = ContextCompat.getColor(context, R.color.error) - ) - viewBinding.errorText.enableCustomLinks(onRetryClick) - viewBinding.errorContainer.visibility = View.VISIBLE - } - is DatabaseSyncerResult.Failed.ServerError.FirstTime -> { - viewBinding.errorText.setHtmlText( - htmlText = context.getString(R.string.my_overview_green_card_server_error), - htmlTextColor = ContextCompat.getColor(context, R.color.error), - htmlTextColorLink = ContextCompat.getColor(context, R.color.error) - ) - viewBinding.errorText.enableCustomLinks(onRetryClick) - viewBinding.errorContainer.visibility = View.VISIBLE - } - is DatabaseSyncerResult.Failed.ServerError.MultipleTimes -> { - viewBinding.errorText.setHtmlText( - htmlText = context.getString( - R.string.my_overview_green_card_server_error_after_retry, - cachedAppConfigUseCase.getCachedAppConfig().contactInfo.phoneNumber - ), - htmlTextColor = ContextCompat.getColor(context, R.color.error), - htmlTextColorLink = ContextCompat.getColor(context, R.color.error) - ) - viewBinding.errorContainer.visibility = View.VISIBLE - } - else -> { - } - } - } - } - - override fun getLayout(): Int { - return R.layout.adapter_item_dashboard_green_card - } - - override fun initializeViewBinding(view: View): AdapterItemDashboardGreenCardBinding { - return AdapterItemDashboardGreenCardBinding.bind(view) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/items/DashboardGreenCardAdapterItemBindingWrapper.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/items/DashboardGreenCardAdapterItemBindingWrapper.kt deleted file mode 100644 index afb5d9aa8..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/items/DashboardGreenCardAdapterItemBindingWrapper.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.dashboard.items - -import android.widget.LinearLayout -import android.widget.TextView -import nl.rijksoverheid.ctr.holder.databinding.AdapterItemDashboardGreenCardBinding - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -interface DashboardGreenCardAdapterItemBindingWrapper { - val title: TextView - val description: LinearLayout - val expiresIn: TextView -} - -class DashboardGreenCardAdapterItemBindingWrapperImpl(private val viewBinding: AdapterItemDashboardGreenCardBinding) : - DashboardGreenCardAdapterItemBindingWrapper { - - override val title: TextView - get() = viewBinding.title - - override val description: LinearLayout - get() = viewBinding.description - - override val expiresIn: TextView - get() = viewBinding.expiresIn -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/items/DashboardGreenCardAdapterItemExpiryUtil.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/items/DashboardGreenCardAdapterItemExpiryUtil.kt deleted file mode 100644 index 56d11285e..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/items/DashboardGreenCardAdapterItemExpiryUtil.kt +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.dashboard.items - -import android.content.Context -import java.time.Clock -import java.time.Instant -import java.time.OffsetDateTime -import java.time.temporal.ChronoUnit -import java.util.concurrent.TimeUnit -import nl.rijksoverheid.ctr.design.ext.formatDayMonthYear -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.persistence.database.entities.OriginEntity -import nl.rijksoverheid.ctr.persistence.database.entities.OriginType - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ - -interface DashboardGreenCardAdapterItemExpiryUtil { - sealed class ExpireCountDown { - data class Show( - val daysLeft: Long, - val hoursLeft: Long, - val minutesLeft: Long, - val secondsLeft: Long - ) : ExpireCountDown() { - fun expired(): Boolean = arrayOf( - daysLeft, - hoursLeft, - minutesLeft, - secondsLeft).all { it == 0L } - } - object Hide : ExpireCountDown() - data class ShowExpired(val date: String) : ExpireCountDown() - } - - fun getExpireCountdown( - expireDate: OffsetDateTime, - type: OriginType - ): ExpireCountDown - - fun getExpiryText(result: ExpireCountDown.Show): String - - /** - * Get the last origin that's valid if it's the only valid one. - * - * @param[origins] origins list to get the last one valid from - * @return last origin that's valid or null when none or more are valid - */ - fun getLastValidOrigin(origins: List): OriginEntity? -} - -class DashboardGreenCardAdapterItemExpiryUtilImpl( - private val clock: Clock, - private val context: Context -) : DashboardGreenCardAdapterItemExpiryUtil { - - override fun getExpireCountdown( - expireDate: OffsetDateTime, - type: OriginType - ): DashboardGreenCardAdapterItemExpiryUtil.ExpireCountDown { - if (expireDate.isBefore(OffsetDateTime.now(clock))) { - val date = expireDate.toLocalDate().formatDayMonthYear() - return DashboardGreenCardAdapterItemExpiryUtil.ExpireCountDown.ShowExpired(date) - } - val hoursBetweenExpiration = - ChronoUnit.HOURS.between(OffsetDateTime.now(clock), expireDate) - return if (hoursBetweenExpiration >= getExpiryHoursForType(type)) { - DashboardGreenCardAdapterItemExpiryUtil.ExpireCountDown.Hide - } else { - var diff = expireDate.toInstant().toEpochMilli() - Instant.now(clock).toEpochMilli() - val daysUntilFinish = diff / TimeUnit.DAYS.toMillis(1) - diff %= TimeUnit.DAYS.toMillis(1) - val hoursUntilFinish = diff / TimeUnit.HOURS.toMillis(1) - diff %= TimeUnit.HOURS.toMillis(1) - val minutesUntilFinish = diff / TimeUnit.MINUTES.toMillis(1) - diff %= TimeUnit.MINUTES.toMillis(1) - val secondsUntilFinish = diff / TimeUnit.SECONDS.toMillis(1) - diff %= TimeUnit.SECONDS.toMillis(1) - - DashboardGreenCardAdapterItemExpiryUtil.ExpireCountDown.Show( - daysLeft = daysUntilFinish, - hoursLeft = hoursUntilFinish, - minutesLeft = minutesUntilFinish, - secondsLeft = secondsUntilFinish - ) - } - } - - private fun getExpiryHoursForType(type: OriginType): Int { - return if (type == OriginType.Test) { - TimeUnit.HOURS.toHours(6).toInt() - } else { - TimeUnit.DAYS.toHours(21).toInt() - } - } - - override fun getExpiryText( - result: DashboardGreenCardAdapterItemExpiryUtil.ExpireCountDown.Show - ): String { - val daysLeft = result.daysLeft.toInt() - val hoursLeft = result.hoursLeft.toInt() - val minutesLeft = result.minutesLeft.toInt() - val secondsLeft = result.secondsLeft.toInt() - return when { - daysLeft >= 2 -> { - context.getString( - R.string.my_overview_test_result_expires_in, - "$daysLeft ${ - context.resources.getQuantityString( - R.plurals.general_days, - daysLeft - ) - }" - ) - } - daysLeft >= 1 -> { - context.getString( - R.string.my_overview_test_result_expires_in_hours_minutes, - "$daysLeft ${ - context.resources.getQuantityString( - R.plurals.general_days, - daysLeft - ) - }", - "$hoursLeft ${ - context.resources.getQuantityString( - R.plurals.my_overview_test_result_expires_hours, - hoursLeft - ) - }" - ) - } - hoursLeft >= 1 -> { - context.getString( - R.string.my_overview_test_result_expires_in_hours_minutes, - "$hoursLeft ${ - context.resources.getQuantityString( - R.plurals.my_overview_test_result_expires_hours, - hoursLeft - ) - }", - "$minutesLeft ${ - context.resources.getQuantityString( - R.plurals.my_overview_test_result_expires_minutes, - minutesLeft - ) - }" - ) - } - minutesLeft >= 5 -> { - context.getString( - R.string.my_overview_test_result_expires_in, - "$minutesLeft ${ - context.resources.getQuantityString( - R.plurals.my_overview_test_result_expires_minutes, - minutesLeft - ) - }" - ) - } - minutesLeft <= 5 && minutesLeft != 0 -> { - context.getString( - R.string.my_overview_test_result_expires_in_hours_minutes, - "$minutesLeft ${ - context.resources.getQuantityString( - R.plurals.my_overview_test_result_expires_minutes, - minutesLeft - ) - }", - "$secondsLeft ${context.resources.getString(R.string.general_seconds)}" - ) - } - else -> { - context.getString( - R.string.my_overview_test_result_expires_in, - "$secondsLeft ${context.resources.getString(R.string.general_seconds)}" - ) - } - } - } - - override fun getLastValidOrigin(origins: List): OriginEntity? { - return origins.filter { it.expirationTime > OffsetDateTime.now(clock) } - .takeIf { it.size == 1 } - ?.firstOrNull() - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/items/DashboardGreenCardAdapterItemUtil.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/items/DashboardGreenCardAdapterItemUtil.kt deleted file mode 100644 index c9f5f89f4..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/items/DashboardGreenCardAdapterItemUtil.kt +++ /dev/null @@ -1,313 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.dashboard.items - -import android.content.Context -import android.view.View -import android.widget.LinearLayout -import android.widget.Space -import android.widget.TextView -import androidx.core.content.ContextCompat -import java.time.Clock -import java.time.Instant -import java.util.concurrent.TimeUnit -import nl.rijksoverheid.ctr.design.ext.formatDateTime -import nl.rijksoverheid.ctr.design.ext.formatDayMonthTime -import nl.rijksoverheid.ctr.design.ext.formatDayMonthYear -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.dashboard.util.CredentialUtil -import nl.rijksoverheid.ctr.holder.dashboard.util.OriginState -import nl.rijksoverheid.ctr.persistence.database.entities.GreenCardType -import nl.rijksoverheid.ctr.persistence.database.entities.OriginEntity -import nl.rijksoverheid.ctr.persistence.database.entities.OriginType -import nl.rijksoverheid.ctr.persistence.database.models.GreenCard -import nl.rijksoverheid.ctr.shared.ext.capitalize -import nl.rijksoverheid.ctr.shared.ext.locale -import org.koin.core.component.KoinComponent - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -interface DashboardGreenCardAdapterItemUtil { - fun setContent( - dashboardGreenCardAdapterItemBinding: DashboardGreenCardAdapterItemBindingWrapper, - cards: List - ) -} - -class DashboardGreenCardAdapterItemUtilImpl( - private val utcClock: Clock, - private val context: Context, - private val credentialUtil: CredentialUtil, - private val dashboardGreenCardAdapterItemExpiryUtil: DashboardGreenCardAdapterItemExpiryUtil -) : DashboardGreenCardAdapterItemUtil, KoinComponent { - - override fun setContent( - dashboardGreenCardAdapterItemBinding: DashboardGreenCardAdapterItemBindingWrapper, - cards: List - ) { - cards.forEach { card -> - val it = card.greenCard - when (it.greenCardEntity.type) { - is GreenCardType.Eu -> { - // European card only has one origin - val originState = card.originStates.first() - val origin = originState.origin - when (origin.type) { - is OriginType.Test -> { - dashboardGreenCardAdapterItemBinding.title.text = - context.getString(R.string.general_testcertificate_0G).capitalize() - setEuTestOrigin( - dashboardGreenCardAdapterItemBinding, it, originState, origin - ) - setExpiryText(origin, dashboardGreenCardAdapterItemBinding) - } - - is OriginType.Vaccination -> { - dashboardGreenCardAdapterItemBinding.title.text = - context.getString(R.string.general_vaccinationcertificate_0G) - .capitalize() - setEuVaccinationOrigin( - dashboardGreenCardAdapterItemBinding, it, origin - ) - setExpiryText(origin, dashboardGreenCardAdapterItemBinding) - } - - is OriginType.Recovery -> { - dashboardGreenCardAdapterItemBinding.title.text = - context.getString(R.string.general_recoverycertificate_0G) - .capitalize() - setEuRecoveryOrigin( - dashboardGreenCardAdapterItemBinding, - originState, - origin - ) - setExpiryText(origin, dashboardGreenCardAdapterItemBinding) - } - } - } - } - } - - val originStates = cards.first().originStates - val becomesValidAutomatically = - originStates.size == 1 && originStates.first() is OriginState.Future - if (becomesValidAutomatically) { - dashboardGreenCardAdapterItemBinding.expiresIn.visibility = View.VISIBLE - dashboardGreenCardAdapterItemBinding.expiresIn.text = - context.getString(R.string.qr_card_validity_future) - } - } - - /** - * Returns if the origin will expire in more than three years from now - * @param origin The origin to check - */ - private fun originExpirationTimeThreeYearsFromNow(origin: OriginEntity): Boolean { - val expirationSecondsFromNow = - origin.expirationTime.toInstant().epochSecond - Instant.now(utcClock).epochSecond - val expirationYearsFromNow = TimeUnit.SECONDS.toDays(expirationSecondsFromNow) / 365 - return expirationYearsFromNow >= 3 - } - - private fun setEuRecoveryOrigin( - dashboardGreenCardAdapterItemBinding: DashboardGreenCardAdapterItemBindingWrapper, - originState: OriginState, - origin: OriginEntity - ) { - // EU recovery description has no title so we put only the space in between for correct alignment - if (originState !is OriginState.Expired) { - dashboardGreenCardAdapterItemBinding.description.addView( - Space(context), LinearLayout.LayoutParams( - LinearLayout.LayoutParams.MATCH_PARENT, - context.resources.getDimensionPixelSize(R.dimen.green_card_item_proof_spacing) - ) - ) - } - setOriginSubtitle( - descriptionLayout = dashboardGreenCardAdapterItemBinding.description, - originState = originState, - showTime = true, - subtitle = context.getString( - R.string.qr_card_validity_valid, - origin.expirationTime.toLocalDate().formatDayMonthYear() - ) - ) - } - - private fun setEuVaccinationOrigin( - dashboardGreenCardAdapterItemBinding: DashboardGreenCardAdapterItemBindingWrapper, - greenCard: GreenCard, - origin: OriginEntity - ) { - val getCurrentDosesString: (String, String, String) -> String = - { currentDose: String, sumDoses: String, country: String -> - val dosisString = context.getString( - R.string.qr_card_vaccination_doses, - currentDose, sumDoses - ) - if (country.isNotEmpty()) { - "$dosisString$country" - } else { - dosisString - } - } - val doses = credentialUtil.getVaccinationDosesCountryLineForEuropeanCredentials( - greenCard.credentialEntities, - context.locale().language, - getCurrentDosesString - ) - setOriginTitle( - descriptionLayout = dashboardGreenCardAdapterItemBinding.description, - title = doses - ) - - setOriginSubtitle( - descriptionLayout = dashboardGreenCardAdapterItemBinding.description, - // force a valid origin, as we need to allow the user to view the QR - // and when is valid from, it depends from the country going to - originState = OriginState.Valid(greenCard.origins.first()), - showTime = false, - subtitle = "${context.getString(R.string.qr_card_vaccination_title_eu)} ${ - origin.eventTime.toLocalDate().formatDayMonthYear() - }" - ) - } - - private fun setEuTestOrigin( - dashboardGreenCardAdapterItemBinding: DashboardGreenCardAdapterItemBindingWrapper, - greenCard: GreenCard, - originState: OriginState, - origin: OriginEntity - ) { - setOriginTitle( - descriptionLayout = dashboardGreenCardAdapterItemBinding.description, - title = "${context.getString(R.string.qr_card_test_eu)} ${ - credentialUtil.getTestTypeForEuropeanCredentials( - greenCard.credentialEntities - ) - }" - ) - - setOriginSubtitle( - descriptionLayout = dashboardGreenCardAdapterItemBinding.description, - originState = originState, - showTime = false, - subtitle = "${context.getString(R.string.qr_card_test_title_eu)} ${ - origin.eventTime.formatDateTime( - context - ) - }" - ) - } - - private fun setOriginTitle( - descriptionLayout: LinearLayout, - title: String - ) { - descriptionLayout.addView( - TextView(descriptionLayout.context).apply { - setTextAppearance(R.style.App_TextAppearance_MaterialComponents_Body1) - text = title - setTextIsSelectable(true) - }, - LinearLayout.LayoutParams( - LinearLayout.LayoutParams.MATCH_PARENT, - LinearLayout.LayoutParams.WRAP_CONTENT - ).apply { - val topMargin = - context.resources.getDimensionPixelSize(R.dimen.green_card_item_proof_spacing) - setMargins(0, topMargin, 0, 0) - } - ) - } - - private fun setOriginSubtitle( - descriptionLayout: LinearLayout, - originState: OriginState, - showTime: Boolean, - subtitle: String - ) { - val textView = TextView(descriptionLayout.context).apply { - setTextAppearance(R.style.App_TextAppearance_MaterialComponents_Body1) - setTextIsSelectable(true) - } - - when (originState) { - is OriginState.Future -> { - val showUntil = - originState.origin.type == OriginType.Vaccination && - !originExpirationTimeThreeYearsFromNow(originState.origin) || - originState.origin.type == OriginType.Recovery - - val validFromDateTime = originState.origin.validFrom - val validFrom = if (showTime) { - validFromDateTime.formatDayMonthTime(context) - } else { - validFromDateTime.toLocalDate().formatDayMonthYear() - } - textView.text = context.getString( - R.string.qr_card_validity_future_from, validFrom, if (showUntil) { - val until = - originState.origin.expirationTime.toLocalDate().formatDayMonthYear() - context.getString(R.string.qr_card_validity_future_until, until) - } else { - "" - } - ) - textView.visibility = View.VISIBLE - } - - is OriginState.Valid -> { - textView.text = subtitle - textView.visibility = View.VISIBLE - } - - is OriginState.Expired -> { - // Should be filtered out and never reach here - } - } - - descriptionLayout.addView(textView) - } - - private fun setExpiryText( - origin: OriginEntity, - dashboardGreenCardAdapterItemBinding: DashboardGreenCardAdapterItemBindingWrapper - ) { - val expireCountDownResult = dashboardGreenCardAdapterItemExpiryUtil.getExpireCountdown( - origin.expirationTime, origin.type - ) - when (expireCountDownResult) { - is DashboardGreenCardAdapterItemExpiryUtil.ExpireCountDown.Show -> { - dashboardGreenCardAdapterItemBinding.expiresIn.visibility = View.VISIBLE - dashboardGreenCardAdapterItemBinding.expiresIn.text = - dashboardGreenCardAdapterItemExpiryUtil.getExpiryText( - expireCountDownResult - ) - } - - is DashboardGreenCardAdapterItemExpiryUtil.ExpireCountDown.ShowExpired -> { - dashboardGreenCardAdapterItemBinding.expiresIn.visibility = View.VISIBLE - val context = dashboardGreenCardAdapterItemBinding.expiresIn.context - val expiredInText = context.getString(R.string.holder_dashboard_qrValidityDate_expired) - dashboardGreenCardAdapterItemBinding.expiresIn.setTextColor(ContextCompat.getColor(context, R.color.error)) - - dashboardGreenCardAdapterItemBinding.expiresIn.text = "$expiredInText ${expireCountDownResult.date}" - } - - else -> { - dashboardGreenCardAdapterItemBinding.expiresIn.visibility = View.GONE - } - } - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/items/DashboardGreenCardPlaceHolderAdapterItem.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/items/DashboardGreenCardPlaceHolderAdapterItem.kt deleted file mode 100644 index fc69e4a6c..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/items/DashboardGreenCardPlaceHolderAdapterItem.kt +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.dashboard.items - -import android.view.View -import com.xwray.groupie.viewbinding.BindableItem -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.databinding.AdapterItemDashboardGreenCardPlaceholderBinding -import nl.rijksoverheid.ctr.persistence.database.entities.GreenCardType - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -class DashboardGreenCardPlaceHolderAdapterItem(private val greenCardType: GreenCardType) : - BindableItem(R.layout.adapter_item_dashboard_green_card_placeholder.toLong()) { - - override fun getLayout(): Int { - return R.layout.adapter_item_dashboard_green_card_placeholder - } - - override fun initializeViewBinding(view: View): AdapterItemDashboardGreenCardPlaceholderBinding { - return AdapterItemDashboardGreenCardPlaceholderBinding.bind(view) - } - - override fun bind(viewBinding: AdapterItemDashboardGreenCardPlaceholderBinding, position: Int) { - val isEu = greenCardType == GreenCardType.Eu - - viewBinding.icon.setBackgroundResource(if (isEu) { - R.drawable.ic_illustration_hand_qr_placeholder_eu - } else { - R.drawable.ic_illustration_hand_qr_placeholder - }) - viewBinding.title.text = viewBinding.title.context.getString(if (isEu) { - R.string.my_overview_qr_placeholder_header_eu - } else { - R.string.my_overview_qr_placeholder_header - }) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/items/DashboardHeaderAdapterItem.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/items/DashboardHeaderAdapterItem.kt deleted file mode 100644 index eea7e6806..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/items/DashboardHeaderAdapterItem.kt +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.dashboard.items - -import android.view.View -import androidx.annotation.StringRes -import com.xwray.groupie.viewbinding.BindableItem -import nl.rijksoverheid.ctr.design.utils.IntentUtil -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.databinding.AdapterItemDashboardHeaderBinding -import org.koin.core.component.KoinComponent -import org.koin.core.component.inject - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -data class ButtonInfo(@StringRes val text: Int, @StringRes val link: Int) - -class DashboardHeaderAdapterItem(@StringRes private val text: Int, private val buttonInfo: ButtonInfo?) : - BindableItem(R.layout.adapter_item_dashboard_header.toLong()), KoinComponent { - - private val intentUtil: IntentUtil by inject() - - override fun bind(viewBinding: AdapterItemDashboardHeaderBinding, position: Int) { - viewBinding.text.setHtmlText(text, htmlLinksEnabled = true) - viewBinding.button.run { - if (buttonInfo != null) { - visibility = View.VISIBLE - setText(buttonInfo.text) - setOnClickListener { - intentUtil.openUrl( - context = context, - url = context.getString(buttonInfo.link) - ) - } - } else { - visibility = View.GONE - } - } - } - - override fun getLayout(): Int { - return R.layout.adapter_item_dashboard_header - } - - override fun initializeViewBinding(view: View): AdapterItemDashboardHeaderBinding { - return AdapterItemDashboardHeaderBinding.bind(view) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/items/DashboardHeaderAdapterItemUtil.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/items/DashboardHeaderAdapterItemUtil.kt deleted file mode 100644 index f9f70cecc..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/items/DashboardHeaderAdapterItemUtil.kt +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.dashboard.items - -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.dashboard.models.DashboardItem -import nl.rijksoverheid.ctr.persistence.database.entities.GreenCardType - -interface DashboardHeaderAdapterItemUtil { - fun getHeaderItem( - greenCardType: GreenCardType, - emptyState: Boolean - ): DashboardItem.HeaderItem -} - -class DashboardHeaderAdapterItemUtilImpl : DashboardHeaderAdapterItemUtil { - - /** - * Get the header item text to display in the domestic tab on the dashboard screen - * @param greenCardType The type of the tab that is currently selected - * @param emptyState If we should treat the dashboard as being empty state - * @param hasVisitorPassIncompleteItem If there is a incomplete visitor pass item currently showing on the dashboard - */ - override fun getHeaderItem( - greenCardType: GreenCardType, - emptyState: Boolean - ): DashboardItem.HeaderItem { - val text = getHeaderText(greenCardType, emptyState) - val buttonInfo = getButtonInfo(greenCardType, emptyState) - return DashboardItem.HeaderItem(text, buttonInfo) - } - - private fun getHeaderText( - tabType: GreenCardType, - emptyState: Boolean - ) = when (tabType) { - is GreenCardType.Eu -> { - if (emptyState) { - R.string.holder_dashboard_emptyState_international_0G_message - } else { - R.string.holder_dashboard_filledState_international_0G_message - } - } - } - - private fun getButtonInfo(tabType: GreenCardType, empty: Boolean) = - if (tabType == GreenCardType.Eu) { - if (empty) { - ButtonInfo( - R.string.holder_dashboard_international_0G_action_certificateNeeded, - R.string.my_overview_description_eu_button_link - ) - } else { - ButtonInfo( - R.string.my_overview_description_eu_button_text, - R.string.my_overview_description_eu_button_link - ) - } - } else { - null - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/items/DashboardInfoCardAdapterItem.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/items/DashboardInfoCardAdapterItem.kt deleted file mode 100644 index 635d5780e..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/items/DashboardInfoCardAdapterItem.kt +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.dashboard.items - -import android.view.View -import androidx.core.content.ContextCompat -import com.xwray.groupie.viewbinding.BindableItem -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.dashboard.models.DashboardItem -import nl.rijksoverheid.ctr.holder.databinding.AdapterItemDashboardInfoCardBinding -import org.koin.core.component.KoinComponent -import org.koin.core.component.inject - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -class DashboardInfoCardAdapterItem( - private val infoItem: DashboardItem.InfoItem, - private val onButtonClick: (infoItem: DashboardItem.InfoItem) -> Unit, - private val onDismiss: (infoCardAdapterItem: DashboardInfoCardAdapterItem, infoItem: DashboardItem.InfoItem) -> Unit = { _, _ -> } -) : BindableItem(R.layout.adapter_item_dashboard_info_card.toLong()), - KoinComponent { - - private val utilAdapter: DashboardInfoCardAdapterItemUtil by inject() - - override fun bind(viewBinding: AdapterItemDashboardInfoCardBinding, position: Int) { - if (infoItem.isDismissible) { - // dismissible item has a close button with callback - viewBinding.close.visibility = View.VISIBLE - viewBinding.close.setOnClickListener { - onDismiss.invoke(this, infoItem) - } - } else { - // Non dismissible item does not have a close button - viewBinding.close.visibility = View.GONE - } - - viewBinding.button.run { - val buttonTextId = infoItem.buttonText ?: R.string.general_readmore - visibility = if (infoItem.hasButton) View.VISIBLE else View.GONE - setText(buttonTextId) - contentDescription = context.getString(buttonTextId) - } - - when (infoItem) { - is DashboardItem.InfoItem.ExportPdf -> { - viewBinding.text.setText(R.string.holder_pdfExport_card_description) - val context = viewBinding.dashboardItemInfoRoot.context - viewBinding.dashboardItemInfoRoot.setCardBackgroundColor(ContextCompat.getColor(context, R.color.export_pdf_info_item_background)) - } - is DashboardItem.InfoItem.ConfigFreshnessWarning -> { - viewBinding.text.setText(R.string.config_warning_card_message) - } - is DashboardItem.InfoItem.ClockDeviationItem -> { - viewBinding.text.setText(R.string.my_overview_clock_deviation_description) - } - is DashboardItem.InfoItem.GreenCardExpiredItem -> { - val expiredItemText = utilAdapter.getExpiredItemText( - greenCardType = infoItem.greenCardType, - originType = infoItem.originEntity.type - ) - viewBinding.text.text = viewBinding.root.context.getString(expiredItemText) - } - is DashboardItem.InfoItem.OriginInfoItem -> { - viewBinding.text.text = - utilAdapter.getOriginInfoText(infoItem, viewBinding.dashboardItemInfoRoot.context) - } - is DashboardItem.InfoItem.AppUpdate -> { - viewBinding.text.setText(R.string.recommended_update_card_description) - } - is DashboardItem.InfoItem.BlockedEvents -> { - viewBinding.text.setText( - R.string.holder_invaliddetailsremoved_banner_title - ) - } - is DashboardItem.InfoItem.FuzzyMatchedEvents -> { - viewBinding.text.setText( - R.string.holder_identityRemoved_banner_title - ) - } - } - - viewBinding.button.setOnClickListener { - onButtonClick.invoke(infoItem) - } - } - - override fun getLayout(): Int { - return R.layout.adapter_item_dashboard_info_card - } - - override fun initializeViewBinding(view: View): AdapterItemDashboardInfoCardBinding { - return AdapterItemDashboardInfoCardBinding.bind(view) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/items/DashboardInfoCardAdapterItemUtil.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/items/DashboardInfoCardAdapterItemUtil.kt deleted file mode 100644 index 9c4d82bbd..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/items/DashboardInfoCardAdapterItemUtil.kt +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.dashboard.items - -import android.content.Context -import androidx.annotation.StringRes -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.dashboard.models.DashboardItem -import nl.rijksoverheid.ctr.persistence.database.entities.GreenCardType -import nl.rijksoverheid.ctr.persistence.database.entities.OriginType - -interface DashboardInfoCardAdapterItemUtil { - fun getOriginInfoText( - infoItem: DashboardItem.InfoItem.OriginInfoItem, - context: Context - ): String - - @StringRes - fun getExpiredItemText( - greenCardType: GreenCardType, - originType: OriginType - ): Int -} - -class DashboardInfoCardAdapterItemUtilImpl : DashboardInfoCardAdapterItemUtil { - override fun getOriginInfoText( - infoItem: DashboardItem.InfoItem.OriginInfoItem, - context: Context - ): String { - val originString = when (infoItem.originType) { - is OriginType.Vaccination -> context.getString(R.string.type_vaccination) - is OriginType.Recovery -> context.getString(R.string.type_recovery) - is OriginType.Test -> context.getString(R.string.type_test) - } - - return when (infoItem.greenCardType) { - is GreenCardType.Eu -> { - when (infoItem.originType) { - else -> { - context.getString( - R.string.my_overview_not_valid_eu_but_is_in_domestic, originString - ) - } - } - } - } - } - - override fun getExpiredItemText( - greenCardType: GreenCardType, - originType: OriginType - ): Int { - return when { - greenCardType == GreenCardType.Eu && originType == OriginType.Vaccination -> R.string.holder_dashboard_originExpiredBanner_internationalVaccine_title - greenCardType == GreenCardType.Eu && originType == OriginType.Recovery -> R.string.holder_dashboard_originExpiredBanner_internationalRecovery_title - greenCardType == GreenCardType.Eu && originType == OriginType.Test -> R.string.holder_dashboard_originExpiredBanner_internationalTest_title - else -> R.string.qr_card_expired - } - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/models/DashboardItem.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/models/DashboardItem.kt deleted file mode 100644 index 3700e9e65..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/models/DashboardItem.kt +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.dashboard.models - -import androidx.annotation.StringRes -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.dashboard.items.ButtonInfo -import nl.rijksoverheid.ctr.holder.dashboard.util.OriginState -import nl.rijksoverheid.ctr.persistence.database.DatabaseSyncerResult -import nl.rijksoverheid.ctr.persistence.database.entities.CredentialEntity -import nl.rijksoverheid.ctr.persistence.database.entities.EventGroupEntity -import nl.rijksoverheid.ctr.persistence.database.entities.GreenCardType -import nl.rijksoverheid.ctr.persistence.database.entities.OriginEntity -import nl.rijksoverheid.ctr.persistence.database.entities.OriginType -import nl.rijksoverheid.ctr.persistence.database.entities.RemovedEventEntity -import nl.rijksoverheid.ctr.persistence.database.models.GreenCard - -sealed class DashboardItem { - - data class HeaderItem( - @StringRes val text: Int, - val buttonInfo: ButtonInfo? - ) : DashboardItem() - - data class PlaceholderCardItem(val greenCardType: GreenCardType) : DashboardItem() - - sealed class InfoItem( - val isDismissible: Boolean, - val hasButton: Boolean, - @StringRes open val buttonText: Int? = null - ) : DashboardItem() { - - data class ConfigFreshnessWarning(val maxValidityDate: Long) : - InfoItem(isDismissible = false, hasButton = true) - - data class OriginInfoItem( - val greenCardType: GreenCardType, - val originType: OriginType - ) : InfoItem(isDismissible = false, hasButton = true) - - object ClockDeviationItem : InfoItem(isDismissible = false, hasButton = true) - - data class GreenCardExpiredItem( - val greenCardType: GreenCardType, - val originEntity: OriginEntity - ) : InfoItem( - isDismissible = true, - hasButton = false - ) - - object AppUpdate : InfoItem( - isDismissible = false, - hasButton = true, - buttonText = R.string.recommended_update_card_action - ) - - data class BlockedEvents( - val blockedEvents: List, - @StringRes override val buttonText: Int = R.string.general_readmore - ) : InfoItem(isDismissible = true, hasButton = true) - - data class FuzzyMatchedEvents( - val storedEvent: EventGroupEntity, - val events: List, - @StringRes override val buttonText: Int = R.string.general_readmore - ) : InfoItem(isDismissible = true, hasButton = true) - - data class ExportPdf( - @StringRes override val buttonText: Int = R.string.holder_pdfExport_card_action - ) : InfoItem(isDismissible = false, hasButton = true) - } - - data class CardsItem(val cards: List) : DashboardItem() { - - sealed class CredentialState { - data class HasCredential(val credential: CredentialEntity) : CredentialState() - object LoadingCredential : CredentialState() - object NoCredential : CredentialState() - } - - data class CardItem( - val greenCard: GreenCard, - val originStates: List, - val credentialState: CredentialState, - val databaseSyncerResult: DatabaseSyncerResult, - val greenCardEnabledState: GreenCardEnabledState - ) - } - - object AddQrButtonItem : DashboardItem() - - object AddQrCardItem : DashboardItem() -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/models/DashboardItems.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/models/DashboardItems.kt deleted file mode 100644 index cd85f93a0..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/models/DashboardItems.kt +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.dashboard.models - -data class DashboardItems( - val domesticItems: List, - val internationalItems: List -) diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/models/DashboardSyncState.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/models/DashboardSyncState.kt deleted file mode 100644 index 4bffba9cf..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/models/DashboardSyncState.kt +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.dashboard.models - -sealed class DashboardSync { - object ForceSync : DashboardSync() - object DisableSync : DashboardSync() - object CheckSync : DashboardSync() -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/models/DashboardTabItem.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/models/DashboardTabItem.kt deleted file mode 100644 index 20d0f1571..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/models/DashboardTabItem.kt +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.dashboard.models - -import androidx.annotation.StringRes -import nl.rijksoverheid.ctr.persistence.database.entities.GreenCardType - -data class DashboardTabItem( - @StringRes val title: Int, - val greenCardType: GreenCardType, - val items: List -) diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/models/GreenCardEnabledState.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/models/GreenCardEnabledState.kt deleted file mode 100644 index 3aa2a3e35..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/models/GreenCardEnabledState.kt +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.dashboard.models - -import nl.rijksoverheid.ctr.holder.R - -sealed class GreenCardEnabledState { - object Enabled : GreenCardEnabledState() - data class Disabled(val text: Int = R.string.holder_dashboard_domesticQRCard_3G_inactive_label) : GreenCardEnabledState() -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/usecases/GetDashboardItemsUseCase.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/usecases/GetDashboardItemsUseCase.kt deleted file mode 100644 index 7d01ab2ff..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/usecases/GetDashboardItemsUseCase.kt +++ /dev/null @@ -1,278 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.dashboard.usecases - -import nl.rijksoverheid.ctr.holder.dashboard.items.DashboardHeaderAdapterItemUtil -import nl.rijksoverheid.ctr.holder.dashboard.models.DashboardItem -import nl.rijksoverheid.ctr.holder.dashboard.models.DashboardItems -import nl.rijksoverheid.ctr.holder.dashboard.util.CardItemUtil -import nl.rijksoverheid.ctr.holder.dashboard.util.CredentialUtil -import nl.rijksoverheid.ctr.holder.dashboard.util.DashboardItemEmptyStateUtil -import nl.rijksoverheid.ctr.holder.dashboard.util.DashboardItemUtil -import nl.rijksoverheid.ctr.holder.dashboard.util.GreenCardUtil -import nl.rijksoverheid.ctr.holder.dashboard.util.OriginState -import nl.rijksoverheid.ctr.holder.dashboard.util.OriginUtil -import nl.rijksoverheid.ctr.holder.usecases.HolderFeatureFlagUseCase -import nl.rijksoverheid.ctr.persistence.database.DatabaseSyncerResult -import nl.rijksoverheid.ctr.persistence.database.HolderDatabase -import nl.rijksoverheid.ctr.persistence.database.entities.EventGroupEntity -import nl.rijksoverheid.ctr.persistence.database.entities.GreenCardType -import nl.rijksoverheid.ctr.persistence.database.entities.RemovedEventReason -import nl.rijksoverheid.ctr.persistence.database.models.GreenCard - -interface GetDashboardItemsUseCase { - suspend fun getItems( - allEventGroupEntities: List, - allGreenCards: List, - databaseSyncerResult: DatabaseSyncerResult = DatabaseSyncerResult.Success(), - isLoadingNewCredentials: Boolean - ): DashboardItems -} - -class GetDashboardItemsUseCaseImpl( - private val greenCardUtil: GreenCardUtil, - private val credentialUtil: CredentialUtil, - private val originUtil: OriginUtil, - private val dashboardItemUtil: DashboardItemUtil, - private val dashboardItemEmptyStateUtil: DashboardItemEmptyStateUtil, - private val dashboardHeaderAdapterItemUtil: DashboardHeaderAdapterItemUtil, - private val cardItemUtil: CardItemUtil, - private val sortGreenCardItemsUseCase: SortGreenCardItemsUseCase, - private val featureFlagUseCase: HolderFeatureFlagUseCase, - private val holderDatabase: HolderDatabase -) : GetDashboardItemsUseCase { - override suspend fun getItems( - allEventGroupEntities: List, - allGreenCards: List, - databaseSyncerResult: DatabaseSyncerResult, - isLoadingNewCredentials: Boolean - ): DashboardItems { - return DashboardItems( - domesticItems = emptyList(), - internationalItems = getInternationalItems( - allGreenCards = allGreenCards, - databaseSyncerResult = databaseSyncerResult, - isLoadingNewCredentials = isLoadingNewCredentials, - allEventGroupEntities = allEventGroupEntities - ) - ) - } - - private suspend fun getInternationalItems( - allEventGroupEntities: List, - allGreenCards: List, - databaseSyncerResult: DatabaseSyncerResult, - isLoadingNewCredentials: Boolean - ): List { - val dashboardItems = mutableListOf() - val internationalGreenCards = - allGreenCards.filter { it.greenCardEntity.type == GreenCardType.Eu } - - val hasEmptyState = dashboardItemEmptyStateUtil.hasEmptyState( - allGreenCards = allGreenCards, - greenCardsForTab = internationalGreenCards - ) - - val headerItem = dashboardHeaderAdapterItemUtil.getHeaderItem( - emptyState = hasEmptyState, - greenCardType = GreenCardType.Eu - ) - - dashboardItems.add(headerItem) - - if (dashboardItemUtil.isAppUpdateAvailable()) { - dashboardItems.add(DashboardItem.InfoItem.AppUpdate) - } - - if (dashboardItemUtil.shouldShowBlockedEventsItem()) { - dashboardItems.add( - DashboardItem.InfoItem.BlockedEvents( - blockedEvents = holderDatabase.removedEventDao() - .getAll(reason = RemovedEventReason.Blocked) - ) - ) - } - - if (dashboardItemUtil.shouldShowFuzzyMatchedEventsItem()) { - dashboardItems.add( - DashboardItem.InfoItem.FuzzyMatchedEvents( - storedEvent = holderDatabase.eventGroupDao().getAll().first(), - events = holderDatabase.removedEventDao() - .getAll(reason = RemovedEventReason.FuzzyMatched) - ) - ) - } - - if (dashboardItemUtil.shouldShowClockDeviationItem(hasEmptyState, allGreenCards)) { - dashboardItems.add(DashboardItem.InfoItem.ClockDeviationItem) - } - - if (dashboardItemUtil.shouldShowConfigFreshnessWarning()) { - dashboardItems.add( - DashboardItem.InfoItem.ConfigFreshnessWarning( - maxValidityDate = dashboardItemUtil.getConfigFreshnessMaxValidity() - ) - ) - } - - if (dashboardItemUtil.shouldShowExportPdf()) { - dashboardItems.add( - DashboardItem.InfoItem.ExportPdf() - ) - } - - dashboardItems.addAll( - getGreenCardItems( - greenCards = allGreenCards, - greenCardType = GreenCardType.Eu, - greenCardsForSelectedType = internationalGreenCards, - greenCardsForUnselectedType = emptyList(), - databaseSyncerResult = databaseSyncerResult, - isLoadingNewCredentials = isLoadingNewCredentials, - combineVaccinations = true - ) - ) - - if (dashboardItemUtil.shouldShowPlaceholderItem(hasEmptyState)) { - dashboardItems.add( - DashboardItem.PlaceholderCardItem(greenCardType = GreenCardType.Eu) - ) - } - - val addEventsButtonEnabled = featureFlagUseCase.getAddEventsButtonEnabled() - - if (addEventsButtonEnabled) { - if (dashboardItemUtil.shouldShowAddQrCardItem(false, hasEmptyState)) { - dashboardItems.add(DashboardItem.AddQrCardItem) - } - - if (dashboardItemUtil.shouldAddQrButtonItem(hasEmptyState)) { - dashboardItems.add(DashboardItem.AddQrButtonItem) - } - } - - return sortGreenCardItemsUseCase.sort(dashboardItems) - } - - private fun getGreenCardItems( - greenCards: List, - greenCardType: GreenCardType, - greenCardsForSelectedType: List, - greenCardsForUnselectedType: List, - databaseSyncerResult: DatabaseSyncerResult, - isLoadingNewCredentials: Boolean, - combineVaccinations: Boolean - ): List { - - // Loop through all green cards that exists in the database and map them to UI models - val items = greenCardsForSelectedType - .mapIndexed { index, greenCard -> - if (!featureFlagUseCase.isInArchiveMode() && greenCardUtil.isExpired(greenCard) && greenCard.origins.isNotEmpty()) { - getExpiredBannerItem( - greenCard = greenCard - ) - } else { - mapGreenCardsItem( - greenCard = greenCard, - greenCardIndex = index, - isLoadingNewCredentials = isLoadingNewCredentials, - databaseSyncerResult = databaseSyncerResult - ) - } - } - .let { if (combineVaccinations) dashboardItemUtil.combineEuVaccinationItems(it) else it } - .toMutableList() - - // If we have valid origins that exists in the other selected type but not in the current one, we show a banner - val allOriginsForSelectedType = greenCardsForSelectedType.map { it.origins }.flatten() - val allOriginsForUnselectedType = greenCardsForUnselectedType.map { it.origins }.flatten() - val allValidOriginsForSelectedType = originUtil.getOriginState(allOriginsForSelectedType) - .filter { it is OriginState.Valid || it is OriginState.Future }.map { it.origin } - val allValidOriginsForUnselectedType = - originUtil.getOriginState(allOriginsForUnselectedType) - .filter { it is OriginState.Valid || it is OriginState.Future }.map { it.origin } - - allValidOriginsForUnselectedType.forEach { originForUnselectedType -> - if (!allValidOriginsForSelectedType.map { it.type } - .contains(originForUnselectedType.type)) { - - if (dashboardItemUtil.shouldShowOriginInfoItem( - greenCards = greenCards, - greenCardType = greenCardType, - originType = originForUnselectedType.type - ) - ) { - items.add( - DashboardItem.InfoItem.OriginInfoItem( - greenCardType = greenCardType, - originType = originForUnselectedType.type - ) - ) - } - } - } - - return items - } - - private fun getExpiredBannerItem( - greenCard: GreenCard - ): DashboardItem { - val origin = greenCard.origins.last() - return DashboardItem.InfoItem.GreenCardExpiredItem( - greenCardType = greenCard.greenCardEntity.type, - originEntity = origin - ) - } - - private fun mapGreenCardsItem( - greenCard: GreenCard, - greenCardIndex: Int, - isLoadingNewCredentials: Boolean, - databaseSyncerResult: DatabaseSyncerResult - ): DashboardItem.CardsItem { - // Check if we have a credential - val activeCredential = credentialUtil.getActiveCredential( - greenCardType = greenCard.greenCardEntity.type, - entities = greenCard.credentialEntities - ) - - // Check the states of our origins - val originStates = originUtil.getOriginState( - origins = greenCard.origins - ).sortedBy { it.origin.type.order } - - // Check if we have any valid origins - val hasValidOriginStates = originStates.any { it is OriginState.Valid } - val nonExpiredOriginStates = originStates.filterNot { it is OriginState.Expired } - - // More our credential to a more readable state - val credentialState = when { - isLoadingNewCredentials -> DashboardItem.CardsItem.CredentialState.LoadingCredential - activeCredential == null -> DashboardItem.CardsItem.CredentialState.NoCredential - !hasValidOriginStates && !featureFlagUseCase.isInArchiveMode() -> DashboardItem.CardsItem.CredentialState.NoCredential - else -> DashboardItem.CardsItem.CredentialState.HasCredential(activeCredential) - } - - val greenCardItem = DashboardItem.CardsItem.CardItem( - greenCard = greenCard, - originStates = if (featureFlagUseCase.isInArchiveMode()) { - originStates - } else { - nonExpiredOriginStates - }, - credentialState = credentialState, - databaseSyncerResult = databaseSyncerResult, - greenCardEnabledState = cardItemUtil.getEnabledState( - greenCard = greenCard - ) - ) - - return DashboardItem.CardsItem(listOf(greenCardItem)) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/usecases/RemoveExpiredGreenCardsUseCase.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/usecases/RemoveExpiredGreenCardsUseCase.kt deleted file mode 100644 index 84ef5efa3..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/usecases/RemoveExpiredGreenCardsUseCase.kt +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.dashboard.usecases - -import nl.rijksoverheid.ctr.holder.usecases.HolderFeatureFlagUseCase -import nl.rijksoverheid.ctr.persistence.database.HolderDatabase -import nl.rijksoverheid.ctr.persistence.database.models.GreenCard - -/** - * Remove expired green cards (= no more origins). We do this every time before fetching green cards. - * The reason for this is that we transform the database model in [SplitDomesticGreenCardsUseCase]. - * If there is one green card with three origins (vaccination, recovery, test), there are cases we split it - * into two green card (green card 1: vaccination, recovery and green card 2: test) in [SplitDomesticGreenCardsUseCase] - * In case the origin of the second "fake" green card expires, we don't want to remove the green card but only the origin. - */ -interface RemoveExpiredGreenCardsUseCase { - suspend fun execute(allGreenCards: List) -} - -class RemoveExpiredGreenCardsUseCaseImpl( - private val featureFlagUseCase: HolderFeatureFlagUseCase, - private val holderDatabase: HolderDatabase -) : RemoveExpiredGreenCardsUseCase { - - override suspend fun execute(allGreenCards: List) { - if (featureFlagUseCase.isInArchiveMode()) { - return - } - - val greenCardsToRemove = allGreenCards - .filter { - it.origins.isEmpty() - } - - greenCardsToRemove.forEach { - holderDatabase.greenCardDao().delete(it.greenCardEntity) - } - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/usecases/ShowBlockedEventsDialogUseCase.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/usecases/ShowBlockedEventsDialogUseCase.kt deleted file mode 100644 index c535417a9..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/usecases/ShowBlockedEventsDialogUseCase.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.dashboard.usecases - -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEvent -import nl.rijksoverheid.ctr.persistence.database.HolderDatabase -import nl.rijksoverheid.ctr.persistence.database.entities.RemovedEventEntity -import nl.rijksoverheid.ctr.persistence.database.entities.RemovedEventReason - -interface ShowBlockedEventsDialogUseCase { - suspend fun execute(blockedRemoteEvents: List): ShowBlockedEventsDialogResult -} - -class ShowBlockedEventsDialogUseCaseImpl( - private val holderDatabase: HolderDatabase -) : ShowBlockedEventsDialogUseCase { - - override suspend fun execute(blockedRemoteEvents: List): ShowBlockedEventsDialogResult { - return if (blockedRemoteEvents.isEmpty()) { - ShowBlockedEventsDialogResult.None - } else { - ShowBlockedEventsDialogResult.Show( - blockedEvents = holderDatabase.removedEventDao().getAll(reason = RemovedEventReason.Blocked) - ) - } - } -} - -sealed class ShowBlockedEventsDialogResult { - data class Show(val blockedEvents: List) : ShowBlockedEventsDialogResult() - object None : ShowBlockedEventsDialogResult() -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/usecases/SortGreenCardItemsUseCase.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/usecases/SortGreenCardItemsUseCase.kt deleted file mode 100644 index 7a5740bfe..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/usecases/SortGreenCardItemsUseCase.kt +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.dashboard.usecases - -import nl.rijksoverheid.ctr.holder.dashboard.models.DashboardItem -import nl.rijksoverheid.ctr.holder.dashboard.util.GreenCardUtil -import nl.rijksoverheid.ctr.holder.usecases.HolderFeatureFlagUseCase - -interface SortGreenCardItemsUseCase { - fun sort(items: List): List -} - -class SortGreenCardItemsUseCaseImpl( - private val featureFlagUseCase: HolderFeatureFlagUseCase, - private val greenCardUtil: GreenCardUtil -) : SortGreenCardItemsUseCase { - - override fun sort(items: List): List { - if (items.size < 2) { - return items - } - return items.sortedBy { - when (it) { - is DashboardItem.HeaderItem -> 10 - is DashboardItem.InfoItem.ExportPdf -> 15 - DashboardItem.InfoItem.ClockDeviationItem -> 20 - is DashboardItem.InfoItem.ConfigFreshnessWarning -> 30 - is DashboardItem.InfoItem.BlockedEvents -> 40 - is DashboardItem.InfoItem.FuzzyMatchedEvents -> 45 - DashboardItem.InfoItem.AppUpdate -> 50 - is DashboardItem.InfoItem.GreenCardExpiredItem -> 70 - is DashboardItem.InfoItem.OriginInfoItem -> 120 - is DashboardItem.PlaceholderCardItem -> 130 - is DashboardItem.CardsItem -> { - val cardsItemOrder = 140 - cardsItemOrder + (it.cards.firstOrNull()?.originStates?.firstOrNull()?.origin?.type?.order ?: 1) - } - DashboardItem.AddQrButtonItem -> 150 - DashboardItem.AddQrCardItem -> 160 - } - } - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/util/CardItemUtil.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/util/CardItemUtil.kt deleted file mode 100644 index 599e7cb24..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/util/CardItemUtil.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.dashboard.util - -import androidx.annotation.StringRes -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.dashboard.models.DashboardItem -import nl.rijksoverheid.ctr.holder.dashboard.models.GreenCardEnabledState -import nl.rijksoverheid.ctr.holder.qrcodes.models.QrCodeFragmentData -import nl.rijksoverheid.ctr.persistence.database.entities.GreenCardType -import nl.rijksoverheid.ctr.persistence.database.models.GreenCard - -interface CardItemUtil { - - fun getEnabledState( - greenCard: GreenCard - ): GreenCardEnabledState - - fun shouldDisclose( - cardItem: DashboardItem.CardsItem.CardItem - ): QrCodeFragmentData.ShouldDisclose - - @StringRes - fun getQrCodesFragmentToolbarTitle(cardItem: DashboardItem.CardsItem.CardItem): Int -} - -class CardItemUtilImpl : CardItemUtil { - - override fun getEnabledState( - greenCard: GreenCard - ): GreenCardEnabledState { - return when (greenCard.greenCardEntity.type) { - is GreenCardType.Eu -> { - GreenCardEnabledState.Enabled - } - } - } - - override fun shouldDisclose(cardItem: DashboardItem.CardsItem.CardItem): QrCodeFragmentData.ShouldDisclose { - return when (cardItem.greenCard.greenCardEntity.type) { - is GreenCardType.Eu -> { - QrCodeFragmentData.ShouldDisclose.DoNotDisclose - } - } - } - - override fun getQrCodesFragmentToolbarTitle(cardItem: DashboardItem.CardsItem.CardItem): Int { - return R.string.domestic_qr_code_title - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/util/CredentialUtil.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/util/CredentialUtil.kt deleted file mode 100644 index dccc28b1e..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/util/CredentialUtil.kt +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.dashboard.util - -import java.time.Clock -import java.time.LocalDate -import java.time.OffsetDateTime -import java.time.ZoneOffset -import nl.rijksoverheid.ctr.holder.utils.CountryUtil -import nl.rijksoverheid.ctr.persistence.HolderCachedAppConfigUseCase -import nl.rijksoverheid.ctr.persistence.database.entities.CredentialEntity -import nl.rijksoverheid.ctr.persistence.database.entities.GreenCardType -import nl.rijksoverheid.ctr.shared.MobileCoreWrapper -import nl.rijksoverheid.ctr.shared.ext.getStringOrNull -import org.json.JSONArray -import org.json.JSONObject - -interface CredentialUtil { - fun getActiveCredential(greenCardType: GreenCardType, entities: List, ignoreExpiredEuCredentials: Boolean = true): CredentialEntity? - fun isExpiring(credentialRenewalDays: Long, credential: CredentialEntity): Boolean - fun getTestTypeForEuropeanCredentials(entities: List): String - fun getVaccinationDosesCountryLineForEuropeanCredentials( - entities: List, - deviceLanguage: String, - getString: (String, String, String) -> String - ): String - - fun vaccinationShouldBeHidden( - readEuropeanCredentials: List, - indexOfVaccination: Int - ): Boolean - - fun europeanCredentialHasExpired(credentialExpirationTimeSeconds: Long): Boolean -} - -class CredentialUtilImpl( - private val clock: Clock, - private val mobileCoreWrapper: MobileCoreWrapper, - private val appConfigUseCase: HolderCachedAppConfigUseCase, - private val countryUtil: CountryUtil, - cachedAppConfigUseCase: HolderCachedAppConfigUseCase -) : CredentialUtil { - - private val holderConfig = cachedAppConfigUseCase.getCachedAppConfig() - - override fun getActiveCredential(greenCardType: GreenCardType, entities: List, ignoreExpiredEuCredentials: Boolean): CredentialEntity? { - - val credentialsInWindow = entities.filter { - when (greenCardType) { - is GreenCardType.Eu -> { - if (ignoreExpiredEuCredentials) { - // accept expired credentials for dcc - true - } else { - // don't accept expired credentials for dcc - it.validFrom.isBefore( - OffsetDateTime.now(clock) - ) && it.expirationTime.isAfter( - OffsetDateTime.now( - clock - ) - ) - } - } - } - } - - // Return the credential with the longest expiration time if it exists - return credentialsInWindow.maxByOrNull { - it.expirationTime.toEpochSecond() - OffsetDateTime.now(clock) - .toEpochSecond() - } - } - - override fun isExpiring(credentialRenewalDays: Long, credential: CredentialEntity): Boolean { - val now = OffsetDateTime.now(clock) - return credential.expirationTime.minusDays(credentialRenewalDays).isBefore(now) - } - - override fun getTestTypeForEuropeanCredentials(entities: List): String { - val data = mobileCoreWrapper.readEuropeanCredential(entities.first().data) - - return try { - val type = ((((data["dcc"] as JSONObject)["t"] as JSONArray)[0]) as JSONObject)["tt"] as String - holderConfig.euTestTypes.firstOrNull { - it.code == type - }?.name ?: type - } catch (exception: Exception) { - exception.printStackTrace() - "" - } - } - - override fun getVaccinationDosesCountryLineForEuropeanCredentials( - entities: List, - deviceLanguage: String, - getString: (String, String, String) -> String - ): String { - return try { - val data = mobileCoreWrapper.readEuropeanCredential(entities.first().data) - val vaccinationData = (((data["dcc"] as JSONObject)["v"] as JSONArray)[0]) as JSONObject - val dn = vaccinationData["dn"] as Int - val sd = vaccinationData["sd"] as Int - val countryCode = vaccinationData["co"] as String - val countryString = if (countryCode != "NL") { - " (${countryUtil.getCountryForInfoScreen(deviceLanguage, countryCode)})" - } else { - "" - } - getString("$dn", "$sd", countryString) - } catch (exception: Exception) { - exception.printStackTrace() - "" - } - } - - override fun vaccinationShouldBeHidden( - readEuropeanCredentials: List, - indexOfVaccination: Int - ): Boolean { - if (readEuropeanCredentials.size == 1) { - return false - } - val vaccinations = readEuropeanCredentials.map { - it.optJSONObject("dcc")?.getJSONArray("v")?.optJSONObject(0) - } - val (dose, totalDoses) = getDoses(vaccinations[indexOfVaccination]) - return getDateWhenRelevant(vaccinations[indexOfVaccination])?.let { - it < OffsetDateTime.now(clock) && - dose < totalDoses && - !hasCompletedButNotRelevantVaccination(vaccinations, dose) - } ?: false - } - - override fun europeanCredentialHasExpired(credentialExpirationTimeSeconds: Long): Boolean { - return credentialExpirationTimeSeconds < OffsetDateTime.now(clock).toEpochSecond() - } - - private fun hasCompletedButNotRelevantVaccination( - vaccinations: List, - doseOfHiddenVaccination: Int - ): Boolean { - return vaccinations.any { vaccination -> - val (dose, totalDoses) = getDoses(vaccination) - getDateWhenRelevant(vaccination)?.let { - it > OffsetDateTime.now(clock) && - dose == totalDoses && - dose == doseOfHiddenVaccination + 1 - } ?: false - } - } - - private fun getDoses(vaccination: JSONObject?): Pair { - val dose = vaccination?.getStringOrNull("dn") ?: "" - val totalDoses = vaccination?.getStringOrNull("sd") ?: "" - return Pair(dose.toInt(), totalDoses.toInt()) - } - - private fun getDateWhenRelevant(vaccination: JSONObject?): OffsetDateTime? { - val date = LocalDate.parse(vaccination?.getStringOrNull("dt")) - ?.atStartOfDay() - ?.atOffset(ZoneOffset.UTC) - val relevancyDays = - appConfigUseCase.getCachedAppConfig().internationalQRRelevancyDays.toLong() - return date?.plusDays(relevancyDays) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/util/DashboardItemEmptyStateUtil.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/util/DashboardItemEmptyStateUtil.kt deleted file mode 100644 index 4d929a22f..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/util/DashboardItemEmptyStateUtil.kt +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.dashboard.util - -import nl.rijksoverheid.ctr.persistence.database.models.GreenCard - -interface DashboardItemEmptyStateUtil { - fun hasEmptyState( - allGreenCards: List, - greenCardsForTab: List - ): Boolean -} - -class DashboardItemEmptyStateUtilImpl : - DashboardItemEmptyStateUtil { - - override fun hasEmptyState( - allGreenCards: List, - greenCardsForTab: List - ): Boolean { - - return greenCardsForTab.isEmpty() - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/util/DashboardItemUtil.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/util/DashboardItemUtil.kt deleted file mode 100644 index 54e177d3f..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/util/DashboardItemUtil.kt +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.dashboard.util - -import nl.rijksoverheid.ctr.appconfig.usecases.AppConfigFreshnessUseCase -import nl.rijksoverheid.ctr.appconfig.usecases.ClockDeviationUseCase -import nl.rijksoverheid.ctr.holder.dashboard.models.DashboardItem -import nl.rijksoverheid.ctr.holder.usecases.HolderFeatureFlagUseCase -import nl.rijksoverheid.ctr.persistence.HolderCachedAppConfigUseCase -import nl.rijksoverheid.ctr.persistence.database.HolderDatabase -import nl.rijksoverheid.ctr.persistence.database.entities.GreenCardType -import nl.rijksoverheid.ctr.persistence.database.entities.OriginType -import nl.rijksoverheid.ctr.persistence.database.entities.RemovedEventReason -import nl.rijksoverheid.ctr.persistence.database.models.GreenCard -import nl.rijksoverheid.ctr.shared.BuildConfigUseCase - -interface DashboardItemUtil { - fun shouldShowClockDeviationItem(emptyState: Boolean, allGreenCards: List): Boolean - fun shouldShowPlaceholderItem(emptyState: Boolean): Boolean - fun shouldAddQrButtonItem(emptyState: Boolean): Boolean - fun isAppUpdateAvailable(): Boolean - suspend fun shouldShowBlockedEventsItem(): Boolean - suspend fun shouldShowFuzzyMatchedEventsItem(): Boolean - - /** - * Multiple EU vaccination green card items will be combined into 1. - * - * @param[items] Items list containing possible multiple vaccination items to combine. - * @return Items list with vaccination green card items combined into 1. - */ - fun combineEuVaccinationItems(items: List): List - - fun shouldShowConfigFreshnessWarning(): Boolean - fun getConfigFreshnessMaxValidity(): Long - - fun shouldShowOriginInfoItem( - greenCards: List, - greenCardType: GreenCardType, - originType: OriginType - ): Boolean - - fun shouldShowAddQrCardItem( - hasVisitorPassIncompleteItem: Boolean, - emptyState: Boolean - ): Boolean - - fun shouldShowExportPdf(): Boolean -} - -class DashboardItemUtilImpl( - private val clockDeviationUseCase: ClockDeviationUseCase, - private val appConfigFreshnessUseCase: AppConfigFreshnessUseCase, - private val appConfigUseCase: HolderCachedAppConfigUseCase, - private val buildConfigUseCase: BuildConfigUseCase, - private val featureFlagUseCase: HolderFeatureFlagUseCase, - private val holderDatabase: HolderDatabase -) : DashboardItemUtil { - - override fun shouldShowClockDeviationItem(emptyState: Boolean, allGreenCards: List) = - clockDeviationUseCase.hasDeviation() && (!emptyState) - - override fun shouldShowPlaceholderItem( - emptyState: Boolean - ) = emptyState - - override fun shouldAddQrButtonItem(emptyState: Boolean): Boolean = emptyState - - override fun isAppUpdateAvailable(): Boolean { - return buildConfigUseCase.getVersionCode() < appConfigUseCase.getCachedAppConfig().recommendedVersion - } - - override suspend fun shouldShowBlockedEventsItem(): Boolean { - return holderDatabase.removedEventDao().getAll(reason = RemovedEventReason.Blocked) - .isNotEmpty() - } - - override suspend fun shouldShowFuzzyMatchedEventsItem(): Boolean { - val storedEvents = holderDatabase.eventGroupDao().getAll() - // if user has removed his events from the menu, there is no point on showing the banner - if (storedEvents.isEmpty()) { - holderDatabase.removedEventDao().deleteAll(RemovedEventReason.FuzzyMatched) - return false - } - return holderDatabase.removedEventDao().getAll(reason = RemovedEventReason.FuzzyMatched) - .isNotEmpty() - } - - override fun combineEuVaccinationItems(items: List): List { - return items - .groupBy { it::class } - .map { itemTypeToItem -> - if (itemTypeToItem.value.first() !is DashboardItem.CardsItem) { - itemTypeToItem.value - } else { - itemTypeToItem.value - .groupBy { (it as DashboardItem.CardsItem).cards.first().greenCard.origins.first().type } - .map { - if (it.key == OriginType.Vaccination) { - listOf( - DashboardItem.CardsItem(it.value.map { greenCardsItem -> - (greenCardsItem as DashboardItem.CardsItem).cards - }.flatten()) - ) - } else it.value - }.flatten() - } - }.flatten() - } - - override fun shouldShowConfigFreshnessWarning(): Boolean { - // return true if config is older than 10 days && less than 28 days - return appConfigFreshnessUseCase.shouldShowConfigFreshnessWarning() - } - - override fun getConfigFreshnessMaxValidity(): Long { - return appConfigFreshnessUseCase.getAppConfigMaxValidityTimestamp() - } - - override fun shouldShowOriginInfoItem( - greenCards: List, - greenCardType: GreenCardType, - originType: OriginType - ): Boolean { - return false - } - - override fun shouldShowAddQrCardItem( - hasVisitorPassIncompleteItem: Boolean, - emptyState: Boolean - ) = !emptyState && !hasVisitorPassIncompleteItem - - override fun shouldShowExportPdf(): Boolean { - return featureFlagUseCase.isInArchiveMode() - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/util/DashboardPageInfoItemHandlerUtil.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/util/DashboardPageInfoItemHandlerUtil.kt deleted file mode 100644 index 0b03dcee4..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/util/DashboardPageInfoItemHandlerUtil.kt +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.dashboard.util - -import android.content.Intent -import android.provider.Settings -import java.time.Instant -import java.time.OffsetDateTime -import java.time.ZoneOffset -import nl.rijksoverheid.ctr.design.ext.formatDayMonthTime -import nl.rijksoverheid.ctr.design.fragments.info.DescriptionData -import nl.rijksoverheid.ctr.design.fragments.info.InfoFragmentData -import nl.rijksoverheid.ctr.design.utils.InfoFragmentUtil -import nl.rijksoverheid.ctr.design.utils.IntentUtil -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.dashboard.DashboardFragmentDirections -import nl.rijksoverheid.ctr.holder.dashboard.DashboardPageFragment -import nl.rijksoverheid.ctr.holder.dashboard.items.DashboardInfoCardAdapterItem -import nl.rijksoverheid.ctr.holder.dashboard.models.DashboardItem -import nl.rijksoverheid.ctr.persistence.database.entities.EventGroupEntity -import nl.rijksoverheid.ctr.persistence.database.entities.GreenCardType -import nl.rijksoverheid.ctr.persistence.database.entities.OriginType -import nl.rijksoverheid.ctr.persistence.database.entities.RemovedEventEntity -import nl.rijksoverheid.ctr.shared.ext.navigateSafety - -/** - * Handles [DashboardInfoCardAdapterItem] actions - */ -interface DashboardPageInfoItemHandlerUtil { - fun handleButtonClick( - dashboardPageFragment: DashboardPageFragment, - infoItem: DashboardItem.InfoItem - ) - - fun handleDismiss( - dashboardPageFragment: DashboardPageFragment, - infoCardAdapterItem: DashboardInfoCardAdapterItem, - infoItem: DashboardItem.InfoItem - ) -} - -class DashboardPageInfoItemHandlerUtilImpl( - private val infoFragmentUtil: InfoFragmentUtil, - private val intentUtil: IntentUtil, - private val removedEventsBottomSheetUtil: RemovedEventsBottomSheetUtil -) : DashboardPageInfoItemHandlerUtil { - - /** - * Handles the button click in the info card - */ - override fun handleButtonClick( - dashboardPageFragment: DashboardPageFragment, - infoItem: DashboardItem.InfoItem - ) { - when (infoItem) { - is DashboardItem.InfoItem.ConfigFreshnessWarning -> - onConfigRefreshClicked(dashboardPageFragment, infoItem) - is DashboardItem.InfoItem.ClockDeviationItem -> - onClockDeviationClicked(dashboardPageFragment) - is DashboardItem.InfoItem.OriginInfoItem -> - onOriginInfoClicked(dashboardPageFragment, infoItem) - is DashboardItem.InfoItem.AppUpdate -> openPlayStore(dashboardPageFragment) - is DashboardItem.InfoItem.BlockedEvents -> onBlockedEventsClick(dashboardPageFragment, infoItem.blockedEvents) - is DashboardItem.InfoItem.FuzzyMatchedEvents -> onFuzzyMatchedEventsClick(dashboardPageFragment, infoItem.storedEvent, infoItem.events) - is DashboardItem.InfoItem.GreenCardExpiredItem -> { - /* nothing, DashboardPageFragment.setItems never creates a card for this */ - } - is DashboardItem.InfoItem.ExportPdf -> { - dashboardPageFragment.navigateSafety(DashboardFragmentDirections.actionExportIntroduction()) - } - } - } - - private fun openPlayStore(dashboardPageFragment: DashboardPageFragment) { - intentUtil.openPlayStore(dashboardPageFragment.requireContext()) - } - - private fun onConfigRefreshClicked( - dashboardPageFragment: DashboardPageFragment, - infoItem: DashboardItem.InfoItem.ConfigFreshnessWarning - ) { - infoFragmentUtil.presentAsBottomSheet( - dashboardPageFragment.parentFragmentManager, - InfoFragmentData.TitleDescription( - title = dashboardPageFragment.getString(R.string.config_warning_page_title), - descriptionData = DescriptionData( - htmlTextString = dashboardPageFragment.getString( - R.string.config_warning_page_message, - OffsetDateTime.ofInstant( - Instant.ofEpochSecond(infoItem.maxValidityDate), - ZoneOffset.UTC - ).formatDayMonthTime(dashboardPageFragment.requireContext()) - ), - htmlLinksEnabled = true - ) - ) - ) - } - - private fun onClockDeviationClicked( - dashboardPageFragment: DashboardPageFragment - ) { - infoFragmentUtil.presentAsBottomSheet( - dashboardPageFragment.parentFragmentManager, InfoFragmentData.TitleDescription( - title = dashboardPageFragment.getString(R.string.clock_deviation_explanation_title), - descriptionData = DescriptionData( - R.string.clock_deviation_explanation_description, - customLinkIntent = Intent(Settings.ACTION_DATE_SETTINGS) - ) - ) - ) - } - - private fun onBlockedEventsClick(dashboardPageFragment: DashboardPageFragment, blockedEvents: List) { - removedEventsBottomSheetUtil.presentBlockedEvents(dashboardPageFragment, blockedEvents) - } - - private fun onFuzzyMatchedEventsClick(dashboardPageFragment: DashboardPageFragment, storedEvent: EventGroupEntity, events: List) { - removedEventsBottomSheetUtil.presentRemovedEvents(dashboardPageFragment, storedEvent, events) - } - - private fun onOriginInfoClicked( - dashboardPageFragment: DashboardPageFragment, - item: DashboardItem.InfoItem.OriginInfoItem - ) { - when (item.greenCardType) { - is GreenCardType.Eu -> presentOriginInfoForEuQr( - item.originType, dashboardPageFragment - ) - } - } - - private fun presentOriginInfoForEuQr( - originType: OriginType, - dashboardPageFragment: DashboardPageFragment - ) { - infoFragmentUtil.presentAsBottomSheet( - dashboardPageFragment.parentFragmentManager, - data = when (originType) { - is OriginType.Test -> { - InfoFragmentData.TitleDescription( - title = dashboardPageFragment.getString(R.string.my_overview_green_card_not_valid_title_test), - descriptionData = DescriptionData(R.string.my_overview_green_card_not_valid_eu_but_is_in_domestic_bottom_sheet_description_test) - ) - } - is OriginType.Vaccination -> { - InfoFragmentData.TitleDescription( - title = dashboardPageFragment.getString(R.string.my_overview_green_card_not_valid_title_vaccination), - descriptionData = DescriptionData(R.string.my_overview_green_card_not_valid_eu_but_is_in_domestic_bottom_sheet_description_vaccination) - ) - } - is OriginType.Recovery -> { - InfoFragmentData.TitleDescription( - title = dashboardPageFragment.getString(R.string.my_overview_green_card_not_valid_title_recovery), - descriptionData = DescriptionData( - htmlText = R.string.my_overview_green_card_not_valid_eu_but_is_in_domestic_bottom_sheet_description_recovery, - htmlLinksEnabled = true - ) - ) - } - } - ) - } - - /** - * Handles the dismiss button click in the info card - */ - override fun handleDismiss( - dashboardPageFragment: DashboardPageFragment, - infoCardAdapterItem: DashboardInfoCardAdapterItem, - infoItem: DashboardItem.InfoItem - ) { - // Remove section from adapter - dashboardPageFragment.section.remove(infoCardAdapterItem) - - // Clear preference so it doesn't show again - when (infoItem) { - is DashboardItem.InfoItem.GreenCardExpiredItem -> { - dashboardPageFragment.dashboardViewModel.removeOrigin(infoItem.originEntity) - } - is DashboardItem.InfoItem.BlockedEvents -> { - dashboardPageFragment.dashboardViewModel.dismissBlockedEventsInfo() - } - is DashboardItem.InfoItem.FuzzyMatchedEvents -> { - dashboardPageFragment.dashboardViewModel.dismissFuzzyMatchedEventsInfo() - } - else -> { - } - } - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/util/GreenCardRefreshUtil.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/util/GreenCardRefreshUtil.kt deleted file mode 100644 index 5996e18e7..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/util/GreenCardRefreshUtil.kt +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.dashboard.util - -import java.time.Clock -import java.time.OffsetDateTime -import java.time.temporal.ChronoUnit.DAYS -import nl.rijksoverheid.ctr.persistence.HolderCachedAppConfigUseCase -import nl.rijksoverheid.ctr.persistence.database.HolderDatabase - -sealed class RefreshState { - class Refreshable(val days: Long) : RefreshState() - object NoRefresh : RefreshState() -} - -interface GreenCardRefreshUtil { - suspend fun shouldRefresh(): Boolean - suspend fun refreshState(): RefreshState -} - -class GreenCardRefreshUtilImpl( - private val holderDatabase: HolderDatabase, - cachedAppConfigUseCase: HolderCachedAppConfigUseCase, - private val greenCardUtil: GreenCardUtil, - private val clock: Clock, - private val credentialUtil: CredentialUtil, - private val originUtil: OriginUtil -) : GreenCardRefreshUtil { - - private val holderConfig = cachedAppConfigUseCase.getCachedAppConfig() - - override suspend fun shouldRefresh(): Boolean { - val credentialRenewalDays = holderConfig.credentialRenewalDays.toLong() - - // Foreign dccs and dutch paper based dccs should not be refreshed - // so exclude them from the refresh logic - val eventFromDccHints = holderDatabase.originHintDao().get("event_from_dcc") - val greenCardsToRefresh = holderDatabase.greenCardDao().getAll() - .filter { !greenCardUtil.isEventFromDcc(it, eventFromDccHints) } - - val greenCardExpiring = greenCardsToRefresh.firstOrNull { greenCard -> - val hasNewCredentials = !greenCardUtil.getExpireDate(greenCard).isEqual( - greenCard.credentialEntities.lastOrNull()?.expirationTime - ?: OffsetDateTime.now(clock) - ) - val latestCredential = greenCard.credentialEntities.maxByOrNull { it.expirationTime } - val latestCredentialExpiring = latestCredential?.let { - credentialUtil.isExpiring(credentialRenewalDays, latestCredential) - } ?: false - hasNewCredentials && latestCredentialExpiring - } - - // It can be that a green card has no credentials but they will be available in the future. - // A refresh should be done in the case there are valid origins within the threshold. - val hasValidFutureOrigins = greenCardsToRefresh - .filter { it.credentialEntities.isEmpty() } - .any { greenCard -> - greenCard.origins.any { - originUtil.isValidWithinRenewalThreshold(credentialRenewalDays, it) - } - } - - return greenCardExpiring != null || hasValidFutureOrigins - } - - // returns the refresh state of the app, - // if it should schedule a refresh or not - // and if so, in how many days from now - override suspend fun refreshState(): RefreshState { - val credentialRenewalDays = holderConfig.credentialRenewalDays.toLong() - - // Foreign dccs and dutch paper based dccs should not be refreshed - // so exclude them from the refresh logic - val eventFromDccHints = holderDatabase.originHintDao().get("event_from_dcc") - val greenCardsToRefresh = holderDatabase.greenCardDao().getAll() - .filter { !greenCardUtil.isEventFromDcc(it, eventFromDccHints) } - - // find the furthest in the future credentials that - // can be renewed, if any - val latestCredentialExpirationTime: OffsetDateTime? = - greenCardsToRefresh.filter { greenCard -> - !greenCardUtil.getExpireDate(greenCard).isEqual( - greenCard.credentialEntities.lastOrNull()?.expirationTime - ?: OffsetDateTime.now(clock) - ) - }.mapNotNull { greenCard -> - greenCard.credentialEntities.maxByOrNull { it.expirationTime }?.expirationTime - }.maxOrNull() - - // for domestic, we don't get credentials for origins which are not valid yet - // so we take into account to fetch them when they become valid - val firstFutureValidFrom: OffsetDateTime? = greenCardsToRefresh - .filter { it.credentialEntities.isEmpty() } - .flatMap { originUtil.getOriginState(it.origins) } - .filterIsInstance() - .map { it.origin.validFrom } - .minOrNull() - - // either we have a future origin to refresh, or an expiring credentials or both - // in the latter case, use the one closest to now - return when { - firstFutureValidFrom != null && latestCredentialExpirationTime != null -> { - if (firstFutureValidFrom.isBefore(latestCredentialExpirationTime.minusDays(credentialRenewalDays))) { - RefreshState.Refreshable( - daysBetween(firstFutureValidFrom) - ) - } else { - RefreshState.Refreshable( - daysBetween(latestCredentialExpirationTime.minusDays(credentialRenewalDays)) - ) - } - } - firstFutureValidFrom != null -> RefreshState.Refreshable( - daysBetween(firstFutureValidFrom) - ) - latestCredentialExpirationTime != null -> RefreshState.Refreshable( - daysBetween(latestCredentialExpirationTime.minusDays(credentialRenewalDays)) - ) - else -> RefreshState.NoRefresh - } - } - - private fun daysBetween(toDate: OffsetDateTime): Long { - val days = DAYS.between(OffsetDateTime.now(clock), toDate) - return if (days < 1) { - 1 - } else { - days - } - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/util/GreenCardUtil.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/util/GreenCardUtil.kt deleted file mode 100644 index c00bae748..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/util/GreenCardUtil.kt +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.dashboard.util - -import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel -import java.time.Clock -import java.time.OffsetDateTime -import nl.rijksoverheid.ctr.persistence.database.HolderDatabase -import nl.rijksoverheid.ctr.persistence.database.entities.GreenCardType -import nl.rijksoverheid.ctr.persistence.database.entities.OriginHintEntity -import nl.rijksoverheid.ctr.persistence.database.entities.OriginType -import nl.rijksoverheid.ctr.persistence.database.models.GreenCard -import nl.rijksoverheid.ctr.shared.MobileCoreWrapper - -interface GreenCardUtil { - suspend fun getAllGreenCards(): List - - fun hasOrigin(greenCards: List, originType: OriginType): Boolean - - fun isExpired(greenCard: GreenCard): Boolean - - /** - * Get the expiration date of the green card or of a specific origin of the green card - * - * @param[greenCard] green card to check expiration date - * @param[type] Origin to get expiration from or if null latest expiration of all origins - * @return Expiration time of origin type or latest expiration of all origins when not specified - */ - fun getExpireDate(greenCard: GreenCard, type: OriginType? = null): OffsetDateTime - - fun getErrorCorrectionLevel(greenCardType: GreenCardType): ErrorCorrectionLevel - - fun isExpiring(renewalDays: Long, greenCard: GreenCard): Boolean - - fun hasNoActiveCredentials(greenCard: GreenCard, ignoreExpiredEuCredentials: Boolean = true): Boolean - - fun isEventFromDcc(greenCard: GreenCard, hints: List): Boolean -} - -class GreenCardUtilImpl( - private val holderDatabase: HolderDatabase, - private val clock: Clock, - private val credentialUtil: CredentialUtil, - private val mobileCoreWrapper: MobileCoreWrapper -) : GreenCardUtil { - - override fun getExpireDate(greenCard: GreenCard, type: OriginType?): OffsetDateTime { - return greenCard.origins - .filter { if (type == null) true else type == it.type } - .maxByOrNull { it.expirationTime } - ?.expirationTime - ?: OffsetDateTime.now(clock) - } - - override fun getErrorCorrectionLevel(greenCardType: GreenCardType): ErrorCorrectionLevel { - return when (greenCardType) { - is GreenCardType.Eu -> ErrorCorrectionLevel.Q - } - } - - override suspend fun getAllGreenCards(): List { - return holderDatabase - .greenCardDao() - .getAll() - .filter { it.origins.isNotEmpty() } - } - - override fun hasOrigin(greenCards: List, originType: OriginType): Boolean { - return greenCards.map { it.origins }.flatten().map { it.type }.any { it == originType } - } - - override fun isExpired(greenCard: GreenCard): Boolean { - return OffsetDateTime.now(clock) >= getExpireDate(greenCard) - } - - override fun isExpiring(renewalDays: Long, greenCard: GreenCard): Boolean { - val now = OffsetDateTime.now(clock) - val expirationTime = getExpireDate(greenCard) - return expirationTime.minusDays(renewalDays).isBefore(now) - } - - override fun hasNoActiveCredentials(greenCard: GreenCard, ignoreExpiredEuCredentials: Boolean): Boolean { - return credentialUtil.getActiveCredential(greenCard.greenCardEntity.type, greenCard.credentialEntities, ignoreExpiredEuCredentials) == null - } - - override fun isEventFromDcc(greenCard: GreenCard, hints: List): Boolean { - return when (greenCard.greenCardEntity.type) { - is GreenCardType.Eu -> { - val eventFromDccHintOriginIds = hints.map { it.originId } - val greenCardOriginIds = greenCard.origins.map { it.id.toLong() } - greenCardOriginIds.intersect(eventFromDccHintOriginIds.toSet()).isNotEmpty() - } - } - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/util/OriginUtil.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/util/OriginUtil.kt deleted file mode 100644 index 039580ef8..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/util/OriginUtil.kt +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.dashboard.util - -import java.time.Clock -import java.time.OffsetDateTime -import nl.rijksoverheid.ctr.persistence.database.entities.OriginEntity - -interface OriginUtil { - fun getOriginState(origins: List): List - - fun isValidWithinRenewalThreshold(credentialRenewalDays: Long, origin: OriginEntity): Boolean -} - -class OriginUtilImpl(private val clock: Clock) : OriginUtil { - - companion object { - private const val PRESENT_SUBTITLE_WHEN_LESS_THEN_YEARS = 3 - } - - override fun getOriginState(origins: List): List { - return origins.map { origin -> - when { - origin.expirationTime.isBefore(OffsetDateTime.now(clock)) -> { - OriginState.Expired(origin) - } - origin.validFrom.isAfter(OffsetDateTime.now(clock)) -> { - OriginState.Future(origin) - } - else -> { - OriginState.Valid(origin) - } - } - } - } - - override fun isValidWithinRenewalThreshold( - credentialRenewalDays: Long, - origin: OriginEntity - ): Boolean { - val now = OffsetDateTime.now(clock) - val thresholdEndDate = now.plusDays(credentialRenewalDays) - return origin.validFrom < thresholdEndDate && origin.expirationTime > now - } -} - -sealed class OriginState(open val origin: OriginEntity) { - data class Valid(override val origin: OriginEntity) : OriginState(origin) - data class Future(override val origin: OriginEntity) : OriginState(origin) - data class Expired(override val origin: OriginEntity) : OriginState(origin) -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/util/RemovedEventsBottomSheetUtil.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/util/RemovedEventsBottomSheetUtil.kt deleted file mode 100644 index 9f7850c9f..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/dashboard/util/RemovedEventsBottomSheetUtil.kt +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.dashboard.util - -import android.content.Context -import androidx.core.text.HtmlCompat -import nl.rijksoverheid.ctr.appconfig.usecases.CachedAppConfigUseCase -import nl.rijksoverheid.ctr.design.ext.formatDateTime -import nl.rijksoverheid.ctr.design.ext.formatDayMonthYear -import nl.rijksoverheid.ctr.design.fragments.info.DescriptionData -import nl.rijksoverheid.ctr.design.fragments.info.InfoFragmentData -import nl.rijksoverheid.ctr.design.utils.InfoFragmentUtil -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.dashboard.DashboardPageFragment -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEvent -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEventNegativeTest -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEventPositiveTest -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEventRecovery -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEventVaccination -import nl.rijksoverheid.ctr.holder.get_events.usecases.GetRemoteProtocolFromEventGroupUseCase -import nl.rijksoverheid.ctr.holder.models.HolderFlow -import nl.rijksoverheid.ctr.holder.models.HolderStep -import nl.rijksoverheid.ctr.holder.your_events.utils.RemoteEventStringUtil -import nl.rijksoverheid.ctr.holder.your_events.utils.YourEventsFragmentUtil -import nl.rijksoverheid.ctr.persistence.database.entities.EventGroupEntity -import nl.rijksoverheid.ctr.persistence.database.entities.RemovedEventEntity -import nl.rijksoverheid.ctr.shared.factories.ErrorCodeStringFactory -import nl.rijksoverheid.ctr.shared.models.AppErrorResult -import nl.rijksoverheid.ctr.shared.models.BlockedEventException - -interface RemovedEventsBottomSheetUtil { - fun presentBlockedEvents(dashboardPageFragment: DashboardPageFragment, blockedEvents: List) - fun presentRemovedEvents(dashboardPageFragment: DashboardPageFragment, storedEvent: EventGroupEntity, removedEvents: List) -} - -class RemovedEventsBottomSheetUtilImpl( - private val errorCodeStringFactory: ErrorCodeStringFactory, - private val remoteEventStringUtil: RemoteEventStringUtil, - private val getRemoteProtocolFromEventGroupUseCase: GetRemoteProtocolFromEventGroupUseCase, - private val yourEventsFragmentUtil: YourEventsFragmentUtil, - private val infoFragmentUtil: InfoFragmentUtil, - private val cachedAppConfigUseCase: CachedAppConfigUseCase -) : RemovedEventsBottomSheetUtil { - - private fun formattedEvents(context: Context, events: List): String { - val removedEventsHtml = StringBuilder() - events.forEachIndexed { index, blockedEvent -> - val remoteEventClass = RemoteEvent.getRemoteEventClassFromType(blockedEvent.type) - - val title = remoteEventStringUtil.remoteEventTitle(remoteEventClass) - val date = when (remoteEventClass) { - RemoteEventVaccination::class.java -> "${context.getString(R.string.qr_card_vaccination_title_eu)} ${ - blockedEvent.eventTime?.toLocalDate()?.formatDayMonthYear() - }" - RemoteEventNegativeTest::class.java -> "${context.getString(R.string.qr_card_test_title_eu)} ${ - blockedEvent.eventTime?.formatDateTime( - context - ) - }" - RemoteEventPositiveTest::class.java -> "${context.getString(R.string.qr_card_test_title_eu)} ${ - blockedEvent.eventTime?.formatDateTime( - context - ) - }" - RemoteEventRecovery::class.java -> "${context.getString(R.string.qr_card_recovery_title_eu)} ${ - blockedEvent.eventTime?.toLocalDate()?.formatDayMonthYear() - }" - else -> "" - } - - removedEventsHtml.append("$title") - removedEventsHtml.append("
") - removedEventsHtml.append("$date") - - val finalEvent = index == events.size - 1 - if (!finalEvent) { - removedEventsHtml.append("

") - } - } - - return removedEventsHtml.toString() - } - - override fun presentBlockedEvents( - dashboardPageFragment: DashboardPageFragment, - blockedEvents: List - ) { - val context = dashboardPageFragment.requireContext() - val removedEventsHtml = formattedEvents(context, blockedEvents) - - val errorCode = errorCodeStringFactory.get( - HolderFlow.Refresh, listOf( - AppErrorResult( - HolderStep.GetCredentialsNetworkRequest, BlockedEventException() - ) - ) - ) - - val contactInformation = cachedAppConfigUseCase.getCachedAppConfig().contactInfo - infoFragmentUtil.presentAsBottomSheet( - dashboardPageFragment.parentFragmentManager, - InfoFragmentData.TitleDescription( - title = context.getString(R.string.holder_invaliddetailsremoved_moreinfo_title), - descriptionData = DescriptionData( - htmlTextString = context.getString( - R.string.holder_invaliddetailsremoved_moreinfo_body, - removedEventsHtml, - contactInformation.phoneNumber, - contactInformation.phoneNumber, - errorCode - ), - htmlLinksEnabled = true - ) - ) - ) - } - - override fun presentRemovedEvents( - dashboardPageFragment: DashboardPageFragment, - storedEvent: EventGroupEntity, - removedEvents: List - ) { - val context = dashboardPageFragment.requireContext() - val removedEventsHtml = formattedEvents(context, removedEvents) - - val name = yourEventsFragmentUtil.getFullName(getRemoteProtocolFromEventGroupUseCase.get(storedEvent)?.holder) - - infoFragmentUtil.presentAsBottomSheet( - dashboardPageFragment.parentFragmentManager, - InfoFragmentData.TitleDescription( - title = context.getString(R.string.holder_identityRemoved_moreinfo_title), - descriptionData = DescriptionData( - htmlTextString = context.getString( - R.string.holder_identityRemoved_moreinfo_body, - HtmlCompat.fromHtml(name, HtmlCompat.FROM_HTML_MODE_LEGACY), - removedEventsHtml - ), - htmlLinksEnabled = true - ) - ) - ) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/FuzzyMatchingBaseViewModel.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/FuzzyMatchingBaseViewModel.kt deleted file mode 100644 index 5f6d78bb6..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/FuzzyMatchingBaseViewModel.kt +++ /dev/null @@ -1,40 +0,0 @@ -package nl.rijksoverheid.ctr.holder.fuzzy_matching - -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import kotlinx.coroutines.launch -import nl.rijksoverheid.ctr.holder.dashboard.util.GreenCardUtil -import nl.rijksoverheid.ctr.persistence.database.HolderDatabase - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -abstract class FuzzyMatchingBaseViewModel( - private val holderDatabase: HolderDatabase, - private val greenCardUtil: GreenCardUtil -) : ViewModel() { - val toolbarButtonsStateLiveData: LiveData = MutableLiveData() - fun canSkip(fromGetEvents: Boolean) { - if (fromGetEvents) { - (toolbarButtonsStateLiveData as MutableLiveData).value = ToolbarButtonsState( - canGoBack = true, - canSkip = false - ) - } else { - viewModelScope.launch { - val activeCredentialExists = holderDatabase.greenCardDao().getAll() - .any { !greenCardUtil.hasNoActiveCredentials(it, false) } - (toolbarButtonsStateLiveData as MutableLiveData).value = ToolbarButtonsState( - canGoBack = activeCredentialExists, - canSkip = activeCredentialExists - ) - } - } - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/FuzzyMatchingModule.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/FuzzyMatchingModule.kt deleted file mode 100644 index 5af9e79cb..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/FuzzyMatchingModule.kt +++ /dev/null @@ -1,52 +0,0 @@ -package nl.rijksoverheid.ctr.holder.fuzzy_matching - -import org.koin.android.ext.koin.androidContext -import org.koin.androidx.viewmodel.dsl.viewModel -import org.koin.dsl.module - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -val fuzzyMatchingModule = module { - viewModel { - FuzzyMatchingOnboardingViewModel(get(), get()) - } - - viewModel { (matchingBlobIds: List>) -> - HolderNameSelectionViewModelImpl( - get(), - get(), - get(), - get(), - get(), - get(), - matchingBlobIds - ) - } - - factory { - fun getFormattedString(stringResId: Int, template: String): String { - return androidContext().getString(stringResId, template) - } - SelectionDataUtilImpl( - get(), - get(), - get(), - androidContext().resources::getQuantityString, - ::getFormattedString, - androidContext()::getString - ) - } - - factory { - SelectionDetailBottomSheetDescriptionUtilImpl() - } - - factory { - MatchedEventsUseCaseImpl(get(), get()) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/FuzzyMatchingOnboardingFragment.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/FuzzyMatchingOnboardingFragment.kt deleted file mode 100644 index 6fe60d3e8..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/FuzzyMatchingOnboardingFragment.kt +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright (c) 2023 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ - -package nl.rijksoverheid.ctr.holder.fuzzy_matching - -import android.annotation.SuppressLint -import android.os.Bundle -import android.view.View -import android.widget.ScrollView -import androidx.activity.OnBackPressedCallback -import androidx.core.content.ContextCompat -import androidx.fragment.app.Fragment -import androidx.navigation.fragment.navArgs -import androidx.viewpager2.widget.ViewPager2 -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.hideNavigationIcon -import nl.rijksoverheid.ctr.holder.showNavigationIcon -import nl.rijksoverheid.ctr.introduction.databinding.FragmentOnboardingBinding -import nl.rijksoverheid.ctr.introduction.onboarding.OnboardingPagerAdapter -import nl.rijksoverheid.ctr.introduction.onboarding.models.OnboardingItem -import nl.rijksoverheid.ctr.shared.ext.findNavControllerSafety -import nl.rijksoverheid.ctr.shared.ext.navigateSafety -import org.koin.androidx.viewmodel.ext.android.viewModel - -class FuzzyMatchingOnboardingFragment : Fragment(R.layout.fragment_onboarding) { - private var _binding: FragmentOnboardingBinding? = null - private val binding get() = _binding!! - - private val fuzzyMatchingOnboardingFragmentArgs: FuzzyMatchingOnboardingFragmentArgs by navArgs() - - private val viewModel: FuzzyMatchingOnboardingViewModel by viewModel() - - private val onboardingItems by lazy { - listOf( - OnboardingItem( - imageResource = R.drawable.ic_holder_fuzzymatching_onboarding_firstpage, - titleResource = R.string.holder_fuzzyMatching_onboarding_firstPage_title, - description = R.string.holder_fuzzyMatching_onboarding_firstPage_body - ), - OnboardingItem( - imageResource = R.drawable.ic_holder_fuzzymatching_onboarding_secondpage, - titleResource = R.string.holder_fuzzyMatching_onboarding_secondPage_title, - description = R.string.holder_fuzzyMatching_onboarding_secondPage_body - ), - OnboardingItem( - imageResource = R.drawable.ic_holder_fuzzymatching_onboarding_thirdpage, - titleResource = R.string.holder_fuzzyMatching_onboarding_thirdPage_title, - description = R.string.holder_fuzzyMatching_onboarding_thirdPage_body - ) - ) - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - _binding = FragmentOnboardingBinding.bind(view) - - val adapter = - OnboardingPagerAdapter( - childFragmentManager, - lifecycle, - onboardingItems - ) - - if (onboardingItems.isNotEmpty()) { - binding.indicators.initIndicator(adapter.itemCount) - initViewPager(adapter, savedInstanceState?.getInt(indicatorPositionKey)) - } - - setBackPressListener() - setBindings(adapter) - - viewModel.toolbarButtonsStateLiveData.observe(viewLifecycleOwner) { (canGoBack, _) -> - if (!canGoBack) { - hideNavigationIcon() - } - } - viewModel.canSkip(fuzzyMatchingOnboardingFragmentArgs.getEventsFlow) - } - - private fun setBindings( - adapter: OnboardingPagerAdapter - ) { - binding.button.setOnClickListener { - val currentItem = binding.viewPager.currentItem - if (currentItem == adapter.itemCount - 1) { - navigateSafety( - FuzzyMatchingOnboardingFragmentDirections.actionHolderNameSelection( - matchingBlobIds = fuzzyMatchingOnboardingFragmentArgs.matchingBlobIds, - getEventsFlow = fuzzyMatchingOnboardingFragmentArgs.getEventsFlow - ) - ) - } else { - binding.viewPager.currentItem = currentItem + 1 - } - } - } - - private fun setBackPressListener() { - requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, object : - OnBackPressedCallback(true) { - override fun handleOnBackPressed() { - val currentItem = binding.viewPager.currentItem - if (currentItem == 0) { - findNavControllerSafety()?.popBackStack() - } else { - binding.viewPager.currentItem = binding.viewPager.currentItem - 1 - } - } - }) - } - - override fun onSaveInstanceState(outState: Bundle) { - super.onSaveInstanceState(outState) - _binding?.let { - outState.putInt(indicatorPositionKey, it.viewPager.currentItem) - } - } - - private fun initViewPager( - adapter: OnboardingPagerAdapter, - startingItem: Int? = null - ) { - binding.viewPager.offscreenPageLimit = onboardingItems.size - binding.viewPager.adapter = adapter - binding.viewPager.registerOnPageChangeCallback(object : - ViewPager2.OnPageChangeCallback() { - @SuppressLint("StringFormatInvalid") - override fun onPageSelected(position: Int) { - super.onPageSelected(position) - binding.indicators.updateSelected(position) - - binding.indicators.contentDescription = getString( - nl.rijksoverheid.ctr.introduction.R.string.onboarding_page_indicator_label, - (position + 1).toString(), - adapter.itemCount.toString() - ) - val isFirstItem = position == 0 - val isLastItem = position == adapter.itemCount - 1 - binding.button.text = getString( - if (isLastItem) { - R.string.holder_fuzzyMatching_onboarding_thirdPage_action - } else { - R.string.onboarding_next - } - ) - - // Apply bottom elevation if the view inside the viewpager is scrollable - val scrollView = - childFragmentManager.fragments[position]?.view?.findViewById(nl.rijksoverheid.ctr.introduction.R.id.scroll) - if (scrollView?.canScrollVertically(1) == true) { - binding.bottom.cardElevation = - resources.getDimensionPixelSize(nl.rijksoverheid.ctr.introduction.R.dimen.scroll_view_button_elevation) - .toFloat() - } else { - binding.bottom.cardElevation = 0f - } - - if (viewModel.toolbarButtonsStateLiveData.value?.canGoBack == false) { - if (isFirstItem) { - hideNavigationIcon() - } else { - ContextCompat.getDrawable(requireContext(), R.drawable.ic_back)?.let { - it.setTint(ContextCompat.getColor(requireContext(), R.color.black)) - showNavigationIcon(it) - } - } - } - } - }) - startingItem?.let { binding.viewPager.currentItem = it } - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } - - companion object { - private const val indicatorPositionKey = "indicator_position_key" - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/FuzzyMatchingOnboardingViewModel.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/FuzzyMatchingOnboardingViewModel.kt deleted file mode 100644 index 6468b666c..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/FuzzyMatchingOnboardingViewModel.kt +++ /dev/null @@ -1,16 +0,0 @@ -package nl.rijksoverheid.ctr.holder.fuzzy_matching - -import nl.rijksoverheid.ctr.holder.dashboard.util.GreenCardUtil -import nl.rijksoverheid.ctr.persistence.database.HolderDatabase - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -class FuzzyMatchingOnboardingViewModel( - holderDatabase: HolderDatabase, - greenCardUtil: GreenCardUtil -) : FuzzyMatchingBaseViewModel(holderDatabase, greenCardUtil) diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/FuzzyMatchingSyncFragment.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/FuzzyMatchingSyncFragment.kt deleted file mode 100644 index 93737786f..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/FuzzyMatchingSyncFragment.kt +++ /dev/null @@ -1,99 +0,0 @@ -package nl.rijksoverheid.ctr.holder.fuzzy_matching - -import android.os.Bundle -import android.view.View -import androidx.core.text.HtmlCompat -import androidx.navigation.fragment.navArgs -import nl.rijksoverheid.ctr.design.fragments.info.ButtonData -import nl.rijksoverheid.ctr.design.fragments.info.DescriptionData -import nl.rijksoverheid.ctr.design.fragments.info.InfoFragmentData -import nl.rijksoverheid.ctr.design.fragments.info.InfoFragmentDirections -import nl.rijksoverheid.ctr.design.utils.InfoFragmentUtil -import nl.rijksoverheid.ctr.holder.BaseFragment -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.hideNavigationIcon -import nl.rijksoverheid.ctr.holder.models.HolderFlow -import nl.rijksoverheid.ctr.holder.sync_greencards.SyncGreenCardsViewModel -import nl.rijksoverheid.ctr.persistence.database.DatabaseSyncerResult -import nl.rijksoverheid.ctr.shared.ext.findNavControllerSafety -import nl.rijksoverheid.ctr.shared.livedata.EventObserver -import nl.rijksoverheid.ctr.shared.models.Flow -import org.koin.android.ext.android.inject -import org.koin.androidx.viewmodel.ext.android.viewModel - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -class FuzzyMatchingSyncFragment : BaseFragment(R.layout.fragment_saved_events_sync_green_cards) { - - private val syncGreenCardsViewModel: SyncGreenCardsViewModel by viewModel() - - private val infoFragmentUtil: InfoFragmentUtil by inject() - - private val fuzzyMatchingSyncFragmentArgs: FuzzyMatchingSyncFragmentArgs by navArgs() - - override fun onButtonClickClose() { - findNavControllerSafety()?.popBackStack() - } - - override fun onButtonClickWithRetryAction() { - syncGreenCardsViewModel.refresh() - } - - override fun getFlow(): Flow { - return HolderFlow.FuzzyMatching - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - hideNavigationIcon() - - syncGreenCardsViewModel.refresh() - - syncGreenCardsViewModel.databaseSyncerResultLiveData.observe( - viewLifecycleOwner, - EventObserver { - when (it) { - is DatabaseSyncerResult.Success -> { - val navDirections = InfoFragmentDirections.actionMyOverview() - infoFragmentUtil.presentFullScreen( - currentFragment = this, - data = InfoFragmentData.TitleDescriptionWithButton( - title = getString(R.string.holder_identitySelection_success_title), - descriptionData = DescriptionData( - htmlTextString = getString( - R.string.holder_identitySelection_success_body, - HtmlCompat.fromHtml(fuzzyMatchingSyncFragmentArgs.selectedName, HtmlCompat.FROM_HTML_MODE_LEGACY) - ), - htmlLinksEnabled = true - ), - primaryButtonData = ButtonData.NavigationButton( - text = getString(R.string.back_to_overview), - navigationActionId = navDirections.actionId, - navigationArguments = navDirections.arguments - ) - ), - toolbarTitle = getString(R.string.holder_identitySelection_success_toolbar_title), - hideNavigationIcon = true - ) - } - is DatabaseSyncerResult.Failed -> { - presentError( - errorResult = it.errorResult - ) - } - is DatabaseSyncerResult.FuzzyMatchingError -> { - findNavControllerSafety()?.popBackStack( - R.id.nav_holder_fuzzy_matching, - true - ) - } - } - }) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/HolderNameSelectionFooterAdapterItem.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/HolderNameSelectionFooterAdapterItem.kt deleted file mode 100644 index f1f1d84ff..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/HolderNameSelectionFooterAdapterItem.kt +++ /dev/null @@ -1,32 +0,0 @@ -package nl.rijksoverheid.ctr.holder.fuzzy_matching - -import android.view.View -import com.xwray.groupie.viewbinding.BindableItem -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.databinding.ItemHolderNameSelectionFooterBinding - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -class HolderNameSelectionFooterAdapterItem( - private val onButtonClicked: () -> Unit -) : BindableItem(R.layout.item_holder_name_selection_footer.toLong()) { - - override fun bind(viewBinding: ItemHolderNameSelectionFooterBinding, position: Int) { - viewBinding.holderNameSelectionExplainButton.setOnClickListener { - onButtonClicked() - } - } - - override fun getLayout(): Int { - return R.layout.item_holder_name_selection_footer - } - - override fun initializeViewBinding(view: View): ItemHolderNameSelectionFooterBinding { - return ItemHolderNameSelectionFooterBinding.bind(view) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/HolderNameSelectionFragment.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/HolderNameSelectionFragment.kt deleted file mode 100644 index 70a8d8564..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/HolderNameSelectionFragment.kt +++ /dev/null @@ -1,201 +0,0 @@ -package nl.rijksoverheid.ctr.holder.fuzzy_matching - -import android.os.Bundle -import android.view.View -import androidx.core.text.HtmlCompat -import androidx.fragment.app.Fragment -import androidx.navigation.fragment.findNavController -import androidx.navigation.fragment.navArgs -import androidx.recyclerview.widget.DividerItemDecoration -import androidx.recyclerview.widget.SimpleItemAnimator -import com.google.android.material.divider.MaterialDividerItemDecoration -import com.xwray.groupie.GroupAdapter -import com.xwray.groupie.GroupieViewHolder -import com.xwray.groupie.Section -import nl.rijksoverheid.ctr.design.fragments.info.DescriptionData -import nl.rijksoverheid.ctr.design.fragments.info.InfoFragmentData -import nl.rijksoverheid.ctr.design.utils.DialogUtil -import nl.rijksoverheid.ctr.design.utils.InfoFragmentUtil -import nl.rijksoverheid.ctr.holder.HolderMainFragment -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.databinding.FragmentHolderNameSelectionBinding -import nl.rijksoverheid.ctr.holder.fuzzy_matching.HolderNameSelectionFragmentDirections.Companion.actionSavedEventsSyncGreenCards -import nl.rijksoverheid.ctr.shared.ext.navigateSafety -import org.koin.android.ext.android.inject -import org.koin.androidx.viewmodel.ext.android.viewModel -import org.koin.core.parameter.parametersOf - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -class HolderNameSelectionFragment : Fragment(R.layout.fragment_holder_name_selection) { - private val section = Section() - - private val infoFragmentUtil: InfoFragmentUtil by inject() - private val dialogUtil: DialogUtil by inject() - private val selectionDetailBottomSheetDescriptionUtil: SelectionDetailBottomSheetDescriptionUtil by inject() - private val holderNameSelectionFragmentArgs: HolderNameSelectionFragmentArgs by navArgs() - - private val viewModel: HolderNameSelectionViewModel by viewModel { - parametersOf(holderNameSelectionFragmentArgs.matchingBlobIds.ids) - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - val binding = FragmentHolderNameSelectionBinding.bind(view) - initRecyclerView(binding) - - viewModel.toolbarButtonsStateLiveData.observe(viewLifecycleOwner) { (_, canSkip) -> - if (canSkip) { - addToolbarButton() - } - } - - viewModel.itemsLiveData.observe(viewLifecycleOwner) { - setItems(it, binding) - } - - viewModel.nameSelectionError.observe(viewLifecycleOwner) { noSelectionError -> - if (noSelectionError) { - viewModel.nothingSelectedError() - binding.bottom.showError() - } - } - - binding.bottom.setButtonClick { - viewModel.storeSelection { selectedName -> - navigateSafety( - actionSavedEventsSyncGreenCards( - selectedName = selectedName - ) - ) - } - } - } - - private fun addToolbarButton() { - (parentFragment?.parentFragment as? HolderMainFragment)?.getToolbar().let { toolbar -> - if (toolbar?.menu?.size() == 0) { - toolbar.apply { - inflateMenu(R.menu.fuzzy_matching_toolbar) - - setOnMenuItemClickListener { - if (it.itemId == R.id.skip) { - dialogUtil.presentDialog( - context = requireContext(), - title = R.string.holder_identitySelection_skipAlert_title, - message = getString(R.string.holder_identitySelection_skipAlert_body), - positiveButtonText = R.string.holder_identitySelection_skipAlert_action, - positiveButtonCallback = { - // close fuzzy matching - findNavController().popBackStack( - R.id.nav_holder_fuzzy_matching, - true - ) - }, - negativeButtonText = R.string.general_cancel - ) - } - true - } - } - } - } - } - - private fun resetToolbar() { - (parentFragment?.parentFragment as? HolderMainFragment)?.let { - it.getToolbar().menu.clear() - // Reset menu item listener to default - it.resetMenuItemListener() - } - } - - override fun onResume() { - super.onResume() - viewModel.canSkip(holderNameSelectionFragmentArgs.getEventsFlow) - } - - override fun onPause() { - super.onPause() - resetToolbar() - } - - private fun initRecyclerView(binding: FragmentHolderNameSelectionBinding) { - val adapter = GroupAdapter().also { - it.add(section) - } - binding.recyclerView.adapter = adapter - binding.recyclerView.addItemDecoration( - MaterialDividerItemDecoration( - requireContext(), - DividerItemDecoration.VERTICAL - ).apply { - isLastItemDecorated = false - } - ) - // prevent item decorator flickering when updating recyclerview to its error state - (binding.recyclerView.itemAnimator as? SimpleItemAnimator)?.supportsChangeAnimations = false - } - - private fun setItems( - items: List, - binding: FragmentHolderNameSelectionBinding - ) { - section.update( - items.map { item -> - when (item) { - HolderNameSelectionItem.FooterItem -> HolderNameSelectionFooterAdapterItem { - infoFragmentUtil.presentAsBottomSheet( - fragmentManager = parentFragmentManager, - data = InfoFragmentData.TitleDescription( - title = getString(R.string.holder_fuzzyMatching_why_title), - descriptionData = DescriptionData( - htmlText = R.string.holder_fuzzyMatching_why_body, - htmlLinksEnabled = true - ) - ) - ) - } - HolderNameSelectionItem.HeaderItem -> HolderNameSelectionHeaderAdapterItem() - is HolderNameSelectionItem.ListItem -> HolderNameSelectionViewAdapterItem( - item, - { - val nameText = - getString(R.string.holder_identitySelection_details_body, HtmlCompat.fromHtml(item.name, HtmlCompat.FROM_HTML_MODE_LEGACY)) - val eventsText = selectionDetailBottomSheetDescriptionUtil.get( - selectionDetailData = item.detailData, - separator = " ${getString(R.string.general_and)} " - ) { - if (it.contains("dcc")) { - getString(R.string.holder_identitySelection_details_scannedPaperProof) - } else { - getString( - R.string.holder_storedEvents_listHeader_fetchedFromProvider, - it - ) - } - } - infoFragmentUtil.presentAsBottomSheet( - fragmentManager = parentFragmentManager, - data = InfoFragmentData.TitleDescription( - title = getString(R.string.general_details), - descriptionData = DescriptionData( - htmlTextString = "$nameText $eventsText", - htmlLinksEnabled = true - ) - ) - ) - }) { - binding.bottom.hideError() - viewModel.onItemSelected(item.name) - } - } - } - ) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/HolderNameSelectionHeaderAdapterItem.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/HolderNameSelectionHeaderAdapterItem.kt deleted file mode 100644 index eaf4adabf..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/HolderNameSelectionHeaderAdapterItem.kt +++ /dev/null @@ -1,26 +0,0 @@ -package nl.rijksoverheid.ctr.holder.fuzzy_matching - -import android.view.View -import com.xwray.groupie.viewbinding.BindableItem -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.databinding.ItemHolderNameSelectionHeaderBinding - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -class HolderNameSelectionHeaderAdapterItem : BindableItem(R.layout.item_holder_name_selection_header.toLong()) { - override fun bind(viewBinding: ItemHolderNameSelectionHeaderBinding, position: Int) { - } - - override fun getLayout(): Int { - return R.layout.item_holder_name_selection_header - } - - override fun initializeViewBinding(view: View): ItemHolderNameSelectionHeaderBinding { - return ItemHolderNameSelectionHeaderBinding.bind(view) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/HolderNameSelectionItem.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/HolderNameSelectionItem.kt deleted file mode 100644 index c9e9d5681..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/HolderNameSelectionItem.kt +++ /dev/null @@ -1,23 +0,0 @@ -package nl.rijksoverheid.ctr.holder.fuzzy_matching - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -sealed class HolderNameSelectionItem { - object HeaderItem : HolderNameSelectionItem() - - data class ListItem( - val name: String, - val events: String, - val isSelected: Boolean = false, - val willBeRemoved: Boolean = false, - val nothingSelectedError: Boolean = false, - val detailData: List = listOf() - ) : HolderNameSelectionItem() - - object FooterItem : HolderNameSelectionItem() -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/HolderNameSelectionViewAdapterItem.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/HolderNameSelectionViewAdapterItem.kt deleted file mode 100644 index 42284448d..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/HolderNameSelectionViewAdapterItem.kt +++ /dev/null @@ -1,56 +0,0 @@ -package nl.rijksoverheid.ctr.holder.fuzzy_matching - -import android.content.res.ColorStateList -import android.view.View -import androidx.core.view.isVisible -import com.xwray.groupie.viewbinding.BindableItem -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.databinding.ItemHolderNameSelectionViewBinding - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -class HolderNameSelectionViewAdapterItem( - private val item: HolderNameSelectionItem.ListItem, - private val onDetailsButtonClicked: () -> Unit, - private val onSelected: () -> Unit -) : BindableItem( - R.layout.item_holder_name_selection_view.toLong() -) { - - override fun bind(viewBinding: ItemHolderNameSelectionViewBinding, position: Int) { - viewBinding.radioButton.isChecked = item.isSelected - if (item.nothingSelectedError) { - viewBinding.radioButton.buttonTintList = - ColorStateList.valueOf(viewBinding.radioButton.context.getColor(R.color.error)) - } else { - viewBinding.radioButton.isUseMaterialThemeColors = true - if (!item.isSelected) { - viewBinding.radioButton.buttonTintList = - ColorStateList.valueOf(viewBinding.radioButton.context.getColor(R.color.menu_icon_color)) - } - } - viewBinding.nameTextView.text = item.name - viewBinding.eventsTextView.text = item.events - viewBinding.removedEventTextView.isVisible = item.willBeRemoved - viewBinding.root.setOnClickListener { - onSelected() - } - viewBinding.detailsButton.contentDescription = "${item.name} ${viewBinding.detailsButton.text}" - viewBinding.detailsButton.setOnClickListener { - onDetailsButtonClicked() - } - } - - override fun getLayout(): Int { - return R.layout.item_holder_name_selection_view - } - - override fun initializeViewBinding(view: View): ItemHolderNameSelectionViewBinding { - return ItemHolderNameSelectionViewBinding.bind(view) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/HolderNameSelectionViewModel.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/HolderNameSelectionViewModel.kt deleted file mode 100644 index 263c915d7..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/HolderNameSelectionViewModel.kt +++ /dev/null @@ -1,114 +0,0 @@ -package nl.rijksoverheid.ctr.holder.fuzzy_matching - -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.viewModelScope -import kotlinx.coroutines.launch -import nl.rijksoverheid.ctr.holder.dashboard.util.GreenCardUtil -import nl.rijksoverheid.ctr.holder.get_events.usecases.GetRemoteProtocolFromEventGroupUseCase -import nl.rijksoverheid.ctr.holder.your_events.utils.YourEventsFragmentUtil -import nl.rijksoverheid.ctr.persistence.database.HolderDatabase - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -abstract class HolderNameSelectionViewModel( - holderDatabase: HolderDatabase, - greenCardUtil: GreenCardUtil -) : FuzzyMatchingBaseViewModel(holderDatabase, greenCardUtil) { - val itemsLiveData: LiveData> = MutableLiveData() - val nameSelectionError: LiveData = MutableLiveData() - - abstract fun onItemSelected(selectedName: String) - abstract fun storeSelection(onStored: (String) -> Unit) - abstract fun nothingSelectedError() -} - -class HolderNameSelectionViewModelImpl( - private val matchedEventsUseCase: MatchedEventsUseCase, - private val getRemoteProtocolFromEventGroupUseCase: GetRemoteProtocolFromEventGroupUseCase, - private val selectionDataUtil: SelectionDataUtil, - private val yourEventsFragmentUtil: YourEventsFragmentUtil, - private val holderDatabase: HolderDatabase, - greenCardUtil: GreenCardUtil, - private val matchingBlobIds: List> -) : HolderNameSelectionViewModel(holderDatabase, greenCardUtil) { - - init { - updateItems() - } - - override fun onItemSelected(selectedName: String) { - (nameSelectionError as MutableLiveData).value = false - updateItems(selectedName) - } - - private fun selectedName(): String? { - return itemsLiveData.value - ?.filterIsInstance() - ?.find { it.isSelected } - ?.name - } - - override fun storeSelection(onStored: (String) -> Unit) { - val selectedName = selectedName() - if (selectedName != null) { - val items = itemsLiveData.value?.filterIsInstance() ?: return - val itemSelected = items.find { it.isSelected } - if (itemSelected != null) { - viewModelScope.launch { - matchedEventsUseCase.selected(items.indexOf(itemSelected), matchingBlobIds) - onStored(selectedName) - } - } - } else { - (nameSelectionError as MutableLiveData).value = true - } - } - - override fun nothingSelectedError() { - updateItems(nothingSelectedError = true) - } - - private fun updateItems( - selectedName: String? = null, - nothingSelectedError: Boolean = false - ) { - viewModelScope.launch { - val allEvents = holderDatabase.eventGroupDao().getAll() - val fuzzyMatchedRemoteProtocols = matchingBlobIds.map { eventsCluster -> - eventsCluster.mapNotNull { fuzzyMatchedEventId -> - allEvents.find { it.id == fuzzyMatchedEventId } - }.mapNotNull(getRemoteProtocolFromEventGroupUseCase::get) - } - - val holderNames = fuzzyMatchedRemoteProtocols.map { it.map { yourEventsFragmentUtil.getFullName(it.holder) } } - val selectionItems = fuzzyMatchedRemoteProtocols.mapIndexed { index, remoteProtocols -> - val holders = remoteProtocols.map { it.holder }.map { yourEventsFragmentUtil.getFullName(it) } - val events = remoteProtocols.flatMap { it.events ?: emptyList() }.sortedByDescending { it.getDate() } - val providerIdentifier = remoteProtocols.first().providerIdentifier - // make sure we don't select a name present in other groups - val otherHolderNames = holderNames.filterIndexed { i, _ -> i != index }.flatten() - val name = holders.first { !otherHolderNames.contains(it) } - HolderNameSelectionItem.ListItem( - name = name, - events = selectionDataUtil.events(events), - detailData = selectionDataUtil.details(providerIdentifier, events), - isSelected = name == selectedName, - willBeRemoved = selectedName != null && name != selectedName, - nothingSelectedError = nothingSelectedError - ) - }.toTypedArray() - - (itemsLiveData as MutableLiveData).value = listOf( - HolderNameSelectionItem.HeaderItem, - *selectionItems, - HolderNameSelectionItem.FooterItem - ) - } - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/MatchedEventsUseCase.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/MatchedEventsUseCase.kt deleted file mode 100644 index 72d743757..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/MatchedEventsUseCase.kt +++ /dev/null @@ -1,47 +0,0 @@ -package nl.rijksoverheid.ctr.holder.fuzzy_matching - -import nl.rijksoverheid.ctr.holder.get_events.usecases.GetRemoteProtocolFromEventGroupUseCase -import nl.rijksoverheid.ctr.persistence.database.HolderDatabase -import nl.rijksoverheid.ctr.persistence.database.entities.RemovedEventEntity -import nl.rijksoverheid.ctr.persistence.database.entities.RemovedEventReason - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -interface MatchedEventsUseCase { - suspend fun selected(selectionIndex: Int, matchingBlobIds: List>) -} - -class MatchedEventsUseCaseImpl( - private val getRemoteProtocolFromEventGroupUseCase: GetRemoteProtocolFromEventGroupUseCase, - private val holderDatabase: HolderDatabase -) : MatchedEventsUseCase { - override suspend fun selected(selectionIndex: Int, matchingBlobIds: List>) { - val eventIdsToDelete = matchingBlobIds.filterIndexed { index, _ -> - index != selectionIndex - }.flatten().toSet().filter { !matchingBlobIds[selectionIndex].contains(it) } - - holderDatabase.eventGroupDao().getAllOfIds(eventIdsToDelete).forEach { eventGroupEntity -> - val remoteProtocol = getRemoteProtocolFromEventGroupUseCase.get(eventGroupEntity) - remoteProtocol?.events?.forEach { remoteEvent -> - holderDatabase.removedEventDao().insert( - RemovedEventEntity( - walletId = eventGroupEntity.walletId, - type = eventGroupEntity.type.getTypeString(), - eventTime = remoteEvent.getDate(), - reason = RemovedEventReason.FuzzyMatched - ) - ) - } - } - - val unDraftEventsIds = matchingBlobIds.flatten().toSet().minus(eventIdsToDelete.toSet()) - - holderDatabase.eventGroupDao().deleteAllOfIds(eventIdsToDelete) - holderDatabase.eventGroupDao().updateDraft(unDraftEventsIds.toList(), false) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/MatchingBlobIds.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/MatchingBlobIds.kt deleted file mode 100644 index 747ea147f..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/MatchingBlobIds.kt +++ /dev/null @@ -1,14 +0,0 @@ -package nl.rijksoverheid.ctr.holder.fuzzy_matching - -import android.os.Parcelable -import kotlinx.parcelize.Parcelize - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -@Parcelize -data class MatchingBlobIds(val ids: List>) : Parcelable diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/SelectionDataUtil.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/SelectionDataUtil.kt deleted file mode 100644 index 3b80e5304..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/SelectionDataUtil.kt +++ /dev/null @@ -1,108 +0,0 @@ -package nl.rijksoverheid.ctr.holder.fuzzy_matching - -import nl.rijksoverheid.ctr.appconfig.usecases.CachedAppConfigUseCase -import nl.rijksoverheid.ctr.design.ext.formatDayMonthYear -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEvent -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEvent.Companion.TYPE_NEGATIVE_TEST -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEvent.Companion.TYPE_POSITIVE_TEST -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEvent.Companion.TYPE_RECOVERY -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEvent.Companion.TYPE_TEST -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEvent.Companion.TYPE_VACCINATION -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEventVaccination -import nl.rijksoverheid.ctr.holder.your_events.utils.RemoteEventStringUtil -import nl.rijksoverheid.ctr.holder.your_events.utils.YourEventsFragmentUtil - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -interface SelectionDataUtil { - fun events(remoteEvents: List): String - fun details( - providerIdentifier: String, - remoteEvents: List - ): List -} - -class SelectionDataUtilImpl( - private val cachedAppConfigUseCase: CachedAppConfigUseCase, - private val yourEventsFragmentUtil: YourEventsFragmentUtil, - private val remoteEventStringUtil: RemoteEventStringUtil, - private val getQuantityString: (Int, Int) -> String, - private val getFormattedString: (Int, String) -> String, - private val getString: (Int) -> String -) : SelectionDataUtil { - - override fun events(remoteEvents: List): String { - val testResultTypes = listOf(TYPE_NEGATIVE_TEST, TYPE_POSITIVE_TEST, TYPE_RECOVERY, TYPE_TEST) - val vaccinationCount = remoteEvents.filter { it.type == TYPE_VACCINATION }.size - val testCount = remoteEvents.filter { testResultTypes.contains(it.type) }.size - - val eventsString = StringBuilder() - - if (vaccinationCount > 0) { - eventsString.append( - "$vaccinationCount ${ - getQuantityString( - R.plurals.general_vaccinations, - vaccinationCount - ) - }" - ) - } - if (testCount > 0) { - if (eventsString.isNotEmpty()) { - eventsString.append(" ${getString(R.string.general_and)} ") - } - eventsString.append( - "$testCount ${ - getQuantityString( - R.plurals.general_testresults, - testCount - ) - }" - ) - } - - return eventsString.toString() - } - - override fun details( - providerIdentifier: String, - remoteEvents: List - ): List { - val configProviders = cachedAppConfigUseCase.getCachedAppConfig().providers - - val data = remoteEvents.map { event -> - val eventDate = event.getDate() - SelectionDetailData( - type = "${remoteEventStringUtil.remoteEventTitle(event.javaClass)}${ - if (providerIdentifier.startsWith("dcc") && event is RemoteEventVaccination) { - val dose = event.vaccination?.doseNumber - val totalDoses = event.vaccination?.totalDoses - if (dose != null && totalDoses != null) { - " ${getFormattedString(R.string.your_vaccination_explanation_dose, "$dose/$totalDoses")}" - } else { - "" - } - } else { - "" - } - }", - providerIdentifiers = listOf( - yourEventsFragmentUtil.getProviderName( - configProviders, - providerIdentifier - ) - ), - eventDate = eventDate?.toLocalDate()?.formatDayMonthYear() ?: "" - ) - } - - return data - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/SelectionDetailBottomSheetDescriptionUtil.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/SelectionDetailBottomSheetDescriptionUtil.kt deleted file mode 100644 index 5dfc85ccf..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/SelectionDetailBottomSheetDescriptionUtil.kt +++ /dev/null @@ -1,34 +0,0 @@ -package nl.rijksoverheid.ctr.holder.fuzzy_matching - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -interface SelectionDetailBottomSheetDescriptionUtil { - fun get( - selectionDetailData: List, - separator: String, - retrievedBy: (String) -> String - ): String -} - -class SelectionDetailBottomSheetDescriptionUtilImpl() : SelectionDetailBottomSheetDescriptionUtil { - override fun get( - selectionDetailData: List, - separator: String, - retrievedBy: (String) -> String - ): String { - val description = StringBuilder("

") - - selectionDetailData.forEach { - description.append("${it.type}
") - description.append("${retrievedBy(it.providerIdentifiers.joinToString(separator))}
") - description.append("${it.eventDate}

") - } - - return description.toString() - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/SelectionDetailData.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/SelectionDetailData.kt deleted file mode 100644 index 0efab56dc..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/SelectionDetailData.kt +++ /dev/null @@ -1,14 +0,0 @@ -package nl.rijksoverheid.ctr.holder.fuzzy_matching - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -data class SelectionDetailData( - val type: String, - val providerIdentifiers: List, - val eventDate: String -) diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/ToolbarButtonsState.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/ToolbarButtonsState.kt deleted file mode 100644 index eb2505749..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/fuzzy_matching/ToolbarButtonsState.kt +++ /dev/null @@ -1,10 +0,0 @@ -package nl.rijksoverheid.ctr.holder.fuzzy_matching - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -data class ToolbarButtonsState(val canGoBack: Boolean, val canSkip: Boolean) diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/DigiDFragment.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/DigiDFragment.kt deleted file mode 100644 index 0096fdfc4..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/DigiDFragment.kt +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.get_events - -import android.os.Bundle -import android.view.View -import nl.rijksoverheid.ctr.design.fragments.info.ButtonData -import nl.rijksoverheid.ctr.design.fragments.info.DescriptionData -import nl.rijksoverheid.ctr.design.fragments.info.InfoFragmentData -import nl.rijksoverheid.ctr.design.fragments.info.InfoFragmentDirections -import nl.rijksoverheid.ctr.design.utils.DialogButtonData -import nl.rijksoverheid.ctr.design.utils.DialogFragmentData -import nl.rijksoverheid.ctr.design.utils.InfoFragmentUtil -import nl.rijksoverheid.ctr.design.utils.SharedDialogFragmentDirections -import nl.rijksoverheid.ctr.holder.BaseFragment -import nl.rijksoverheid.ctr.holder.HolderMainFragment -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.get_events.models.EventProvider -import nl.rijksoverheid.ctr.holder.get_events.models.EventsResult -import nl.rijksoverheid.ctr.holder.get_events.models.LoginType -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteOriginType -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteProtocol -import nl.rijksoverheid.ctr.holder.get_events.utils.LoginTypeUtil -import nl.rijksoverheid.ctr.holder.your_events.YourEventsFragmentType -import nl.rijksoverheid.ctr.shared.livedata.EventObserver -import nl.rijksoverheid.ctr.shared.models.ErrorResult -import nl.rijksoverheid.ctr.shared.models.ErrorResultFragmentData -import org.koin.android.ext.android.inject -import org.koin.androidx.viewmodel.ext.android.viewModel - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -abstract class DigiDFragment(contentLayoutId: Int) : BaseFragment(contentLayoutId) { - - private val infoFragmentUtil: InfoFragmentUtil by inject() - private val loginTypeUtil: LoginTypeUtil by inject() - private val getEventsViewModel: GetEventsViewModel by viewModel() - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - val copy = getCopyForOriginType() - - getEventsViewModel.eventsResult.observe(viewLifecycleOwner, EventObserver { - when (it) { - is EventsResult.Success -> { - if (it.missingEvents) { - val yourEventsDestination = SharedDialogFragmentDirections.actionYourEvents( - toolbarTitle = getCopyForOriginType().toolbarTitle, - type = yourEventsFragmentType( - remoteProtocols = it.remoteEvents, - eventProviders = it.eventProviders - ), - flow = getFlow() - ) - openDialog( - data = DialogFragmentData( - title = getDialogTitleFromOriginType(getOriginTypes().first()), - message = R.string.error_get_events_missing_events_dialog_description, - positiveButtonData = DialogButtonData.NavigationButton( - textId = R.string.dialog_close, - navigationActionId = yourEventsDestination.actionId, - navigationArguments = yourEventsDestination.arguments - ) - ) - ) - dialogPresented() - } else { - onNavigateToYourEvents( - remoteProtocols = it.remoteEvents, - eventProviders = it.eventProviders - ) - } - } - is EventsResult.HasNoEvents -> { - if (it.missingEvents) { - presentError( - data = ErrorResultFragmentData( - title = getString(R.string.error_get_events_no_events_title), - description = getString( - R.string.error_get_events_http_error_description, - getErrorCodes(it.errorResults) - ), - buttonTitle = getString(R.string.back_to_overview), - ErrorResultFragmentData.ButtonAction.Destination(R.id.action_my_overview), - urlData = ErrorResultFragmentData.UrlData( - urlButtonTitle = getString(R.string.error_something_went_wrong_outage_button), - urlButtonUrl = getString(R.string.error_something_went_wrong_outage_button_url) - ) - ) - ) - } else { - val navDirections = InfoFragmentDirections.actionMyOverview() - infoFragmentUtil.presentFullScreen( - currentFragment = this, - infoFragmentDirections = GetEventsFragmentDirections.actionInfoFragment( - toolbarTitle = copy.toolbarTitle, - data = InfoFragmentData.TitleDescriptionWithButton( - title = copy.hasNoEventsTitle, - descriptionData = DescriptionData( - htmlTextString = copy.hasNoEventsDescription, - htmlLinksEnabled = true - ), - primaryButtonData = ButtonData.NavigationButton( - text = getString(R.string.back_to_overview), - navigationActionId = navDirections.actionId, - navigationArguments = navDirections.arguments - ) - ) - ) - ) - } - } - is EventsResult.Error -> { - when { - it.accessTokenSessionExpiredError() -> { - presentError( - data = ErrorResultFragmentData( - title = getString(R.string.error_access_tokens_session_expired_title), - description = getString(R.string.error_access_tokens_Session_expired_description), - buttonTitle = getString(R.string.error_access_tokens_session_expired_button), - ErrorResultFragmentData.ButtonAction.PopBackStack - ) - ) - } - it.accessTokenNoBsn() -> { - presentError( - data = ErrorResultFragmentData( - title = getString(R.string.error_access_tokens_no_bsn_title), - description = getString(R.string.error_access_tokens_no_bsn_description), - buttonTitle = getString(R.string.back_to_overview), - buttonAction = ErrorResultFragmentData.ButtonAction.Destination( - R.id.action_my_overview - ) - ) - ) - } - it.unomiOrEventErrors() -> { - presentError( - it.errorResults.first(), - getString( - R.string.error_get_events_http_error_description, - getErrorCodes(it.errorResults) - ) - ) - } - else -> { - presentError(it.errorResults.first()) - } - } - } - } - }) - - getEventsViewModel.loading.observe(viewLifecycleOwner, EventObserver { - onGetEventsLoading(it) - }) - } - - fun loginWithDigiD() { - - } - - private fun getErrorCodes(errorResults: List): String { - return errorCodeStringFactory.get( - flow = getFlow(), - errorResults = errorResults - ) - } - - private fun getDialogTitleFromOriginType(originType: RemoteOriginType): Int { - return when (originType) { - RemoteOriginType.Recovery -> R.string.error_get_events_missing_events_dialog_title_recoveries - RemoteOriginType.Test -> R.string.error_get_events_missing_events_dialog_title_testresults - RemoteOriginType.Vaccination -> R.string.error_get_events_missing_events_dialog_title_vaccines - } - } - - protected fun getCopyForOriginType(): GetEventsFragmentCopy { - when (getOriginTypes().first()) { - is RemoteOriginType.Test -> { - return GetEventsFragmentCopy( - title = getString(R.string.holder_negativetest_ggd_title), - description = getString(R.string.holder_negativetest_ggd_message), - toolbarTitle = getString(R.string.your_negative_test_results_header), - hasNoEventsTitle = getString(R.string.no_test_results_title), - hasNoEventsDescription = getString(R.string.no_test_results_description) - ) - } - is RemoteOriginType.Vaccination -> { - return GetEventsFragmentCopy( - title = getString(R.string.holder_addVaccination_title), - description = getString(R.string.holder_addVaccination_message), - toolbarTitle = getString(R.string.your_vaccination_result_toolbar_title), - hasNoEventsTitle = getString(R.string.no_vaccinations_title), - hasNoEventsDescription = getString(R.string.no_vaccinations_description) - ) - } - is RemoteOriginType.Recovery -> { - return GetEventsFragmentCopy( - title = getString(R.string.get_recovery_title), - description = getString(R.string.get_recovery_description), - toolbarTitle = getString(R.string.your_positive_test_toolbar_title), - hasNoEventsTitle = getString(R.string.no_positive_test_result_title), - hasNoEventsDescription = getString(R.string.no_positive_test_result_description) - ) - } - } - } - - abstract fun getLoginType(): LoginType - abstract fun onDigidLoading(loading: Boolean) - abstract fun onGetEventsLoading(loading: Boolean) - abstract fun getOriginTypes(): List - abstract fun onNavigateToYourEvents( - remoteProtocols: Map, - eventProviders: List = emptyList() - ) - - abstract fun dialogPresented() - abstract fun yourEventsFragmentType( - remoteProtocols: Map, - eventProviders: List - ): YourEventsFragmentType - - abstract fun openDialog(data: DialogFragmentData) -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/GetEventsFragment.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/GetEventsFragment.kt deleted file mode 100644 index 271ef7e85..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/GetEventsFragment.kt +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.get_events - -import android.os.Bundle -import android.view.View -import androidx.core.view.isVisible -import androidx.navigation.fragment.navArgs -import nl.rijksoverheid.ctr.design.utils.DialogFragmentData -import nl.rijksoverheid.ctr.holder.HolderMainFragment -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.databinding.FragmentGetEventsBinding -import nl.rijksoverheid.ctr.holder.get_events.models.EventProvider -import nl.rijksoverheid.ctr.holder.get_events.models.LoginType -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteOriginType -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteProtocol -import nl.rijksoverheid.ctr.holder.models.HolderFlow -import nl.rijksoverheid.ctr.holder.no_digid.NoDigidFragmentData -import nl.rijksoverheid.ctr.holder.no_digid.NoDigidScreenDataUtil -import nl.rijksoverheid.ctr.holder.your_events.YourEventsFragmentType -import nl.rijksoverheid.ctr.shared.ext.navigateSafety -import nl.rijksoverheid.ctr.shared.models.Flow -import nl.rijksoverheid.ctr.shared.utils.Accessibility.makeIndeterminateAccessible -import org.koin.android.ext.android.inject - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -class GetEventsFragment : DigiDFragment(R.layout.fragment_get_events) { - - private val args: GetEventsFragmentArgs by navArgs() - private var _binding: FragmentGetEventsBinding? = null - private val binding get() = _binding!! - private val noDigidScreenDataUtil: NoDigidScreenDataUtil by inject() - - override fun onButtonClickWithRetryAction() { - loginWithDigiD() - } - - override fun getFlow(): Flow { - return when (args.originType) { - RemoteOriginType.Recovery -> HolderFlow.Recovery - RemoteOriginType.Test -> HolderFlow.DigidTest - RemoteOriginType.Vaccination -> HolderFlow.Vaccination - } - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - _binding = FragmentGetEventsBinding.bind(view) - super.onViewCreated(view, savedInstanceState) - setBindings() - } - - override fun getLoginType(): LoginType { - return LoginType.Max - } - - private fun setBindings() { - val copy = getCopyForOriginType() - - binding.title.text = copy.title - binding.description.setHtmlText(copy.description, htmlLinksEnabled = true) - binding.button.setOnClickListener { - onButtonClickWithRetryAction() - } - binding.noDigidButton.setOnClickListener { - if (args.originType == RemoteOriginType.Vaccination) { - navigateSafety( - GetEventsFragmentDirections.actionNoDigid( - NoDigidFragmentData( - title = getString(R.string.holder_noDigiD_title), - description = getString(R.string.holder_noDigiD_message), - firstNavigationButtonData = noDigidScreenDataUtil.requestDigidButton(), - secondNavigationButtonData = noDigidScreenDataUtil.continueWithoutDigidButton( - args.originType - ), - originType = args.originType - ) - ) - ) - } else { - navigateSafety( - GetEventsFragmentDirections.actionPap(args.originType) - ) - } - } - - if (args.originType == RemoteOriginType.Vaccination) { - binding.checkboxWithHeader.visibility = View.VISIBLE - binding.checkboxWithHeader.header(R.string.holder_addVaccination_alsoCollectPositiveTestResults_message) - } - } - - override fun onDestroyView() { - super.onDestroyView() - (parentFragment?.parentFragment as HolderMainFragment).presentLoading(false) - } - - override fun onDigidLoading(loading: Boolean) { - binding.button.isEnabled = !loading - binding.checkboxWithHeader.binding.checkbox.isEnabled = !loading - } - - override fun onGetEventsLoading(loading: Boolean) { - if (loading) { - binding.loadingOverlay.progressBar.makeIndeterminateAccessible( - context = requireContext(), - isLoading = true, - message = R.string.holder_fetchevents_loading - ) - binding.loadingOverlay.root.isVisible = true - } - } - - override fun getOriginTypes(): List { - val originTypes = mutableListOf() - originTypes.add(args.originType) - if (binding.checkboxWithHeader.binding.checkbox.isChecked) { - originTypes.add(RemoteOriginType.Recovery) - } - return originTypes - } - - override fun onNavigateToYourEvents( - remoteProtocols: Map, - eventProviders: List - ) { - val flow = getFlow() - val checkedPositiveTest = binding.checkboxWithHeader.binding.checkbox.isChecked - navigateSafety( - GetEventsFragmentDirections.actionYourEvents( - type = YourEventsFragmentType.RemoteProtocol3Type( - remoteEvents = remoteProtocols, - eventProviders = eventProviders - ), - toolbarTitle = getCopyForOriginType().toolbarTitle, - flow = if (flow == HolderFlow.Vaccination && checkedPositiveTest) { - HolderFlow.VaccinationAndPositiveTest - } else { - flow - } - ) - ) - } - - override fun yourEventsFragmentType( - remoteProtocols: Map, - eventProviders: List - ): YourEventsFragmentType { - return YourEventsFragmentType.RemoteProtocol3Type( - remoteEvents = remoteProtocols, - eventProviders = eventProviders - ) - } - - override fun dialogPresented() { - binding.loadingOverlay.progressBar.makeIndeterminateAccessible( - context = requireContext(), - isLoading = false, - message = R.string.holder_fetchevents_loading - ) - binding.loadingOverlay.root.isVisible = false - } - - override fun openDialog(data: DialogFragmentData) { - navigateSafety(GetEventsFragmentDirections.actionDialog(data)) - } -} - -data class GetEventsFragmentCopy( - val title: String, - val description: String, - val toolbarTitle: String, - val hasNoEventsTitle: String, - val hasNoEventsDescription: String -) diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/GetEventsViewModel.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/GetEventsViewModel.kt deleted file mode 100644 index ede5fe7aa..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/GetEventsViewModel.kt +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.get_events - -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import kotlinx.coroutines.launch -import nl.rijksoverheid.ctr.holder.get_events.models.EventsResult -import nl.rijksoverheid.ctr.holder.get_events.models.LoginType -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteOriginType -import nl.rijksoverheid.ctr.holder.get_events.usecases.ConfigProvidersUseCase -import nl.rijksoverheid.ctr.holder.get_events.usecases.GetEventsUseCase -import nl.rijksoverheid.ctr.holder.get_events.usecases.GetMijnCnEventsUsecase -import nl.rijksoverheid.ctr.shared.livedata.Event - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -abstract class GetEventsViewModel : ViewModel() { - val loading: LiveData> = MutableLiveData() - val eventsResult: LiveData> = MutableLiveData() - - abstract fun getDigidEvents( - loginType: LoginType, - jwt: String, - originTypes: List, - getPositiveTestWithVaccination: Boolean = false - ) - - abstract fun getMijnCnEvents( - jwt: String, - originType: RemoteOriginType, - getPositiveTestWithVaccination: Boolean = false - ) -} - -class GetEventsViewModelImpl( - private val configProvidersUseCase: ConfigProvidersUseCase, - private val getEventsUseCase: GetEventsUseCase, - private val mijnCnEventsUsecase: GetMijnCnEventsUsecase -) : GetEventsViewModel() { - - override fun getDigidEvents( - loginType: LoginType, - jwt: String, - originTypes: List, - getPositiveTestWithVaccination: Boolean - ) { - getEvents { - getEventsUseCase.getEvents( - eventProvidersResult = configProvidersUseCase.eventProviders(), - loginType = loginType, - jwt = jwt, - originTypes = originTypes - ) - } - } - - override fun getMijnCnEvents( - jwt: String, - originType: RemoteOriginType, - getPositiveTestWithVaccination: Boolean - ) { - getEvents { - mijnCnEventsUsecase.getEvents( - jwt = jwt, - originType = originType, - withIncompleteVaccination = getPositiveTestWithVaccination - ) - } - } - - fun getEvents(function: suspend () -> EventsResult) { - (loading as MutableLiveData).value = Event(true) - viewModelScope.launch { - try { - val events = function.invoke() - (eventsResult as MutableLiveData).value = Event(events) - } finally { - loading.value = Event(false) - } - } - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/LoginResult.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/LoginResult.kt deleted file mode 100644 index e86925add..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/LoginResult.kt +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.get_events - -import nl.rijksoverheid.ctr.shared.models.ErrorResult - -sealed class LoginResult { - data class Success(val jwt: String) : LoginResult() - data class Failed(val errorResult: ErrorResult) : LoginResult() - object Cancelled : LoginResult() - object NoBrowserFound : LoginResult() -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/LoginViewModel.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/LoginViewModel.kt deleted file mode 100644 index bc38b684b..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/LoginViewModel.kt +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.get_events - -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import nl.rijksoverheid.ctr.shared.livedata.Event -import nl.rijksoverheid.ctr.shared.utils.AndroidUtil - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -class LoginViewModel( - private val androidUtil: AndroidUtil -) : ViewModel() { - - val loading: LiveData> = MutableLiveData() - val loginResultLiveData = MutableLiveData>() -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/EventProvider.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/EventProvider.kt deleted file mode 100644 index e73b58117..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/EventProvider.kt +++ /dev/null @@ -1,14 +0,0 @@ -package nl.rijksoverheid.ctr.holder.get_events.models - -import android.os.Parcelable -import kotlinx.parcelize.Parcelize - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -@Parcelize -data class EventProvider(val identifier: String, val name: String) : Parcelable diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/EventsResult.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/EventsResult.kt deleted file mode 100644 index 7c5faeca6..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/EventsResult.kt +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.get_events.models - -import nl.rijksoverheid.ctr.holder.models.HolderStep -import nl.rijksoverheid.ctr.shared.exceptions.NoProvidersException -import nl.rijksoverheid.ctr.shared.models.ErrorResult -import nl.rijksoverheid.ctr.shared.models.NetworkRequestResult - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ - -sealed class EventsResult { - data class Success( - val remoteEvents: Map, - val missingEvents: Boolean, - val eventProviders: List - ) : EventsResult() - - data class HasNoEvents(val missingEvents: Boolean, val errorResults: List = emptyList()) : EventsResult() - - data class Error constructor(val errorResults: List) : EventsResult() { - constructor(errorResult: ErrorResult) : this(listOf(errorResult)) - - fun accessTokenSessionExpiredError(): Boolean { - val accessTokenCallError = errorResults.find { it.getCurrentStep() == HolderStep.AccessTokensNetworkRequest } - accessTokenCallError?.let { - return hasErrorCode(it, 99710) - } - return false - } - - fun accessTokenNoBsn(): Boolean { - val accessTokenCallError = errorResults.find { it.getCurrentStep() == HolderStep.AccessTokensNetworkRequest } - accessTokenCallError?.let { - return hasErrorCode(it, 99782) - } - return false - } - - private fun hasErrorCode(errorResult: ErrorResult, expectedErrorCode: Int): Boolean { - return if (errorResult is NetworkRequestResult.Failed.CoronaCheckWithErrorResponseHttpError) { - errorResult.getCode() == expectedErrorCode - } else { - false - } - } - - fun unomiOrEventErrors(): Boolean { - val unomiOrEventErrors = errorResults.find { it.getCurrentStep() == HolderStep.UnomiNetworkRequest || it.getCurrentStep() == HolderStep.EventNetworkRequest } - return unomiOrEventErrors != null - } - - fun isMijnCnMissingDataErrors(): Boolean { - val returnedError = errorResults.find { it.getCurrentStep() == HolderStep.EventNetworkRequest } - returnedError?.let { errorResult -> - return errorResult is NetworkRequestResult.Failed.CoronaCheckWithErrorResponseHttpError && errorResult.getCode() in 777706..777716 - } - return false - } - - companion object { - fun noProvidersError(originType: RemoteOriginType) = Error(object : ErrorResult { - override fun getCurrentStep() = HolderStep.ConfigProvidersNetworkRequest - - override fun getException() = when (originType) { - RemoteOriginType.Recovery -> NoProvidersException.Recovery - RemoteOriginType.Test -> NoProvidersException.Test - RemoteOriginType.Vaccination -> NoProvidersException.Vaccination - } - }) - } - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/Holder.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/Holder.kt deleted file mode 100644 index 677045a17..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/Holder.kt +++ /dev/null @@ -1,21 +0,0 @@ -package nl.rijksoverheid.ctr.holder.get_events.models - -import android.os.Parcelable -import com.squareup.moshi.JsonClass -import kotlinx.parcelize.Parcelize - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -@Parcelize -@JsonClass(generateAdapter = true) -data class Holder( - val firstNameInitial: String, - val lastNameInitial: String, - val birthDay: String, - val birthMonth: String -) : Parcelable diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/LoginType.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/LoginType.kt deleted file mode 100644 index 5913677d4..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/LoginType.kt +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.get_events.models - -sealed class LoginType { - object Max : LoginType() - object Pap : LoginType() -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/MijnCNTokenResponse.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/MijnCNTokenResponse.kt deleted file mode 100644 index a00236944..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/MijnCNTokenResponse.kt +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ - -package nl.rijksoverheid.ctr.holder.get_events.models - -import com.squareup.moshi.Json -import com.squareup.moshi.JsonClass - -@JsonClass(generateAdapter = true) -data class MijnCNTokenResponse( - @Json(name = "access_token") val accessToken: String, - @Json(name = "token_type") val tokenType: String, - @Json(name = "expires_in") val expiresIn: Int, - @Json(name = "id_token") val idToken: String -) diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/RemoteAccessTokens.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/RemoteAccessTokens.kt deleted file mode 100644 index 44aa5db73..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/RemoteAccessTokens.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.get_events.models - -import com.squareup.moshi.Json -import com.squareup.moshi.JsonClass - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -@JsonClass(generateAdapter = true) -data class RemoteAccessTokens( - val tokens: List = listOf() -) { - @JsonClass(generateAdapter = true) - data class Token( - @Json(name = "provider_identifier") val providerIdentifier: String, - @Json(name = "unomi") val unomi: String, - @Json(name = "event") val event: String - ) -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/RemoteConfigProviders.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/RemoteConfigProviders.kt deleted file mode 100644 index 82cd62951..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/RemoteConfigProviders.kt +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.get_events.models - -import com.squareup.moshi.Json -import com.squareup.moshi.JsonClass - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -@JsonClass(generateAdapter = true) -data class RemoteConfigProviders( - @Json(name = "tokenProviders") val testProviders: List, - @Json(name = "eventProviders") val eventProviders: List, - @Json(name = "eventProvidersBes") val eventProvidersBes: List -) { - - @JsonClass(generateAdapter = true) - data class TestProvider( - val name: String, - @Json(name = "identifier") val providerIdentifier: String, - @Json(name = "url") val resultUrl: String, - @Json(name = "cms") val cms: List, - @Json(name = "tls") val tls: List, - @Json(name = "usage") val usage: List - ) { - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false - - other as TestProvider - - if (name != other.name) return false - if (providerIdentifier != other.providerIdentifier) return false - if (resultUrl != other.resultUrl) return false - if (!cms.first().contentEquals(other.cms.first())) return false - - return true - } - - override fun hashCode(): Int { - var result = name.hashCode() - result = 31 * result + providerIdentifier.hashCode() - result = 31 * result + resultUrl.hashCode() - result = 31 * result + cms.first().contentHashCode() - return result - } - } - - data class EventProvider( - val name: String, - @Json(name = "identifier") val providerIdentifier: String, - @Json(name = "unomiUrl") val unomiUrl: String, - @Json(name = "eventUrl") val eventUrl: String, - val cms: List, - val tls: List, - val usage: List, - val auth: List - ) { - fun supports(originType: RemoteOriginType, loginType: LoginType): Boolean { - return when (originType) { - RemoteOriginType.Recovery -> usage.contains("r") && auth.contains(getAuthForLoginType(loginType)) - RemoteOriginType.Test -> (usage.contains("nt") || usage.contains("pt")) && auth.contains(getAuthForLoginType(loginType)) - RemoteOriginType.Vaccination -> usage.contains("v") && auth.contains(getAuthForLoginType(loginType)) - } - } - - private fun getAuthForLoginType(loginType: LoginType): String { - return when (loginType) { - is LoginType.Pap -> "pap" - is LoginType.Max -> "max" - } - } - - companion object { - const val PROVIDER_IDENTIFIER_DCC = "dcc" - const val PROVIDER_IDENTIFIER_DCC_SUFFIX = "dcc_[unique]" - } - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false - - other as EventProvider - - if (name != other.name) return false - if (providerIdentifier != other.providerIdentifier) return false - if (unomiUrl != other.unomiUrl) return false - if (eventUrl != other.eventUrl) return false - if (!cms.first().contentEquals(other.cms.first())) return false - if (!tls.first().contentEquals(other.tls.first())) return false - - return true - } - - override fun hashCode(): Int { - var result = name.hashCode() - result = 31 * result + providerIdentifier.hashCode() - result = 31 * result + unomiUrl.hashCode() - result = 31 * result + eventUrl.hashCode() - result = 31 * result + cms.first().contentHashCode() - result = 31 * result + tls.first().contentHashCode() - return result - } - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/RemoteEvent.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/RemoteEvent.kt deleted file mode 100644 index 405f45a72..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/RemoteEvent.kt +++ /dev/null @@ -1,28 +0,0 @@ -package nl.rijksoverheid.ctr.holder.get_events.models - -import android.os.Parcelable -import java.time.OffsetDateTime - -abstract class RemoteEvent(open val unique: String?, open val type: String?) : Parcelable { - - companion object { - const val TYPE_VACCINATION = "vaccination" - const val TYPE_NEGATIVE_TEST = "negativetest" - const val TYPE_POSITIVE_TEST = "positivetest" - const val TYPE_RECOVERY = "recovery" - const val TYPE_TEST = "test" - - fun getRemoteEventClassFromType(type: String): Class { - return when (type) { - "positivetest" -> RemoteEventPositiveTest::class.java - "recovery" -> RemoteEventRecovery::class.java - "negativetest" -> RemoteEventNegativeTest::class.java - "test" -> RemoteEventNegativeTest::class.java - "vaccination" -> RemoteEventVaccination::class.java - else -> RemoteEvent::class.java - } - } - } - - abstract fun getDate(): OffsetDateTime? -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/RemoteEventNegativeTest.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/RemoteEventNegativeTest.kt deleted file mode 100644 index 65125d530..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/RemoteEventNegativeTest.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.get_events.models - -import android.os.Parcelable -import com.squareup.moshi.Json -import com.squareup.moshi.JsonClass -import java.time.OffsetDateTime -import kotlinx.parcelize.Parcelize - -@Parcelize -@JsonClass(generateAdapter = true) -data class RemoteEventNegativeTest( - override val type: String?, - override val unique: String?, - val isSpecimen: Boolean?, - @Json(name = "negativetest") val negativeTest: NegativeTest? -) : Parcelable, RemoteEvent(unique, type) { - - @Parcelize - @JsonClass(generateAdapter = true) - data class NegativeTest( - val sampleDate: OffsetDateTime?, - val negativeResult: Boolean?, - val facility: String?, - val type: String?, - val name: String?, - val country: String?, - val manufacturer: String? - ) : Parcelable - - override fun getDate(): OffsetDateTime? { - return negativeTest?.sampleDate - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/RemoteEventPositiveTest.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/RemoteEventPositiveTest.kt deleted file mode 100644 index 4cfa75ce6..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/RemoteEventPositiveTest.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.get_events.models - -import android.os.Parcelable -import com.squareup.moshi.Json -import com.squareup.moshi.JsonClass -import java.time.OffsetDateTime -import kotlinx.parcelize.Parcelize - -@Parcelize -@JsonClass(generateAdapter = true) -data class RemoteEventPositiveTest( - override val type: String?, - override val unique: String?, - val isSpecimen: Boolean?, - @Json(name = "positivetest") val positiveTest: PositiveTest? -) : Parcelable, RemoteEvent(unique, type) { - - @Parcelize - @JsonClass(generateAdapter = true) - data class PositiveTest( - val sampleDate: OffsetDateTime?, - val positiveResult: Boolean?, - val facility: String?, - val type: String?, - val name: String?, - val country: String?, - val manufacturer: String? - ) : Parcelable - - override fun getDate(): OffsetDateTime? { - return positiveTest?.sampleDate - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/RemoteEventRecovery.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/RemoteEventRecovery.kt deleted file mode 100644 index 4deaa942c..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/RemoteEventRecovery.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.get_events.models - -import android.os.Parcelable -import com.squareup.moshi.Json -import com.squareup.moshi.JsonClass -import java.time.LocalDate -import java.time.OffsetDateTime -import java.time.ZoneOffset -import kotlinx.parcelize.Parcelize - -@Parcelize -@JsonClass(generateAdapter = true) -data class RemoteEventRecovery( - override val type: String?, - override val unique: String, - val isSpecimen: Boolean, - @Json(name = "recovery") val recovery: Recovery? -) : Parcelable, RemoteEvent(unique, type) { - - @Parcelize - @JsonClass(generateAdapter = true) - data class Recovery( - val sampleDate: LocalDate?, - val validFrom: LocalDate?, - val validUntil: LocalDate?, - val country: String? - ) : Parcelable - - override fun getDate(): OffsetDateTime? { - return recovery?.sampleDate?.atStartOfDay()?.atOffset(ZoneOffset.UTC) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/RemoteEventVaccination.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/RemoteEventVaccination.kt deleted file mode 100644 index 07fab70b2..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/RemoteEventVaccination.kt +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.get_events.models - -import android.os.Parcelable -import com.squareup.moshi.Json -import com.squareup.moshi.JsonClass -import java.time.LocalDate -import java.time.OffsetDateTime -import java.time.ZoneOffset -import kotlinx.parcelize.Parcelize - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -@Parcelize -@JsonClass(generateAdapter = true) -data class RemoteEventVaccination( - override val type: String?, - override val unique: String?, - @Json(name = "vaccination") val vaccination: Vaccination? -) : Parcelable, RemoteEvent(unique, type) { - - @Parcelize - @JsonClass(generateAdapter = true) - data class Vaccination( - val date: LocalDate?, - val hpkCode: String?, - val type: String?, - val brand: String?, - val completedByMedicalStatement: Boolean?, - val completedByPersonalStatement: Boolean?, - val completionReason: String?, - val doseNumber: String?, - val totalDoses: String?, - val country: String?, - val manufacturer: String? - ) : Parcelable - - override fun getDate(): OffsetDateTime? { - return vaccination?.date?.atStartOfDay()?.atOffset(ZoneOffset.UTC) - } - - override fun equals(other: Any?): Boolean { - val otherVaccination = (other as? RemoteEventVaccination)?.vaccination ?: return false - return this.vaccination?.date == otherVaccination.date && - ((this.vaccination?.hpkCode != null && otherVaccination.hpkCode != null && this.vaccination.hpkCode == otherVaccination.hpkCode) || - (this.vaccination?.manufacturer != null && otherVaccination.manufacturer != null && this.vaccination.manufacturer == otherVaccination.manufacturer)) - } - - override fun hashCode(): Int { - return vaccination?.date.hashCode() - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/RemoteOriginType.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/RemoteOriginType.kt deleted file mode 100644 index ed4dfbc02..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/RemoteOriginType.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.get_events.models - -import android.os.Parcelable -import kotlinx.parcelize.Parcelize -import nl.rijksoverheid.ctr.persistence.database.entities.OriginType - -/** - * Types of origins that we communicate with the backend. - * The difference with [OriginType] is that this is used for sending - * and [OriginType] for retrieving from backend and database - */ -sealed class RemoteOriginType : Parcelable { - - @Parcelize - object Vaccination : RemoteOriginType(), Parcelable - - @Parcelize - object Recovery : RemoteOriginType(), Parcelable - - @Parcelize - object Test : RemoteOriginType(), Parcelable - - fun toOriginType(): OriginType { - return when (this) { - is Vaccination -> OriginType.Vaccination - is Recovery -> OriginType.Recovery - is Test -> OriginType.Test - } - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/RemoteProtocol.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/RemoteProtocol.kt deleted file mode 100644 index 8e37de159..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/RemoteProtocol.kt +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.get_events.models - -import android.os.Parcelable -import com.squareup.moshi.JsonClass -import kotlinx.parcelize.Parcelize - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -@Parcelize -data class RemoteProtocol( - val providerIdentifier: String, - val protocolVersion: String, - val status: Status, - val holder: Holder?, - val events: List? -) : Parcelable { - - @Parcelize - @JsonClass(generateAdapter = true) - data class Holder( - val infix: String?, - val firstName: String?, - val lastName: String?, - val birthDate: String? - ) : Parcelable - - fun hasEvents(): Boolean { - return events?.isNotEmpty() ?: false - } - - enum class Status(val apiStatus: String) { - UNKNOWN(""), - PENDING("pending"), - INVALID_TOKEN("invalid_token"), - VERIFICATION_REQUIRED("verification_required"), - RESULT_BLOCKED("result_blocked"), - COMPLETE("complete"); - - companion object { - fun fromValue(value: String?): Status { - return values().firstOrNull { it.apiStatus == value } ?: UNKNOWN - } - } - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/RemoteUnomi.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/RemoteUnomi.kt deleted file mode 100644 index 6039c8c8b..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/models/RemoteUnomi.kt +++ /dev/null @@ -1,17 +0,0 @@ -package nl.rijksoverheid.ctr.holder.get_events.models - -import com.squareup.moshi.JsonClass - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -@JsonClass(generateAdapter = true) -data class RemoteUnomi( - val protocolVersion: String, - val providerIdentifier: String, - val informationAvailable: Boolean -) diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/usecases/ConfigProvidersUseCase.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/usecases/ConfigProvidersUseCase.kt deleted file mode 100644 index a462c92cd..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/usecases/ConfigProvidersUseCase.kt +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.get_events.usecases - -import nl.rijksoverheid.ctr.holder.api.repositories.CoronaCheckRepository -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteConfigProviders -import nl.rijksoverheid.ctr.shared.models.ErrorResult -import nl.rijksoverheid.ctr.shared.models.NetworkRequestResult - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -interface ConfigProvidersUseCase { - suspend fun eventProviders(): EventProvidersResult - suspend fun eventProvidersBES(): EventProvidersResult - suspend fun testProviders(): TestProvidersResult -} - -class ConfigProvidersUseCaseImpl(private val coronaCheckRepository: CoronaCheckRepository) : - ConfigProvidersUseCase { - - override suspend fun testProviders(): TestProvidersResult { - return when (val result = coronaCheckRepository.configProviders()) { - is NetworkRequestResult.Success -> TestProvidersResult.Success( - result.response.testProviders - ) - is NetworkRequestResult.Failed -> TestProvidersResult.Error(result) - } - } - - override suspend fun eventProviders(): EventProvidersResult { - return when (val result = coronaCheckRepository.configProviders()) { - is NetworkRequestResult.Success -> { - EventProvidersResult.Success(result.response.eventProviders) - } - is NetworkRequestResult.Failed -> EventProvidersResult.Error(result) - } - } - - override suspend fun eventProvidersBES(): EventProvidersResult { - return when (val result = coronaCheckRepository.configProviders()) { - is NetworkRequestResult.Success -> { - EventProvidersResult.Success(result.response.eventProvidersBes) - } - is NetworkRequestResult.Failed -> EventProvidersResult.Error(result) - } - } -} - -sealed class TestProvidersResult { - class Success(val testProviders: List) : - TestProvidersResult() - - class Error(val errorResult: ErrorResult) : TestProvidersResult() -} - -sealed class EventProvidersResult { - class Success(val eventProviders: List) : - EventProvidersResult() - - class Error(val errorResult: ErrorResult) : EventProvidersResult() -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/usecases/GetEventProvidersWithTokensUseCase.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/usecases/GetEventProvidersWithTokensUseCase.kt deleted file mode 100644 index 73b343363..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/usecases/GetEventProvidersWithTokensUseCase.kt +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.get_events.usecases - -import android.annotation.SuppressLint -import nl.rijksoverheid.ctr.holder.api.repositories.EventProviderRepository -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteAccessTokens -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteConfigProviders -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteUnomi -import nl.rijksoverheid.ctr.persistence.database.entities.OriginType -import nl.rijksoverheid.ctr.shared.ext.filterNotNullValues -import nl.rijksoverheid.ctr.shared.ext.parallelMap -import nl.rijksoverheid.ctr.shared.models.ErrorResult -import nl.rijksoverheid.ctr.shared.models.NetworkRequestResult - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ - -/** - * Get all event providers that have events for the [OriginType] - */ -interface GetEventProvidersWithTokensUseCase { - - /** - * @param eventProviders A list of all the event providers - * @param tokens A list of all tokens - * @param filter events to filter by type - * @param scope optional parameter to specify the scope of the filter - * @param targetProviderIds used to filter on specific target providers - */ - suspend fun get( - eventProviders: List, - tokens: List, - filter: String, - scope: String?, - targetProviderIds: List? = null - ): List -} - -class GetEventProvidersWithTokensUseCaseImpl( - private val eventProviderRepository: EventProviderRepository -) : GetEventProvidersWithTokensUseCase { - - @SuppressLint("DefaultLocale") - override suspend fun get( - eventProviders: List, - tokens: List, - filter: String, - scope: String?, - targetProviderIds: List? - ): List { - - // Map event providers to tokens - val allEventProvidersWithTokens = - eventProviders - .associateWith { eventProvider -> - tokens - .firstOrNull { eventProvider.providerIdentifier == it.providerIdentifier } - } - .filterNotNullValues() - - // If we want to only target specific providers ids we filter others out - val targetEventProvidersWithTokens = allEventProvidersWithTokens.filter { - targetProviderIds?.contains(it.key.providerIdentifier.lowercase()) ?: true - } - - return targetEventProvidersWithTokens.toList().parallelMap { - val eventProvider = it.first - val token = it.second - - val unomiResult = eventProviderRepository.getUnomi( - url = eventProvider.unomiUrl, - token = token.unomi, - filter = filter, - scope = scope, - signingCertificateBytes = eventProvider.cms, - provider = eventProvider.providerIdentifier, - tlsCertificateBytes = eventProvider.tls - ) - - when (unomiResult) { - is NetworkRequestResult.Success -> { - if (unomiResult.response.informationAvailable) { - EventProviderWithTokenResult.Success( - eventProvider = eventProvider, - token = token - ) - } else { - null - } - } - is NetworkRequestResult.Failed -> EventProviderWithTokenResult.Error(unomiResult) - } - }.filterNotNull() - } -} - -sealed class EventProviderWithTokenResult { - data class Success( - val eventProvider: RemoteConfigProviders.EventProvider, - val token: RemoteAccessTokens.Token - ) : EventProviderWithTokenResult() - - data class Error(val errorResult: ErrorResult) : EventProviderWithTokenResult() -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/usecases/GetEventsUseCase.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/usecases/GetEventsUseCase.kt deleted file mode 100644 index 7936b7f4e..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/usecases/GetEventsUseCase.kt +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.get_events.usecases - -import nl.rijksoverheid.ctr.holder.api.repositories.CoronaCheckRepository -import nl.rijksoverheid.ctr.holder.api.repositories.EventProviderRepository -import nl.rijksoverheid.ctr.holder.get_events.models.EventProvider -import nl.rijksoverheid.ctr.holder.get_events.models.EventsResult -import nl.rijksoverheid.ctr.holder.get_events.models.LoginType -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteAccessTokens -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteOriginType -import nl.rijksoverheid.ctr.holder.get_events.utils.ScopeUtil -import nl.rijksoverheid.ctr.persistence.database.entities.OriginType -import nl.rijksoverheid.ctr.shared.ext.parallelMap -import nl.rijksoverheid.ctr.shared.models.ErrorResult -import nl.rijksoverheid.ctr.shared.models.NetworkRequestResult - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ - -/** - * Get events for a specific [OriginType] - * This is the entry point class for getting Events and will take care of: - * - getting all event providers - * - getting tokens based on JWT - * - getting events at event providers - * - map result to success or error states - */ -interface GetEventsUseCase { - suspend fun getEvents( - eventProvidersResult: EventProvidersResult, - jwt: String, - originTypes: List, - loginType: LoginType - ): EventsResult -} - -class GetEventsUseCaseImpl( - private val coronaCheckRepository: CoronaCheckRepository, - private val getEventProvidersWithTokensUseCase: GetEventProvidersWithTokensUseCase, - private val getRemoteEventsUseCase: GetRemoteEventsUseCase, - private val scopeUtil: ScopeUtil -) : GetEventsUseCase { - - override suspend fun getEvents( - eventProvidersResult: EventProvidersResult, - jwt: String, - originTypes: List, - loginType: LoginType - ): EventsResult { - - val (tokens, remoteEventProviders) = when (eventProvidersResult) { - is EventProvidersResult.Error -> return EventsResult.Error(eventProvidersResult.errorResult) - is EventProvidersResult.Success -> { - when (loginType) { - is LoginType.Pap -> { - val fakeRemoteAccessTokens = RemoteAccessTokens( - tokens = eventProvidersResult.eventProviders.map { - RemoteAccessTokens.Token( - providerIdentifier = it.providerIdentifier, - unomi = jwt, - event = jwt - ) - } - ) - Pair( - fakeRemoteAccessTokens, - eventProvidersResult.eventProviders - ) - } - is LoginType.Max -> { - when (val tokensResult = coronaCheckRepository.accessTokens(jwt)) { - is NetworkRequestResult.Failed -> return EventsResult.Error(tokensResult) - is NetworkRequestResult.Success -> Pair( - tokensResult.response, - eventProvidersResult.eventProviders - ) - } - } - } - } - } - val eventProviders = eventProvidersResult.eventProviders - - val eventProviderWithTokensResults = - mutableMapOf>() - - val eventsResults = originTypes.parallelMap { originType -> - val targetProviderIds = eventProviders.filter { - it.supports(originType, loginType) - }.map { it.providerIdentifier.lowercase() } - - if (targetProviderIds.isEmpty()) { - return@parallelMap EventsResult.Error.noProvidersError(originType) - } - - val filter = EventProviderRepository.getFilter(originType) - - val scope = scopeUtil.getScopeForRemoteOriginType( - remoteOriginType = originType, - getPositiveTestWithVaccination = originTypes.size > 1 - ) - - // Fetch event providers that have events for us - eventProviderWithTokensResults[originType] = getEventProvidersWithTokensUseCase.get( - eventProviders = eventProviders, - tokens = tokens.tokens, - filter = filter, - scope = scope, - targetProviderIds = targetProviderIds - ) - } - - val eventsResultsErrors = eventsResults.filterIsInstance() - if (eventsResultsErrors.isNotEmpty()) { - return eventsResultsErrors.first() - } - - val eventProvidersWithTokensSuccessResults = - eventProviderWithTokensResults.mapValues { - it.value.filterIsInstance() - }.filterValues { it.isNotEmpty() } - val eventProvidersWithTokensErrorResults = - eventProviderWithTokensResults.values.flatten() - .filterIsInstance() - - return if (eventProvidersWithTokensSuccessResults.isNotEmpty()) { - val eventResults = mutableMapOf>() - eventProvidersWithTokensSuccessResults.forEach { (originType, eventProviders) -> - // We have received providers that claim to have events for us so we get those events for each provider - val events = eventProviders.map { - getRemoteEventsUseCase.getRemoteEvents( - eventProvider = it.eventProvider, - token = it.token, - filter = EventProviderRepository.getFilter(originType), - scope = scopeUtil.getScopeForRemoteOriginType( - remoteOriginType = originType, - getPositiveTestWithVaccination = originTypes.size > 1 - ) - ) - } - eventResults[originType] = events - } - - // All successful responses - val eventSuccessResults = - eventResults.mapValues { - it.value.filterIsInstance() - } - // All failed responses - val eventFailureResults = - eventResults.values.flatten().filterIsInstance() - - if (eventSuccessResults.flatMap { it.value }.isNotEmpty()) { - // If we have success responses - val signedModels = eventSuccessResults - .mapValues { events -> - events.value - .map { it.signedModel } - .filter { it.model.hasEvents() } - } - .filterValues { it.isNotEmpty() } - - if (signedModels.isEmpty()) { - // But we do not have any events - val missingEvents = - eventProvidersWithTokensErrorResults.isNotEmpty() || eventFailureResults.isNotEmpty() - val errorResults: List = if (missingEvents) { - eventProvidersWithTokensErrorResults.map { it.errorResult } + eventFailureResults.map { it.errorResult } - } else { - emptyList() - } - EventsResult.HasNoEvents( - missingEvents = missingEvents, - errorResults = errorResults - ) - } else { - // We do have events - EventsResult.Success( - remoteEvents = signedModels.map { - it.value.associate { signedModel -> - signedModel.model to signedModel.rawResponse - } - }.fold(mapOf()) { protocol, byteArray -> protocol + byteArray }, - missingEvents = eventProvidersWithTokensErrorResults.isNotEmpty() || eventFailureResults.isNotEmpty(), - eventProviders = remoteEventProviders.map { - EventProvider( - it.providerIdentifier, - it.name - ) - } - ) - } - } else { - // We don't have any successful responses from retrieving events for providers - EventsResult.Error(eventFailureResults.map { it.errorResult }) - } - } else { - if (eventProvidersWithTokensErrorResults.isEmpty()) { - // There are no successful responses and no error responses so no events - EventsResult.HasNoEvents(missingEvents = false) - } else { - // We don't have any successful responses but do have error responses - EventsResult.Error(eventProvidersWithTokensErrorResults.map { it.errorResult }) - } - } - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/usecases/GetMijnCnEventsUsecase.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/usecases/GetMijnCnEventsUsecase.kt deleted file mode 100644 index 51831a388..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/usecases/GetMijnCnEventsUsecase.kt +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.get_events.usecases - -import nl.rijksoverheid.ctr.holder.api.repositories.EventProviderRepository -import nl.rijksoverheid.ctr.holder.get_events.models.EventProvider -import nl.rijksoverheid.ctr.holder.get_events.models.EventsResult -import nl.rijksoverheid.ctr.holder.get_events.models.LoginType -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteAccessTokens -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteOriginType -import nl.rijksoverheid.ctr.holder.get_events.utils.ScopeUtil -import nl.rijksoverheid.ctr.persistence.database.entities.OriginType -import nl.rijksoverheid.ctr.shared.models.ErrorResult - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ - -/** - * Get events for a specific [OriginType] - * This is the entry point class for getting Events and will take care of: - * - getting all event providers - * - getting tokens based on JWT - * - getting events at event providers - * - map result to success or error states - */ -interface GetMijnCnEventsUsecase { - suspend fun getEvents( - jwt: String, - originType: RemoteOriginType, - withIncompleteVaccination: Boolean - ): EventsResult -} - -class GetMijnCnEventsUsecaseImpl( - private val configProvidersUseCase: ConfigProvidersUseCase, - private val getRemoteEventsUseCase: GetRemoteEventsUseCase, - private val scopeUtil: ScopeUtil -) : GetMijnCnEventsUsecase { - - override suspend fun getEvents( - jwt: String, - originType: RemoteOriginType, - withIncompleteVaccination: Boolean - ): EventsResult { - // Fetch event providers - val eventProvidersResult = configProvidersUseCase.eventProvidersBES() - when (eventProvidersResult) { - is EventProvidersResult.Error -> return EventsResult.Error(eventProvidersResult.errorResult) - is EventProvidersResult.Success -> { - eventProvidersResult.eventProviders - } - } - - val eventProviders = eventProvidersResult.eventProviders - val targetProviderIds = eventProviders.filter { - // TODO Support LoginType MijnCN - it.supports(originType, LoginType.Max) - }.map { it.providerIdentifier.lowercase() } - - if (targetProviderIds.isEmpty()) { - return EventsResult.Error.noProvidersError(originType) - } - - return if (eventProviders.isNotEmpty()) { - // We have received providers that claim to have events for us so we get those events for each provider - val filter = EventProviderRepository.getFilter(originType) - val scope = scopeUtil.getScopeForRemoteOriginType( - remoteOriginType = originType, - getPositiveTestWithVaccination = withIncompleteVaccination - ) - - val eventResults = eventProviders.map { eventProvider -> - getRemoteEventsUseCase.getRemoteEvents( - eventProvider = eventProvider, - token = RemoteAccessTokens.Token( - providerIdentifier = eventProvider.providerIdentifier, - unomi = "", - event = jwt - ), - filter = filter, - scope = scope - ) - } - - // All successful responses - val eventSuccessResults = - eventResults.filterIsInstance() - - // All failed responses - val eventFailureResults = - eventResults.filterIsInstance() - - if (eventSuccessResults.isNotEmpty()) { - // If we have success responses - val signedModels = eventSuccessResults.map { it.signedModel } - val allEvents = signedModels.map { it.model }.mapNotNull { it.events }.flatten() - val hasEvents = allEvents.isNotEmpty() - - if (!hasEvents) { - // But we do not have any events - val missingEvents = eventFailureResults.isNotEmpty() - val errorResults: List = if (missingEvents) { - eventFailureResults.map { it.errorResult } - } else { - emptyList() - } - EventsResult.HasNoEvents( - missingEvents = missingEvents, - errorResults = errorResults - ) - } else { - // We do have events - EventsResult.Success( - remoteEvents = signedModels.associate { signedModel -> - signedModel.model to signedModel.rawResponse - }, - missingEvents = eventFailureResults.isNotEmpty(), - eventProviders = eventProviders.map { - EventProvider( - it.providerIdentifier, - it.name - ) - } - ) - } - } else { - // We don't have any successful responses from retrieving events for providers - EventsResult.Error(eventFailureResults.map { it.errorResult }) - } - } else { - if (eventProviders.isEmpty()) { - // There are no successful responses and no error responses so no events - EventsResult.HasNoEvents(missingEvents = false) - } else { - // We don't have any successful responses but do have error responses - EventsResult.Error((eventProvidersResult as EventProvidersResult.Error).errorResult) - } - } - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/usecases/GetRemoteEventsUseCase.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/usecases/GetRemoteEventsUseCase.kt deleted file mode 100644 index 1284e7102..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/usecases/GetRemoteEventsUseCase.kt +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.get_events.usecases - -import nl.rijksoverheid.ctr.holder.api.models.SignedResponseWithModel -import nl.rijksoverheid.ctr.holder.api.repositories.EventProviderRepository -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteAccessTokens -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteConfigProviders -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteProtocol -import nl.rijksoverheid.ctr.shared.models.ErrorResult -import nl.rijksoverheid.ctr.shared.models.NetworkRequestResult - -/** - * Get events for a event provider - */ -interface GetRemoteEventsUseCase { - suspend fun getRemoteEvents( - eventProvider: RemoteConfigProviders.EventProvider, - filter: String, - scope: String?, - token: RemoteAccessTokens.Token - ): RemoteEventsResult -} - -class GetRemoteEventsUseCaseImpl(private val eventProviderRepository: EventProviderRepository) : - GetRemoteEventsUseCase { - - override suspend fun getRemoteEvents( - eventProvider: RemoteConfigProviders.EventProvider, - filter: String, - scope: String?, - token: RemoteAccessTokens.Token - ): RemoteEventsResult { - - return when (val eventsResult = eventProviderRepository - .getEvents( - url = eventProvider.eventUrl, - token = token.event, - filter = filter, - scope = scope, - signingCertificateBytes = eventProvider.cms, - provider = eventProvider.providerIdentifier, - tlsCertificateBytes = eventProvider.tls - )) { - - is NetworkRequestResult.Success> -> - RemoteEventsResult.Success(eventsResult.response) - is NetworkRequestResult.Failed -> { - RemoteEventsResult.Error(eventsResult) - } - } - } -} - -sealed class RemoteEventsResult { - data class Success(val signedModel: SignedResponseWithModel) : - RemoteEventsResult() - - data class Error(val errorResult: ErrorResult) : RemoteEventsResult() -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/usecases/GetRemoteProtocolFromEventGroupUseCase.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/usecases/GetRemoteProtocolFromEventGroupUseCase.kt deleted file mode 100644 index 58469a974..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/usecases/GetRemoteProtocolFromEventGroupUseCase.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.get_events.usecases - -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteProtocol -import nl.rijksoverheid.ctr.holder.paper_proof.usecases.GetEventsFromPaperProofQrUseCase -import nl.rijksoverheid.ctr.holder.your_events.utils.RemoteEventUtil -import nl.rijksoverheid.ctr.persistence.database.entities.EventGroupEntity -import org.json.JSONObject - -interface GetRemoteProtocolFromEventGroupUseCase { - fun get(eventGroup: EventGroupEntity): RemoteProtocol? -} - -class GetRemoteProtocolFromEventGroupUseCaseImpl( - private val remoteEventUtil: RemoteEventUtil, - private val getEventsFromPaperProofQrUseCase: GetEventsFromPaperProofQrUseCase -) : GetRemoteProtocolFromEventGroupUseCase { - - override fun get(eventGroup: EventGroupEntity): RemoteProtocol? { - val isDccEvent = remoteEventUtil.isDccEvent( - providerIdentifier = eventGroup.providerIdentifier - ) - - return if (isDccEvent) { - val credential = - JSONObject(eventGroup.jsonData.decodeToString()).getString("credential") - getEventsFromPaperProofQrUseCase.get(credential) - } else { - remoteEventUtil.getRemoteProtocol3FromNonDcc( - eventGroupEntity = eventGroup - ) - } - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/usecases/PersistBlockedEventsUseCase.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/usecases/PersistBlockedEventsUseCase.kt deleted file mode 100644 index 581a886f6..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/usecases/PersistBlockedEventsUseCase.kt +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.get_events.usecases - -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEvent -import nl.rijksoverheid.ctr.persistence.database.HolderDatabase -import nl.rijksoverheid.ctr.persistence.database.entities.RemovedEventEntity -import nl.rijksoverheid.ctr.persistence.database.entities.RemovedEventReason - -interface PersistBlockedEventsUseCase { - suspend fun persist( - newEvents: List, - removedEvents: List, - reason: RemovedEventReason - ) -} - -class PersistBlockedEventsUseCaseImpl( - private val holderDatabase: HolderDatabase -) : PersistBlockedEventsUseCase { - - override suspend fun persist( - newEvents: List, - removedEvents: List, - reason: RemovedEventReason - ) { - val eventsToPersist = removedEvents.filter { !newEvents.contains(it) } - eventsToPersist.forEach { remoteEvent -> - val removedEventEntity = RemovedEventEntity( - walletId = 1, - type = remoteEvent.type ?: "", - eventTime = remoteEvent.getDate(), - reason = reason - ) - - holderDatabase.removedEventDao().insert(removedEventEntity) - } - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/utils/LoginTypeUtil.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/utils/LoginTypeUtil.kt deleted file mode 100644 index 545c4b1f8..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/utils/LoginTypeUtil.kt +++ /dev/null @@ -1,53 +0,0 @@ -package nl.rijksoverheid.ctr.holder.get_events.utils - -import androidx.annotation.StringRes -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.get_events.models.LoginType -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteOriginType - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -interface LoginTypeUtil { - @StringRes - fun getCanceledDialogTitle(loginType: LoginType): Int - @StringRes - fun getCanceledDialogDescription(loginType: LoginType, originType: RemoteOriginType): Int - @StringRes - fun getNoBrowserDialogDescription(loginType: LoginType): Int -} - -class LoginTypeUtilImpl : LoginTypeUtil { - override fun getCanceledDialogTitle(loginType: LoginType): Int { - return when (loginType) { - LoginType.Max -> R.string.holder_authentication_popup_digid_title - LoginType.Pap -> R.string.holder_authentication_popup_portal_title - } - } - - override fun getCanceledDialogDescription(loginType: LoginType, originType: RemoteOriginType): Int { - return when (loginType) { - LoginType.Max -> if (originType == RemoteOriginType.Vaccination) { - R.string.holder_authentication_popup_digid_message_vaccinationFlow - } else { - R.string.holder_authentication_popup_digid_message_testFlow - } - LoginType.Pap -> if (originType == RemoteOriginType.Vaccination) { - R.string.holder_authentication_popup_portal_message_vaccinationFlow - } else { - R.string.holder_authentication_popup_portal_message_testFlow - } - } - } - - override fun getNoBrowserDialogDescription(loginType: LoginType): Int { - return when (loginType) { - LoginType.Max -> R.string.holder_authentication_popup_digid - LoginType.Pap -> R.string.holder_authentication_popup_portal - } - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/utils/ScopeUtil.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/utils/ScopeUtil.kt deleted file mode 100644 index 62b4d64fe..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/get_events/utils/ScopeUtil.kt +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.get_events.utils - -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteOriginType -import nl.rijksoverheid.ctr.persistence.database.entities.OriginType - -interface ScopeUtil { - - fun getScopeForRemoteOriginType( - remoteOriginType: RemoteOriginType, - getPositiveTestWithVaccination: Boolean - ): String - - fun getScopeForOriginType( - originType: OriginType, - getPositiveTestWithVaccination: Boolean - ): String -} - -class ScopeUtilImpl : ScopeUtil { - - override fun getScopeForRemoteOriginType( - remoteOriginType: RemoteOriginType, - getPositiveTestWithVaccination: Boolean - ): String { - return getScopeForOriginType( - originType = remoteOriginType.toOriginType(), - getPositiveTestWithVaccination = getPositiveTestWithVaccination - ) - } - - override fun getScopeForOriginType( - originType: OriginType, - getPositiveTestWithVaccination: Boolean - ): String { - return if (originType is OriginType.Recovery) { - return if (getPositiveTestWithVaccination) { - "firstepisode" - } else { - "recovery" - } - } else { - "" - } - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/input_token/CommercialTestInputTokenFragment.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/input_token/CommercialTestInputTokenFragment.kt deleted file mode 100644 index f7f7d81c2..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/input_token/CommercialTestInputTokenFragment.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.input_token - -import androidx.navigation.fragment.findNavController -import androidx.navigation.fragment.navArgs -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.input_token.usecases.TestResult -import nl.rijksoverheid.ctr.holder.models.HolderFlow -import nl.rijksoverheid.ctr.holder.your_events.YourEventsFragmentType -import nl.rijksoverheid.ctr.shared.models.Flow - -class CommercialTestInputTokenFragment : InputTokenFragment() { - - private val args: CommercialTestInputTokenFragmentArgs by navArgs() - - override fun getFlow(): Flow { - return HolderFlow.CommercialTest - } - - override fun getFragmentData(): InputTokenFragmentData { - return InputTokenFragmentData.CommercialTest - } - - override fun navigateCouldNotCreateQr() { - CommercialTestInputTokenFragmentDirections.actionCouldNotCreateQr( - toolbarTitle = getString(getFragmentData().noResultScreenToolbarTitle), - title = getString(getFragmentData().noResultScreenTitle), - description = getString(getFragmentData().noResultScreenDescription), - buttonTitle = getString(R.string.back_to_overview) - ) - } - - override fun navigateMyEvents(result: TestResult.NegativeTestResult) { - findNavController().navigate( - CommercialTestInputTokenFragmentDirections.actionYourEvents( - type = YourEventsFragmentType.RemoteProtocol3Type( - remoteEvents = mapOf(result.remoteTestResult to result.signedResponseWithTestResult.rawResponse) - ), - flow = HolderFlow.CommercialTest, - toolbarTitle = getString(R.string.your_negative_test_results_toolbar) - ) - ) - } - - override fun getDeeplinkToken(): String? { - return args.token - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/input_token/InputTokenFragment.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/input_token/InputTokenFragment.kt deleted file mode 100644 index 81e45756a..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/input_token/InputTokenFragment.kt +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.input_token - -import android.os.Bundle -import android.text.InputFilter -import android.view.View -import android.view.inputmethod.EditorInfo -import androidx.annotation.StringRes -import androidx.core.view.isVisible -import androidx.core.widget.addTextChangedListener -import nl.rijksoverheid.ctr.design.fragments.info.DescriptionData -import nl.rijksoverheid.ctr.design.fragments.info.InfoFragmentData -import nl.rijksoverheid.ctr.design.utils.DialogUtil -import nl.rijksoverheid.ctr.design.utils.InfoFragmentUtil -import nl.rijksoverheid.ctr.holder.BaseFragment -import nl.rijksoverheid.ctr.holder.HolderMainFragment -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.databinding.FragmentInputTokenBinding -import nl.rijksoverheid.ctr.holder.input_token.usecases.TestResult -import nl.rijksoverheid.ctr.shared.ext.hideKeyboard -import nl.rijksoverheid.ctr.shared.ext.showKeyboard -import nl.rijksoverheid.ctr.shared.livedata.EventObserver -import nl.rijksoverheid.ctr.shared.utils.Accessibility -import org.koin.android.ext.android.inject -import org.koin.androidx.viewmodel.ext.android.stateViewModel -import org.koin.androidx.viewmodel.scope.emptyState - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -abstract class InputTokenFragment : BaseFragment(R.layout.fragment_input_token) { - - private var _binding: FragmentInputTokenBinding? = null - private val binding get() = _binding!! - private val viewModel: InputTokenViewModel by stateViewModel( - state = emptyState() - ) - - private val dialogUtil: DialogUtil by inject() - private val infoFragmentUtil: InfoFragmentUtil by inject() - - override fun onButtonClickWithRetryAction() { - fetchTestResults(binding) - } - - private fun setCopies() { - val data = getFragmentData() - - binding.description.text = getString(data.description) - binding.uniqueCodeInput.hint = getString(data.uniqueCodeInputHeader) - binding.noTokenReceivedBtn.text = getString(data.noCodeText) - binding.noTokenReceivedBtn.contentDescription = getString(data.noCodeText) - binding.bottom.setButtonText(getString(data.buttonText)) - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - _binding = FragmentInputTokenBinding.bind(view) - - binding.uniqueCodeText.filters = arrayOf(InputFilter.AllCaps()) - binding.uniqueCodeText.addTextChangedListener { - viewModel.testCode = it?.toString()?.uppercase() ?: "" - } - - binding.verificationCodeText.addTextChangedListener { - if (binding.verificationCodeInput.isVisible) { - viewModel.verificationCode = it.toString().takeIf { it.isNotEmpty() } - } - } - - setCopies() - - viewModel.viewState.observe(viewLifecycleOwner) { - binding.uniqueCodeText.imeOptions = - (if (it.verificationRequired) EditorInfo.IME_ACTION_NEXT else EditorInfo.IME_ACTION_SEND) - binding.verificationCodeInput.visibility = - if (it.verificationRequired) View.VISIBLE else View.GONE - binding.noVerificationRecievedBtn.visibility = - if (it.verificationRequired) View.VISIBLE else View.GONE - binding.noTokenReceivedBtn.visibility = - if (!it.verificationRequired) View.VISIBLE else View.GONE - - // Start with empty text for possible empty field error when field is visible - if (it.verificationRequired && viewModel.verificationCode == null) { - viewModel.verificationCode = "" - } - - if (it.fromDeeplink && it.verificationRequired) { - binding.uniqueCodeInput.isVisible = false - binding.noTokenReceivedBtn.isVisible = false - binding.description.setText(getFragmentData().descriptionDeeplink) - } - - binding.uniqueCodeText.setHint( - if (Accessibility.screenReader(context)) { - getFragmentData().uniqueCodeInputHintScreenReader - } else { - getFragmentData().uniqueCodeInputHint - } - ) - } - - binding.uniqueCodeText.setOnEditorActionListener { _, actionId, _ -> - if (actionId == EditorInfo.IME_ACTION_SEND && !viewModel.verificationRequired) { - fetchTestResults(binding) - true - } else { - false - } - } - - viewModel.testResult.observe(viewLifecycleOwner, EventObserver { - when (it) { - is TestResult.EmptyToken -> showTokenError(getFragmentData().noUniqueCodeEntered) - is TestResult.InvalidToken -> showTokenError(getFragmentData().invalidTokenText) - is TestResult.ResultBlocked -> showTokenError(R.string.holder_inputRetrievalCode_error_blocked) - is TestResult.UnknownTestProvider -> showTokenError(R.string.commercial_test_error_unknown_test_provider) - is TestResult.NegativeTestResult -> showNegativeTestResult(it) - is TestResult.NoNegativeTestResult -> { - navigateCouldNotCreateQr() - } - is TestResult.Pending -> { - navigateCouldNotCreateQr() - } - is TestResult.VerificationRequired -> { - // If we come here a second time, it means the inputted verification code is not valid - if (binding.verificationCodeText.text?.isNotEmpty() == true) { - binding.verificationCodeInput.error = getString(R.string.commercial_test_error_invalid_combination) - } - binding.verificationCodeInput.requestFocus() - } - is TestResult.EmptyVerificationCode -> { - binding.verificationCodeInput.error = getString(R.string.commercial_test_error_empty_verification_code) - } - is TestResult.Error -> { - presentError(it.errorResult) - } - } - }) - - // Show dialog to send verification code again - binding.noVerificationRecievedBtn.setOnClickListener { - dialogUtil.presentDialog( - context = requireContext(), - title = R.string.dialog_verification_code_title, - message = getString(R.string.dialog_verification_code_message), - positiveButtonText = R.string.dialog_verification_code_positive_button, - positiveButtonCallback = { - viewModel.sendVerificationCode() - }, - negativeButtonText = R.string.dialog_close - ) - } - - binding.bottom.setButtonClick { - onButtonClickWithRetryAction() - } - - // If a location token is set, automatically fill it in. Else we show the keyboard focussing on first code input field - getDeeplinkToken()?.let { token -> - // Only run this once. If the token has been handled once don't try to retrieve a testresult automatically again. - if (viewModel.testCode.isEmpty()) { - binding.uniqueCodeText.setText(token) - fetchTestResults(binding, fromDeeplink = true) - } - } ?: showKeyboard(binding.uniqueCodeText) - - viewModel.loading.observe(viewLifecycleOwner, EventObserver { - if (!viewModel.fromDeeplink) { - (parentFragment?.parentFragment as HolderMainFragment).presentLoading(it) - } else { - // Show different loading state when loading from deeplink - binding.loadingOverlay.isVisible = it - } - }) - - binding.noTokenReceivedBtn.setOnClickListener { - infoFragmentUtil.presentAsBottomSheet(childFragmentManager, InfoFragmentData.TitleDescription( - title = getString(getFragmentData().noCodeDialogTitle), - descriptionData = DescriptionData( - htmlText = getFragmentData().noCodeDialogDescription, - htmlLinksEnabled = true - ) - )) - } - } - - private fun showNegativeTestResult(result: TestResult.NegativeTestResult) { - navigateMyEvents(result) - } - - private fun showTokenError(@StringRes errorMessageRes: Int) { - binding.uniqueCodeInput.error = getString(errorMessageRes) - binding.verificationCodeInput.isVisible = false - } - - override fun onPause() { - super.onPause() - hideKeyboard() - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } - - private fun fetchTestResults( - binding: FragmentInputTokenBinding, - fromDeeplink: Boolean = false - ) { - binding.verificationCodeInput.error = null - binding.uniqueCodeInput.error = null - viewModel.getTestResult(fromDeeplink) - } - - abstract fun getFragmentData(): InputTokenFragmentData - abstract fun navigateCouldNotCreateQr() - abstract fun navigateMyEvents(result: TestResult.NegativeTestResult) - abstract fun getDeeplinkToken(): String? -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/input_token/InputTokenFragmentData.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/input_token/InputTokenFragmentData.kt deleted file mode 100644 index b55cc5931..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/input_token/InputTokenFragmentData.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.input_token - -import android.os.Parcelable -import androidx.annotation.StringRes -import kotlinx.parcelize.Parcelize -import nl.rijksoverheid.ctr.holder.R - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -sealed class InputTokenFragmentData( - @StringRes val description: Int, - @StringRes val descriptionDeeplink: Int, - @StringRes val uniqueCodeInputHeader: Int, - @StringRes val uniqueCodeInputHint: Int, - @StringRes val uniqueCodeInputHintScreenReader: Int, - @StringRes val noUniqueCodeEntered: Int, - @StringRes val noCodeText: Int, - @StringRes val noCodeDialogTitle: Int, - @StringRes val noCodeDialogDescription: Int, - @StringRes val noResultScreenToolbarTitle: Int, - @StringRes val noResultScreenTitle: Int, - @StringRes val noResultScreenDescription: Int, - @StringRes val invalidTokenText: Int, - @StringRes val buttonText: Int -) : Parcelable { - @Parcelize - object CommercialTest : InputTokenFragmentData( - description = R.string.commercial_test_code_description, - descriptionDeeplink = R.string.commercial_test_verification_code_description_deeplink, - uniqueCodeInputHeader = R.string.commercial_test_unique_code_header, - uniqueCodeInputHint = R.string.commercial_test_unique_code_hint, - uniqueCodeInputHintScreenReader = R.string.commercial_test_unique_code_hint_screenreader, - noUniqueCodeEntered = R.string.commercial_test_error_empty_retrieval_code, - noCodeText = R.string.commercial_test_type_no_code_title, - noCodeDialogTitle = R.string.commercial_test_type_no_code_title, - noCodeDialogDescription = R.string.commercial_test_type_no_code_description, - noResultScreenToolbarTitle = R.string.commercial_test_type_title, - noResultScreenTitle = R.string.no_negative_test_result_title, - noResultScreenDescription = R.string.no_negative_test_result_description, - invalidTokenText = R.string.commercial_test_error_invalid_code, - buttonText = R.string.commercial_test_button - ) -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/input_token/InputTokenViewModel.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/input_token/InputTokenViewModel.kt deleted file mode 100644 index f4f70043f..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/input_token/InputTokenViewModel.kt +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.input_token - -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.SavedStateHandle -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import kotlinx.coroutines.launch -import nl.rijksoverheid.ctr.holder.input_token.usecases.TestResult -import nl.rijksoverheid.ctr.holder.input_token.usecases.TestResultUseCase -import nl.rijksoverheid.ctr.shared.livedata.Event - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ - -abstract class InputTokenViewModel : ViewModel() { - abstract fun updateViewState() - abstract fun getTestResult(fromDeeplink: Boolean = false) - abstract fun sendVerificationCode() - - open var verificationCode: String? = null - open var verificationRequired: Boolean = false - open var testCode: String = "" - open var fromDeeplink: Boolean = false - - val testResult: LiveData> = MutableLiveData() - val loading: LiveData> = MutableLiveData() - val viewState: LiveData = MutableLiveData(ViewState()) -} - -class InputTokenViewModelImpl( - private val savedStateHandle: SavedStateHandle, - private val testResultUseCase: TestResultUseCase -) : InputTokenViewModel() { - - override var verificationCode: String? = savedStateHandle["verification_code"] - set(value) { - field = value - savedStateHandle["verification_code"] = value - updateViewState() - } - - override var verificationRequired: Boolean = savedStateHandle["verification_required"] ?: false - set(value) { - field = value - savedStateHandle["verification_required"] = value - updateViewState() - } - - override var testCode: String = savedStateHandle["test_code"] ?: "" - set(value) { - field = value - savedStateHandle["test_code"] = value - updateViewState() - } - - override var fromDeeplink: Boolean = savedStateHandle["from_deeplink"] ?: false - set(value) { - field = value - savedStateHandle["from_deeplink"] = value - updateViewState() - } - - private val currentViewState: ViewState - get() = viewState.value!! - - init { - updateViewState() - } - - override fun updateViewState() { - (viewState as MutableLiveData).value = currentViewState.copy( - verificationRequired = verificationRequired, - fromDeeplink = fromDeeplink - ) - } - - override fun getTestResult(fromDeeplink: Boolean) { - this.fromDeeplink = fromDeeplink - (loading as MutableLiveData).value = Event(true) - viewModelScope.launch { - try { - val result = testResultUseCase.testResult(testCode, verificationCode) - if (result == TestResult.VerificationRequired) { - verificationRequired = true - } - (testResult as MutableLiveData).value = Event(result) - } finally { - loading.value = Event(false) - } - } - } - - override fun sendVerificationCode() { - viewModelScope.launch { - val result = testResultUseCase.testResult(testCode, "") - - // Only notify the UI of errors, since this is just about resending a sms verification on the backend - if (result is TestResult.Error) { - (testResult as MutableLiveData).value = Event(result) - } - } - } -} - -data class ViewState( - val verificationRequired: Boolean = false, - val fromDeeplink: Boolean = false -) diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/input_token/usecases/TestResultUseCase.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/input_token/usecases/TestResultUseCase.kt deleted file mode 100644 index 9fd0c2903..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/input_token/usecases/TestResultUseCase.kt +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.input_token.usecases - -import nl.rijksoverheid.ctr.holder.api.models.SignedResponseWithModel -import nl.rijksoverheid.ctr.holder.api.repositories.TestProviderRepository -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteProtocol -import nl.rijksoverheid.ctr.holder.get_events.usecases.ConfigProvidersUseCase -import nl.rijksoverheid.ctr.holder.get_events.usecases.TestProvidersResult -import nl.rijksoverheid.ctr.holder.models.HolderStep -import nl.rijksoverheid.ctr.persistence.HolderCachedAppConfigUseCase -import nl.rijksoverheid.ctr.shared.ext.removeWhitespace -import nl.rijksoverheid.ctr.shared.models.AppErrorResult -import nl.rijksoverheid.ctr.shared.models.ErrorResult -import nl.rijksoverheid.ctr.shared.models.NetworkRequestResult -import nl.rijksoverheid.rdo.modules.luhncheck.TokenValidator -import nl.rijksoverheid.rdo.modules.luhncheck.TokenValidatorImpl - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -class TestResultUseCase( - private val configProviderUseCase: ConfigProvidersUseCase, - private val testProviderRepository: TestProviderRepository, - private val tokenValidatorUtil: TokenValidator, - private val configUseCase: HolderCachedAppConfigUseCase -) { - - suspend fun testResult(uniqueCode: String, verificationCode: String? = null): TestResult { - try { - if (uniqueCode.isEmpty()) { - return TestResult.EmptyToken - } - - if (uniqueCode.indexOf("-") == -1) { - return TestResult.InvalidToken - } - - val uniqueCodeAttributes = uniqueCode.split("-") - - if (uniqueCodeAttributes.size != 3) { - return TestResult.InvalidToken - } - - val providerIdentifier = uniqueCodeAttributes[0] - val token = uniqueCodeAttributes[1] - val checksum = uniqueCodeAttributes[2] - - // We need to check for valid chars - token.toCharArray().forEach { - if (!TokenValidatorImpl.CODE_POINTS.contains(it)) { - return TestResult.InvalidToken - } - } - - // Enable the luhn check based on the current config value - if (configUseCase.getCachedAppConfig().luhnCheckEnabled) { - if (!tokenValidatorUtil.validate(token = token, checksum = checksum)) { - return TestResult.InvalidToken - } - } - - val testProvider = - when (val testProvidersResult = configProviderUseCase.testProviders()) { - is TestProvidersResult.Success -> { - testProvidersResult.testProviders - .firstOrNull { it.providerIdentifier == providerIdentifier } - ?: return TestResult.UnknownTestProvider - } - is TestProvidersResult.Error -> { - return TestResult.Error(testProvidersResult.errorResult) - } - } - - if (verificationCode != null && verificationCode.isEmpty()) { - return TestResult.EmptyVerificationCode - } - - val signedResponseWithTestResultRequestResult = testProviderRepository.remoteTestResult( - url = testProvider.resultUrl, - token = token.removeWhitespace(), - verifierCode = verificationCode?.removeWhitespace() ?: "", - signingCertificateBytes = testProvider.cms, - provider = providerIdentifier, - tlsCertificateBytes = testProvider.tls - ) - - val signedResponseWithTestResult = when (signedResponseWithTestResultRequestResult) { - is NetworkRequestResult.Success -> { - signedResponseWithTestResultRequestResult.response - } - is NetworkRequestResult.Failed -> { - return TestResult.Error(signedResponseWithTestResultRequestResult) - } - } - - val remoteTestResult = signedResponseWithTestResult.model - - when (remoteTestResult.status) { - RemoteProtocol.Status.VERIFICATION_REQUIRED -> return TestResult.VerificationRequired - RemoteProtocol.Status.INVALID_TOKEN -> return TestResult.InvalidToken - RemoteProtocol.Status.PENDING -> return TestResult.Pending - RemoteProtocol.Status.RESULT_BLOCKED -> return TestResult.ResultBlocked - RemoteProtocol.Status.COMPLETE -> { - if (!remoteTestResult.hasEvents()) { - return TestResult.NoNegativeTestResult - } - - return TestResult.NegativeTestResult( - remoteTestResult, - signedResponseWithTestResult - ) - } - else -> throw IllegalStateException("Unsupported status ${remoteTestResult.status}") - } - } catch (e: Exception) { - return TestResult.Error( - errorResult = AppErrorResult( - step = HolderStep.TestResultNetworkRequest, - e = e - ) - ) - } - } -} - -sealed class TestResult { - object NoNegativeTestResult : TestResult() - data class NegativeTestResult( - val remoteTestResult: RemoteProtocol, - val signedResponseWithTestResult: SignedResponseWithModel - ) : TestResult() - - object Pending : TestResult() - object EmptyToken : TestResult() - object InvalidToken : TestResult() - object UnknownTestProvider : TestResult() - object EmptyVerificationCode : TestResult() - object VerificationRequired : TestResult() - object ResultBlocked : TestResult() - data class Error(val errorResult: ErrorResult) : TestResult() -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/menu/AboutThisAppDataModel.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/menu/AboutThisAppDataModel.kt deleted file mode 100644 index 4c749418c..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/menu/AboutThisAppDataModel.kt +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ - -package nl.rijksoverheid.ctr.holder.menu - -import android.content.Context -import nl.rijksoverheid.ctr.appconfig.persistence.AppConfigPersistenceManager -import nl.rijksoverheid.ctr.appconfig.usecases.CachedAppConfigUseCase -import nl.rijksoverheid.ctr.design.fragments.menu.MenuFragmentDirections -import nl.rijksoverheid.ctr.design.menu.about.AboutThisAppData -import nl.rijksoverheid.ctr.design.utils.DialogButtonData -import nl.rijksoverheid.ctr.design.utils.DialogFragmentData -import nl.rijksoverheid.ctr.holder.BuildConfig -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.usecases.HolderFeatureFlagUseCase - -interface AboutThisAppDataModel { - fun get(context: Context): AboutThisAppData -} - -class AboutThisAppDataModelImpl( - private val cachedAppConfigUseCase: CachedAppConfigUseCase, - private val featureFlagUseCase: HolderFeatureFlagUseCase, - private val appConfigPersistenceManager: AppConfigPersistenceManager -) : AboutThisAppDataModel { - override fun get(context: Context): AboutThisAppData { - - val dialogDirection = MenuFragmentDirections.actionDialog( - data = DialogFragmentData( - title = nl.rijksoverheid.ctr.design.R.string.about_this_app_clear_data_title, - message = nl.rijksoverheid.ctr.design.R.string.about_this_app_clear_data_description, - positiveButtonData = DialogButtonData.ResetApp( - textId = nl.rijksoverheid.ctr.design.R.string.about_this_app_clear_data_confirm - ), - negativeButtonData = DialogButtonData.Dismiss(nl.rijksoverheid.ctr.design.R.string.about_this_app_clear_data_cancel) - ) - ) - return AboutThisAppData( - description = if (featureFlagUseCase.isInArchiveMode()) { - context.getString(R.string.holder_aboutThisApp_archiveMode_description) - } else { - context.getString(R.string.about_this_app_description) - }, - deeplinkScannerUrl = BuildConfig.DEEPLINK_SCANNER_TEST_URL, - versionName = BuildConfig.VERSION_NAME, - versionCode = BuildConfig.VERSION_CODE.toString(), - resetAppDialogDirection = AboutThisAppData.Destination( - text = context.getString(R.string.about_this_app_clear_data_confirm), - dialogDirection.actionId, - dialogDirection.arguments - ), - sections = listOf( - AboutThisAppData.AboutThisAppSection( - header = R.string.about_this_app_read_more, - items = mutableListOf( - AboutThisAppData.Url( - text = context.getString(R.string.privacy_statement), - url = context.getString(R.string.url_privacy_statement) - ), - AboutThisAppData.Url( - text = context.getString(R.string.about_this_app_accessibility), - url = context.getString(R.string.url_accessibility) - ), - AboutThisAppData.Url( - text = context.getString(R.string.about_this_app_colofon), - url = context.getString(R.string.about_this_app_colofon_url) - ) - ) - ) - ), - configVersionHash = cachedAppConfigUseCase.getCachedAppConfigHash(), - configVersionTimestamp = appConfigPersistenceManager.getAppConfigLastFetchedSeconds() - ) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/menu/HelpMenuDataModel.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/menu/HelpMenuDataModel.kt deleted file mode 100644 index 150dcd049..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/menu/HelpMenuDataModel.kt +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ - -package nl.rijksoverheid.ctr.holder.menu - -import android.content.Context -import java.time.DayOfWeek -import java.time.Instant -import java.time.OffsetDateTime -import java.time.ZoneOffset -import java.time.format.TextStyle -import nl.rijksoverheid.ctr.appconfig.persistence.AppConfigPersistenceManager -import nl.rijksoverheid.ctr.appconfig.usecases.CachedAppConfigUseCase -import nl.rijksoverheid.ctr.design.ext.formatDayMonthYearTimeNumerical -import nl.rijksoverheid.ctr.design.fragments.menu.MenuFragmentDirections -import nl.rijksoverheid.ctr.design.fragments.menu.MenuSection -import nl.rijksoverheid.ctr.design.menu.about.HelpdeskData -import nl.rijksoverheid.ctr.holder.BuildConfig -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.shared.ext.locale - -interface HelpMenuDataModel { - fun get(context: Context): Array -} - -class HelpMenuDataModelImpl( - private val aboutThisAppDataModel: AboutThisAppDataModel, - private val cachedAppConfigUseCase: CachedAppConfigUseCase, - private val appConfigPersistenceManager: AppConfigPersistenceManager -) : HelpMenuDataModel { - - override fun get(context: Context): Array { - val configFetchDate = OffsetDateTime.ofInstant( - Instant.ofEpochSecond(appConfigPersistenceManager.getAppConfigLastFetchedSeconds()), - ZoneOffset.UTC - ).formatDayMonthYearTimeNumerical() - val contactInformation = cachedAppConfigUseCase.getCachedAppConfig().contactInfo - val startDay = DayOfWeek.of(contactInformation.startDay).getDisplayName(TextStyle.FULL, context.locale()) - val endDay = DayOfWeek.of(contactInformation.endDay).getDisplayName(TextStyle.FULL, context.locale()) - val actionHelpdesk = MenuFragmentDirections.actionHelpdesk( - data = HelpdeskData( - contactTitle = context.getString(R.string.holder_helpdesk_contact_title), - contactMessageLines = listOf( - context.getString( - R.string.holder_helpdesk_contact_message_line1, - contactInformation.phoneNumber, - contactInformation.phoneNumber - ), - context.getString( - R.string.holder_helpdesk_contact_message_line2, - contactInformation.phoneNumberAbroad, - contactInformation.phoneNumberAbroad - ), - context.getString( - R.string.holder_helpdesk_contact_message_line3, - startDay, - endDay, - contactInformation.startHour, - contactInformation.endHour - ) - ), - supportTitle = context.getString(R.string.holder_helpdesk_support_title), - supportMessage = context.getString(R.string.holder_helpdesk_support_message), - appVersionTitle = context.getString(R.string.holder_helpdesk_appVersion), - appVersion = "${BuildConfig.VERSION_NAME} (build ${BuildConfig.VERSION_CODE})", - configurationTitle = context.getString(R.string.holder_helpdesk_configuration), - configuration = "${cachedAppConfigUseCase.getCachedAppConfigHash()}, $configFetchDate" - ) - ) - - val aboutThisAppAction = MenuFragmentDirections.actionAboutThisApp( - data = aboutThisAppDataModel.get(context) - ) - return listOf( - MenuSection( - menuItems = listOf( - MenuSection.MenuItem( - icon = R.drawable.ic_menu_chatbubble, - title = R.string.frequently_asked_questions, - onClick = MenuSection.MenuItem.OnClick.OpenBrowser( - url = context.getString(R.string.url_faq) - ) - ), - MenuSection.MenuItem( - icon = R.drawable.ic_menu_helpdesk, - title = R.string.holder_helpInfo_helpdesk, - onClick = MenuSection.MenuItem.OnClick.Navigate( - navigationActionId = actionHelpdesk.actionId, - navigationArguments = actionHelpdesk.arguments - ) - ) - ) - ), - MenuSection( - menuItems = listOf( - MenuSection.MenuItem( - icon = R.drawable.ic_menu_smartphone, - title = R.string.about_this_app, - onClick = MenuSection.MenuItem.OnClick.Navigate( - navigationActionId = aboutThisAppAction.actionId, - navigationArguments = aboutThisAppAction.arguments - ) - ) - ) - ) - ).toTypedArray() - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/menu/MenuViewModel.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/menu/MenuViewModel.kt deleted file mode 100644 index 46fc04f52..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/menu/MenuViewModel.kt +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.menu - -import android.content.Context -import androidx.lifecycle.MutableLiveData -import nl.rijksoverheid.ctr.design.fragments.menu.MenuFragmentDirections -import nl.rijksoverheid.ctr.design.fragments.menu.MenuSection -import nl.rijksoverheid.ctr.design.menu.MenuViewModel -import nl.rijksoverheid.ctr.design.utils.DialogButtonData -import nl.rijksoverheid.ctr.design.utils.DialogFragmentData -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.usecases.HolderFeatureFlagUseCase -import nl.rijksoverheid.ctr.shared.livedata.Event -import nl.rijksoverheid.ctr.shared.models.Environment - -class MenuViewModelImpl( - private val helpMenuDataModel: HelpMenuDataModel, - private val featureFlagUseCase: HolderFeatureFlagUseCase -) : MenuViewModel() { - - override fun click(context: Context) { - (menuSectionLiveData as MutableLiveData).value = Event(menuSections(context)) - } - - private fun menuSections(context: Context): Array { - val actionExportIntroduction = MenuFragmentDirections.actionExportIntroduction() - val actionChooseProofType = MenuFragmentDirections.actionChooseProofType() - val actionSavedEvents = MenuFragmentDirections.actionSavedEvents() - val actionHelpInfo = MenuFragmentDirections.actionMenu( - toolbarTitle = context.getString(R.string.holder_helpInfo_title), - menuSections = helpMenuDataModel.get(context) - ) - - val exportPdfMenuItem = MenuSection.MenuItem( - icon = R.drawable.ic_menu_export_pdf, - title = R.string.holder_menu_exportPDF, - onClick = MenuSection.MenuItem.OnClick.Navigate( - navigationActionId = actionExportIntroduction.actionId - ) - ) - - val addVaccinationOrTestMenuItem = MenuSection.MenuItem( - icon = R.drawable.ic_menu_add, - title = R.string.holder_menu_listItem_addVaccinationOrTest_title, - onClick = MenuSection.MenuItem.OnClick.Navigate( - navigationActionId = actionChooseProofType.actionId, - navigationArguments = actionChooseProofType.arguments - ) - ) - - val savedEventsMenuItem = MenuSection.MenuItem( - icon = R.drawable.ic_menu_saved_events, - title = R.string.holder_menu_storedEvents, - onClick = MenuSection.MenuItem.OnClick.Navigate( - navigationActionId = actionSavedEvents.actionId - ) - ) - - val helpInfoMenuItem = MenuSection.MenuItem( - icon = R.drawable.ic_menu_info, - title = R.string.holder_menu_helpInfo, - onClick = MenuSection.MenuItem.OnClick.Navigate( - navigationActionId = actionHelpInfo.actionId, - navigationArguments = actionHelpInfo.arguments - ) - ) - - val firstSectionItems = listOfNotNull( - if (featureFlagUseCase.isInArchiveMode()) { - exportPdfMenuItem - } else { - null - }, - if (featureFlagUseCase.getAddEventsButtonEnabled()) { - addVaccinationOrTestMenuItem - } else { - null - } - ) - - val menuSections: List = listOfNotNull( - MenuSection( - menuItems = firstSectionItems - ), - MenuSection( - menuItems = listOfNotNull( - if (featureFlagUseCase.isInArchiveMode()) { - null - } else { - savedEventsMenuItem - } - ) - ), - MenuSection( - menuItems = listOfNotNull( - if (featureFlagUseCase.isInArchiveMode()) { - savedEventsMenuItem - } else { - null - }, - helpInfoMenuItem - ) - ), - if (Environment.get(context) == Environment.Prod) { - null - } else { - val dialogDirection = MenuFragmentDirections.actionDialog( - data = DialogFragmentData( - title = nl.rijksoverheid.ctr.design.R.string.about_this_app_clear_data_title, - message = nl.rijksoverheid.ctr.design.R.string.about_this_app_clear_data_description, - positiveButtonData = DialogButtonData.ResetApp( - textId = nl.rijksoverheid.ctr.design.R.string.about_this_app_clear_data_confirm - ), - negativeButtonData = DialogButtonData.Dismiss(nl.rijksoverheid.ctr.design.R.string.about_this_app_clear_data_cancel) - ) - ) - MenuSection( - menuItems = listOf( - MenuSection.MenuItem( - icon = R.drawable.ic_warning, - iconColor = R.color.error, - titleColor = R.color.error, - title = R.string.general_menu_resetApp, - onClick = MenuSection.MenuItem.OnClick.Navigate( - dialogDirection.actionId, - dialogDirection.arguments - ) - ) - ) - ) - } - ) - - return menuSections.toTypedArray() - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/models/HolderFlow.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/models/HolderFlow.kt index 8e61e6a38..d76b0e0cb 100644 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/models/HolderFlow.kt +++ b/holder/src/main/java/nl/rijksoverheid/ctr/holder/models/HolderFlow.kt @@ -9,7 +9,6 @@ package nl.rijksoverheid.ctr.holder.models import android.os.Parcelable import kotlinx.parcelize.Parcelize -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteProtocol import nl.rijksoverheid.ctr.shared.models.Flow sealed class HolderFlow(code: Int) : Flow(code), Parcelable { @@ -32,9 +31,6 @@ sealed class HolderFlow(code: Int) : Flow(code), Parcelable { @Parcelize object HkviScan : HolderFlow(5) - @Parcelize - data class HkviScanned(val remoteProtocol: RemoteProtocol) : HolderFlow(5) - @Parcelize object SyncGreenCards : HolderFlow(7) diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/AppModules.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/AppModules.kt index 48de6e011..6fbf1701c 100644 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/AppModules.kt +++ b/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/AppModules.kt @@ -14,9 +14,6 @@ import nl.rijksoverheid.ctr.holder.ui.priority_notification.PriorityNotification import nl.rijksoverheid.ctr.holder.usecases.BuildConfigUseCaseImpl import nl.rijksoverheid.ctr.holder.usecases.HolderFeatureFlagUseCase import nl.rijksoverheid.ctr.holder.usecases.HolderFeatureFlagUseCaseImpl -import nl.rijksoverheid.ctr.holder.workers.HolderWorkerFactory -import nl.rijksoverheid.ctr.holder.workers.WorkerManagerUtil -import nl.rijksoverheid.ctr.holder.workers.WorkerManagerUtilImpl import nl.rijksoverheid.ctr.persistence.HolderCachedAppConfigUseCase import nl.rijksoverheid.ctr.persistence.HolderCachedAppConfigUseCaseImpl import nl.rijksoverheid.ctr.shared.BuildConfigUseCase @@ -52,8 +49,6 @@ val appModule = module { HolderFeatureFlagUseCaseImpl(get(), get()) } - factory { WorkerManagerUtilImpl(androidContext(), get(), get()) } - factory { HolderWorkerFactory(get(), get(), get(), get()) } } private fun isDebugApp(androidContext: Context) = diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/CardUtilsModule.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/CardUtilsModule.kt deleted file mode 100644 index c5d69f795..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/CardUtilsModule.kt +++ /dev/null @@ -1,49 +0,0 @@ -package nl.rijksoverheid.ctr.holder.modules - -import java.time.Clock -import nl.rijksoverheid.ctr.holder.dashboard.items.DashboardGreenCardAdapterItemExpiryUtil -import nl.rijksoverheid.ctr.holder.dashboard.items.DashboardGreenCardAdapterItemExpiryUtilImpl -import nl.rijksoverheid.ctr.holder.dashboard.util.GreenCardRefreshUtil -import nl.rijksoverheid.ctr.holder.dashboard.util.GreenCardRefreshUtilImpl -import nl.rijksoverheid.ctr.holder.dashboard.util.GreenCardUtil -import nl.rijksoverheid.ctr.holder.dashboard.util.GreenCardUtilImpl -import nl.rijksoverheid.ctr.holder.qrcodes.utils.LastVaccinationDoseUtil -import nl.rijksoverheid.ctr.holder.qrcodes.utils.LastVaccinationDoseUtilImpl -import nl.rijksoverheid.ctr.holder.qrcodes.utils.QrCodeUtil -import nl.rijksoverheid.ctr.holder.qrcodes.utils.QrCodeUtilImpl -import nl.rijksoverheid.ctr.holder.qrcodes.utils.QrInfoScreenUtil -import nl.rijksoverheid.ctr.holder.qrcodes.utils.QrInfoScreenUtilImpl -import nl.rijksoverheid.ctr.holder.your_events.utils.InfoScreenUtil -import nl.rijksoverheid.ctr.holder.your_events.utils.InfoScreenUtilImpl -import nl.rijksoverheid.ctr.holder.your_events.utils.RecoveryInfoScreenUtil -import nl.rijksoverheid.ctr.holder.your_events.utils.RecoveryInfoScreenUtilImpl -import nl.rijksoverheid.ctr.holder.your_events.utils.TestInfoScreenUtil -import nl.rijksoverheid.ctr.holder.your_events.utils.TestInfoScreenUtilImpl -import nl.rijksoverheid.ctr.holder.your_events.utils.VaccinationInfoScreenUtil -import nl.rijksoverheid.ctr.holder.your_events.utils.VaccinationInfoScreenUtilImpl -import org.koin.android.ext.koin.androidContext -import org.koin.dsl.module - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -val cardUtilsModule = module { - factory { QrCodeUtilImpl() } - factory { DashboardGreenCardAdapterItemExpiryUtilImpl(get(), androidContext()) } - factory { InfoScreenUtilImpl(get(), get(), get()) } - factory { TestInfoScreenUtilImpl(androidContext().resources, get(), get(), get()) } - factory { RecoveryInfoScreenUtilImpl(androidContext().resources, get(), get()) } - factory { QrInfoScreenUtilImpl(get(), get(), get(), get(), get()) } - factory { - VaccinationInfoScreenUtilImpl(get(), androidContext().resources, get(), get(), get()) - } - factory { LastVaccinationDoseUtilImpl(androidContext().resources) } - factory { GreenCardUtilImpl(get(), Clock.systemUTC(), get(), get()) } - factory { - GreenCardRefreshUtilImpl(get(), get(), get(), get(), get(), get()) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/EventsUseCasesModule.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/EventsUseCasesModule.kt deleted file mode 100644 index bf1f1376f..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/EventsUseCasesModule.kt +++ /dev/null @@ -1,92 +0,0 @@ -package nl.rijksoverheid.ctr.holder.modules - -import java.time.Clock -import nl.rijksoverheid.ctr.holder.dashboard.usecases.ShowBlockedEventsDialogUseCase -import nl.rijksoverheid.ctr.holder.dashboard.usecases.ShowBlockedEventsDialogUseCaseImpl -import nl.rijksoverheid.ctr.holder.get_events.usecases.GetEventProvidersWithTokensUseCase -import nl.rijksoverheid.ctr.holder.get_events.usecases.GetEventProvidersWithTokensUseCaseImpl -import nl.rijksoverheid.ctr.holder.get_events.usecases.GetEventsUseCase -import nl.rijksoverheid.ctr.holder.get_events.usecases.GetEventsUseCaseImpl -import nl.rijksoverheid.ctr.holder.get_events.usecases.GetMijnCnEventsUsecase -import nl.rijksoverheid.ctr.holder.get_events.usecases.GetMijnCnEventsUsecaseImpl -import nl.rijksoverheid.ctr.holder.get_events.usecases.GetRemoteEventsUseCase -import nl.rijksoverheid.ctr.holder.get_events.usecases.GetRemoteEventsUseCaseImpl -import nl.rijksoverheid.ctr.holder.get_events.usecases.GetRemoteProtocolFromEventGroupUseCase -import nl.rijksoverheid.ctr.holder.get_events.usecases.GetRemoteProtocolFromEventGroupUseCaseImpl -import nl.rijksoverheid.ctr.holder.get_events.usecases.PersistBlockedEventsUseCase -import nl.rijksoverheid.ctr.holder.get_events.usecases.PersistBlockedEventsUseCaseImpl -import nl.rijksoverheid.ctr.holder.paper_proof.usecases.GetEventsFromPaperProofQrUseCase -import nl.rijksoverheid.ctr.holder.paper_proof.usecases.GetEventsFromPaperProofQrUseCaseImpl -import nl.rijksoverheid.ctr.holder.paper_proof.usecases.ValidatePaperProofDomesticInputCodeUseCase -import nl.rijksoverheid.ctr.holder.paper_proof.usecases.ValidatePaperProofDomesticInputCodeUseCaseImpl -import nl.rijksoverheid.ctr.holder.paper_proof.usecases.ValidatePaperProofDomesticUseCase -import nl.rijksoverheid.ctr.holder.paper_proof.usecases.ValidatePaperProofDomesticUseCaseImpl -import nl.rijksoverheid.ctr.holder.pdf.PreviewPdfUseCase -import nl.rijksoverheid.ctr.holder.pdf.PreviewPdfUseCaseImpl -import nl.rijksoverheid.ctr.holder.pdf.PrintExportDccUseCase -import nl.rijksoverheid.ctr.holder.pdf.PrintExportDccUseCaseImpl -import nl.rijksoverheid.ctr.holder.qrcodes.usecases.QrCodeUseCase -import nl.rijksoverheid.ctr.holder.qrcodes.usecases.QrCodeUseCaseImpl -import nl.rijksoverheid.ctr.holder.saved_events.usecases.GetSavedEventsUseCase -import nl.rijksoverheid.ctr.holder.saved_events.usecases.GetSavedEventsUseCaseImpl -import nl.rijksoverheid.ctr.holder.your_events.usecases.SaveEventsUseCase -import nl.rijksoverheid.ctr.holder.your_events.usecases.SaveEventsUseCaseImpl -import nl.rijksoverheid.ctr.persistence.database.usecases.DraftEventUseCase -import nl.rijksoverheid.ctr.persistence.database.usecases.DraftEventUseCaseImpl -import nl.rijksoverheid.ctr.persistence.database.usecases.RemoveExpiredEventsUseCase -import nl.rijksoverheid.ctr.persistence.database.usecases.RemoveExpiredEventsUseCaseImpl -import org.koin.dsl.module - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -val eventsUseCasesModule = module { - factory { - ValidatePaperProofDomesticInputCodeUseCaseImpl() - } - - factory { - ValidatePaperProofDomesticUseCaseImpl(get(), get(), get()) - } - - factory { - GetEventProvidersWithTokensUseCaseImpl(get()) - } - factory { - GetRemoteEventsUseCaseImpl(get()) - } - factory { - QrCodeUseCaseImpl( - get(), - get(), - get(), - get() - ) - } - factory { GetEventsUseCaseImpl(get(), get(), get(), get()) } - factory { GetMijnCnEventsUsecaseImpl(get(), get(), get()) } - factory { SaveEventsUseCaseImpl(get(), get(), get(), get(), get()) } - - factory { - GetEventsFromPaperProofQrUseCaseImpl(get(), get()) - } - - factory { - RemoveExpiredEventsUseCaseImpl(Clock.systemUTC(), get(), get()) - } - factory { - GetSavedEventsUseCaseImpl(get(), get(), get(), get(), get(), get(), get()) - } - factory { - GetRemoteProtocolFromEventGroupUseCaseImpl(get(), get()) - } - factory { PersistBlockedEventsUseCaseImpl(get()) } - factory { ShowBlockedEventsDialogUseCaseImpl(get()) } - factory { DraftEventUseCaseImpl(get()) } - factory { PrintExportDccUseCaseImpl(get(), get(), get()) } - factory { PreviewPdfUseCaseImpl() } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/GreenCardUseCasesModule.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/GreenCardUseCasesModule.kt deleted file mode 100644 index 78d6d44cc..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/GreenCardUseCasesModule.kt +++ /dev/null @@ -1,58 +0,0 @@ -package nl.rijksoverheid.ctr.holder.modules - -import nl.rijksoverheid.ctr.dashboard.usecases.RemoveExpiredGreenCardsUseCase -import nl.rijksoverheid.ctr.dashboard.usecases.RemoveExpiredGreenCardsUseCaseImpl -import nl.rijksoverheid.ctr.holder.dashboard.usecases.GetDashboardItemsUseCase -import nl.rijksoverheid.ctr.holder.dashboard.usecases.GetDashboardItemsUseCaseImpl -import nl.rijksoverheid.ctr.holder.dashboard.usecases.SortGreenCardItemsUseCase -import nl.rijksoverheid.ctr.holder.dashboard.usecases.SortGreenCardItemsUseCaseImpl -import nl.rijksoverheid.ctr.holder.paper_proof.usecases.GetDccFromEuropeanCredentialUseCase -import nl.rijksoverheid.ctr.holder.paper_proof.usecases.GetDccFromEuropeanCredentialUseCaseImpl -import nl.rijksoverheid.ctr.holder.paper_proof.usecases.GetPaperProofTypeUseCase -import nl.rijksoverheid.ctr.holder.paper_proof.usecases.GetPaperProofTypeUseCaseImpl -import nl.rijksoverheid.ctr.persistence.database.usecases.CreateEuGreenCardUseCase -import nl.rijksoverheid.ctr.persistence.database.usecases.CreateEuGreenCardUseCaseImpl -import nl.rijksoverheid.ctr.persistence.database.usecases.GetRemoteGreenCardsUseCase -import nl.rijksoverheid.ctr.persistence.database.usecases.GetRemoteGreenCardsUseCaseImpl -import nl.rijksoverheid.ctr.persistence.database.usecases.SyncRemoteGreenCardsUseCase -import nl.rijksoverheid.ctr.persistence.database.usecases.SyncRemoteGreenCardsUseCaseImpl -import nl.rijksoverheid.ctr.persistence.database.usecases.UpdateEventExpirationUseCase -import nl.rijksoverheid.ctr.persistence.database.usecases.UpdateEventExpirationUseCaseImpl -import org.koin.dsl.module - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -val greenCardUseCasesModule = module { - factory { - GetRemoteGreenCardsUseCaseImpl(get(), get(), get()) - } - factory { - SyncRemoteGreenCardsUseCaseImpl(get(), get(), get()) - } - factory { - CreateEuGreenCardUseCaseImpl(get(), get()) - } - factory { - GetDashboardItemsUseCaseImpl(get(), get(), get(), get(), get(), get(), get(), get(), get(), get()) - } - factory { - SortGreenCardItemsUseCaseImpl(get(), get()) - } - factory { - RemoveExpiredGreenCardsUseCaseImpl(get(), get()) - } - factory { - GetPaperProofTypeUseCaseImpl(get(), get(), get()) - } - factory { - GetDccFromEuropeanCredentialUseCaseImpl(get()) - } - factory { - UpdateEventExpirationUseCaseImpl(get()) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/QrsModule.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/QrsModule.kt deleted file mode 100644 index 284093606..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/QrsModule.kt +++ /dev/null @@ -1,28 +0,0 @@ -package nl.rijksoverheid.ctr.holder.modules - -import nl.rijksoverheid.ctr.holder.qrcodes.usecases.QrCodeAnimationUseCase -import nl.rijksoverheid.ctr.holder.qrcodes.usecases.QrCodeAnimationUseCaseImpl -import nl.rijksoverheid.ctr.holder.qrcodes.usecases.QrCodesResultUseCase -import nl.rijksoverheid.ctr.holder.qrcodes.usecases.QrCodesResultUseCaseImpl -import org.koin.dsl.module - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -val qrsModule = module { - factory { - QrCodesResultUseCaseImpl( - get(), - get(), - get(), - get(), - get(), - get() - ) - } - factory { QrCodeAnimationUseCaseImpl(get()) } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/RepositoriesModules.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/RepositoriesModules.kt index 745dc0071..b19975628 100644 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/RepositoriesModules.kt +++ b/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/RepositoriesModules.kt @@ -1,15 +1,5 @@ package nl.rijksoverheid.ctr.holder.modules -import nl.rijksoverheid.ctr.holder.api.HolderApiClientUtil -import nl.rijksoverheid.ctr.holder.api.HolderApiClientUtilImpl -import nl.rijksoverheid.ctr.holder.api.TestProviderApiClientUtil -import nl.rijksoverheid.ctr.holder.api.TestProviderApiClientUtilImpl -import nl.rijksoverheid.ctr.holder.api.repositories.CoronaCheckRepository -import nl.rijksoverheid.ctr.holder.api.repositories.CoronaCheckRepositoryImpl -import nl.rijksoverheid.ctr.holder.api.repositories.EventProviderRepository -import nl.rijksoverheid.ctr.holder.api.repositories.EventProviderRepositoryImpl -import nl.rijksoverheid.ctr.holder.api.repositories.TestProviderRepository -import nl.rijksoverheid.ctr.holder.api.repositories.TestProviderRepositoryImpl import nl.rijksoverheid.ctr.holder.modules.qualifier.ErrorResponseQualifier import org.koin.core.qualifier.named import org.koin.dsl.module @@ -22,37 +12,4 @@ import org.koin.dsl.module * */ val repositoriesModule = module { - factory { - HolderApiClientUtilImpl(get(), get()) - } - single { - CoronaCheckRepositoryImpl( - get(), - get(), - get(), - get(named(ErrorResponseQualifier.CORONA_CHECK)), - get(), - get() - ) - } - factory { - TestProviderRepositoryImpl( - get(), - get(), - get(named("SignedResponseWithModel")) - ) - } - factory { - TestProviderApiClientUtilImpl( - get(), - get(), - get() - ) - } - factory { - EventProviderRepositoryImpl( - get(), - get() - ) - } } diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/ResponsesModule.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/ResponsesModule.kt deleted file mode 100644 index d124a8c37..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/ResponsesModule.kt +++ /dev/null @@ -1,76 +0,0 @@ -package nl.rijksoverheid.ctr.holder.modules - -import com.squareup.moshi.Moshi -import com.squareup.moshi.Types -import com.squareup.moshi.adapters.PolymorphicJsonAdapterFactory -import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory -import nl.rijksoverheid.ctr.holder.api.OriginTypeJsonAdapter -import nl.rijksoverheid.ctr.holder.api.RemoteCouplingStatusJsonAdapter -import nl.rijksoverheid.ctr.holder.api.RemoteTestStatusJsonAdapter -import nl.rijksoverheid.ctr.holder.api.models.SignedResponseWithModel -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEvent -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteProtocol -import nl.rijksoverheid.ctr.holder.modules.qualifier.ErrorResponseQualifier -import nl.rijksoverheid.ctr.holder.your_events.models.RemoteGreenCards -import nl.rijksoverheid.ctr.shared.models.CoronaCheckErrorResponse -import nl.rijksoverheid.ctr.shared.models.MijnCnErrorResponse -import okhttp3.ResponseBody -import org.koin.core.qualifier.named -import org.koin.dsl.module -import retrofit2.Converter -import retrofit2.Retrofit - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -val responsesModule = module { - single>>(named("SignedResponseWithModel")) { - get(Retrofit::class).responseBodyConverter( - Types.newParameterizedType( - SignedResponseWithModel::class.java, - RemoteProtocol::class.java - ), emptyArray() - ) - } - - single> { - get(Retrofit::class).responseBodyConverter( - RemoteGreenCards::class.java, - emptyArray() - ) - } - - single>(named(ErrorResponseQualifier.CORONA_CHECK)) { - get(Retrofit::class).responseBodyConverter( - CoronaCheckErrorResponse::class.java, emptyArray() - ) - } - - single>(named(ErrorResponseQualifier.MIJN_CN)) { - get(Retrofit::class).responseBodyConverter( - MijnCnErrorResponse::class.java, emptyArray() - ) - } - - single { - get(Moshi.Builder::class) - .add(RemoteTestStatusJsonAdapter()) - .add(OriginTypeJsonAdapter()) - .add(RemoteCouplingStatusJsonAdapter()) - .add( - PolymorphicJsonAdapterFactory.of( - RemoteEvent::class.java, "type" - ) - .withSubtype(RemoteEvent.getRemoteEventClassFromType(RemoteEvent.TYPE_POSITIVE_TEST), RemoteEvent.TYPE_POSITIVE_TEST) - .withSubtype(RemoteEvent.getRemoteEventClassFromType(RemoteEvent.TYPE_RECOVERY), RemoteEvent.TYPE_RECOVERY) - .withSubtype(RemoteEvent.getRemoteEventClassFromType(RemoteEvent.TYPE_NEGATIVE_TEST), RemoteEvent.TYPE_NEGATIVE_TEST) - .withSubtype(RemoteEvent.getRemoteEventClassFromType(RemoteEvent.TYPE_VACCINATION), RemoteEvent.TYPE_VACCINATION) - ) - .add(KotlinJsonAdapterFactory()) - .build() - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/RetrofitModules.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/RetrofitModules.kt deleted file mode 100644 index 86913f847..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/RetrofitModules.kt +++ /dev/null @@ -1,46 +0,0 @@ -package nl.rijksoverheid.ctr.holder.modules - -import nl.rijksoverheid.ctr.holder.BuildConfig -import nl.rijksoverheid.ctr.holder.api.MijnCnApiClient -import nl.rijksoverheid.ctr.holder.api.RemoteConfigApiClient -import okhttp3.OkHttpClient -import okhttp3.tls.HandshakeCertificates -import org.koin.dsl.module -import retrofit2.Retrofit -import retrofit2.converter.moshi.MoshiConverterFactory - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -fun retrofitModule(baseUrl: String, cdnUrl: String) = module { - single { - get(Retrofit::class).newBuilder().baseUrl(cdnUrl).build().create(RemoteConfigApiClient::class.java) - } - - single { - val okHttpClient = get(OkHttpClient::class) - .newBuilder() - .apply { - if (BuildConfig.FEATURE_TEST_PROVIDER_API_CHECKS) { - val handshakeCertificates = HandshakeCertificates.Builder() - .build() - - sslSocketFactory( - handshakeCertificates.sslSocketFactory(), - handshakeCertificates.trustManager - ) - } - }.build() - - Retrofit.Builder() - .client(okHttpClient) - .baseUrl(baseUrl) - .addConverterFactory(MoshiConverterFactory.create(get())) - .build() - .create(MijnCnApiClient::class.java) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/StorageModule.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/StorageModule.kt index f9960a5ae..1e82f0cbd 100644 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/StorageModule.kt +++ b/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/StorageModule.kt @@ -3,10 +3,6 @@ package nl.rijksoverheid.ctr.holder.modules import nl.rijksoverheid.ctr.persistence.PersistenceManager import nl.rijksoverheid.ctr.persistence.SharedPreferencesPersistenceManager import nl.rijksoverheid.ctr.persistence.database.HolderDatabase -import nl.rijksoverheid.ctr.persistence.database.HolderDatabaseSyncer -import nl.rijksoverheid.ctr.persistence.database.HolderDatabaseSyncerImpl -import nl.rijksoverheid.ctr.persistence.database.usecases.RemoveCTBUseCase -import nl.rijksoverheid.ctr.persistence.database.usecases.RemoveCTBUseCaseImpl import nl.rijksoverheid.ctr.shared.models.Environment import org.koin.android.ext.koin.androidContext import org.koin.dsl.module @@ -28,29 +24,9 @@ val storageModule = module { ) } - factory { - HolderDatabaseSyncerImpl( - get(), - get(), - get(), - get(), - get(), - get(), - get(), - get(), - get(), - get(), - get() - ) - } - single { SharedPreferencesPersistenceManager( get() ) } - - factory { - RemoveCTBUseCaseImpl(get(), get()) - } } diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/TestProvidersUseCasesModule.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/TestProvidersUseCasesModule.kt deleted file mode 100644 index 5df4be7d8..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/TestProvidersUseCasesModule.kt +++ /dev/null @@ -1,28 +0,0 @@ -package nl.rijksoverheid.ctr.holder.modules - -import nl.rijksoverheid.ctr.holder.get_events.usecases.ConfigProvidersUseCase -import nl.rijksoverheid.ctr.holder.get_events.usecases.ConfigProvidersUseCaseImpl -import nl.rijksoverheid.ctr.holder.input_token.usecases.TestResultUseCase -import org.koin.dsl.module - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -val testProvidersUseCasesModule = module { - factory { - ConfigProvidersUseCaseImpl(get()) - } - - factory { - TestResultUseCase( - get(), - get(), - get(), - get() - ) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/UtilsModule.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/UtilsModule.kt index 5849f3547..5e170562d 100644 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/UtilsModule.kt +++ b/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/UtilsModule.kt @@ -1,69 +1,13 @@ package nl.rijksoverheid.ctr.holder.modules -import java.time.Clock -import nl.rijksoverheid.ctr.holder.dashboard.items.DashboardGreenCardAdapterItemUtil -import nl.rijksoverheid.ctr.holder.dashboard.items.DashboardGreenCardAdapterItemUtilImpl -import nl.rijksoverheid.ctr.holder.dashboard.items.DashboardHeaderAdapterItemUtil -import nl.rijksoverheid.ctr.holder.dashboard.items.DashboardHeaderAdapterItemUtilImpl -import nl.rijksoverheid.ctr.holder.dashboard.items.DashboardInfoCardAdapterItemUtil -import nl.rijksoverheid.ctr.holder.dashboard.items.DashboardInfoCardAdapterItemUtilImpl -import nl.rijksoverheid.ctr.holder.dashboard.util.CardItemUtil -import nl.rijksoverheid.ctr.holder.dashboard.util.CardItemUtilImpl -import nl.rijksoverheid.ctr.holder.dashboard.util.CredentialUtil -import nl.rijksoverheid.ctr.holder.dashboard.util.CredentialUtilImpl -import nl.rijksoverheid.ctr.holder.dashboard.util.DashboardItemEmptyStateUtil -import nl.rijksoverheid.ctr.holder.dashboard.util.DashboardItemEmptyStateUtilImpl -import nl.rijksoverheid.ctr.holder.dashboard.util.DashboardItemUtil -import nl.rijksoverheid.ctr.holder.dashboard.util.DashboardItemUtilImpl -import nl.rijksoverheid.ctr.holder.dashboard.util.DashboardPageInfoItemHandlerUtil -import nl.rijksoverheid.ctr.holder.dashboard.util.DashboardPageInfoItemHandlerUtilImpl -import nl.rijksoverheid.ctr.holder.dashboard.util.OriginUtil -import nl.rijksoverheid.ctr.holder.dashboard.util.OriginUtilImpl -import nl.rijksoverheid.ctr.holder.dashboard.util.RemovedEventsBottomSheetUtil -import nl.rijksoverheid.ctr.holder.dashboard.util.RemovedEventsBottomSheetUtilImpl -import nl.rijksoverheid.ctr.holder.get_events.utils.LoginTypeUtil -import nl.rijksoverheid.ctr.holder.get_events.utils.LoginTypeUtilImpl -import nl.rijksoverheid.ctr.holder.get_events.utils.ScopeUtil -import nl.rijksoverheid.ctr.holder.get_events.utils.ScopeUtilImpl -import nl.rijksoverheid.ctr.holder.menu.AboutThisAppDataModel -import nl.rijksoverheid.ctr.holder.menu.AboutThisAppDataModelImpl -import nl.rijksoverheid.ctr.holder.menu.HelpMenuDataModel -import nl.rijksoverheid.ctr.holder.menu.HelpMenuDataModelImpl -import nl.rijksoverheid.ctr.holder.no_digid.NoDigidScreenDataUtil -import nl.rijksoverheid.ctr.holder.no_digid.NoDigidScreenDataUtilImpl -import nl.rijksoverheid.ctr.holder.paper_proof.utils.PaperProofUtil -import nl.rijksoverheid.ctr.holder.paper_proof.utils.PaperProofUtilImpl -import nl.rijksoverheid.ctr.holder.qrcodes.models.ReadEuropeanCredentialUtil -import nl.rijksoverheid.ctr.holder.qrcodes.models.ReadEuropeanCredentialUtilImpl -import nl.rijksoverheid.ctr.holder.qrcodes.utils.MultipleQrCodesUtil -import nl.rijksoverheid.ctr.holder.qrcodes.utils.MultipleQrCodesUtilImpl -import nl.rijksoverheid.ctr.holder.qrcodes.utils.QrCodesFragmentUtil -import nl.rijksoverheid.ctr.holder.qrcodes.utils.QrCodesFragmentUtilImpl import nl.rijksoverheid.ctr.holder.utils.CountryUtil import nl.rijksoverheid.ctr.holder.utils.CountryUtilImpl import nl.rijksoverheid.ctr.holder.utils.LocalDateUtil import nl.rijksoverheid.ctr.holder.utils.LocalDateUtilImpl import nl.rijksoverheid.ctr.holder.utils.StringUtil import nl.rijksoverheid.ctr.holder.utils.StringUtilImpl -import nl.rijksoverheid.ctr.holder.your_events.utils.EventGroupEntityUtil -import nl.rijksoverheid.ctr.holder.your_events.utils.EventGroupEntityUtilImpl -import nl.rijksoverheid.ctr.holder.your_events.utils.RemoteEventHolderUtil -import nl.rijksoverheid.ctr.holder.your_events.utils.RemoteEventHolderUtilImpl -import nl.rijksoverheid.ctr.holder.your_events.utils.RemoteEventStringUtil -import nl.rijksoverheid.ctr.holder.your_events.utils.RemoteEventStringUtilImpl -import nl.rijksoverheid.ctr.holder.your_events.utils.RemoteEventUtil -import nl.rijksoverheid.ctr.holder.your_events.utils.RemoteEventUtilImpl -import nl.rijksoverheid.ctr.holder.your_events.utils.RemoteProtocol3Util -import nl.rijksoverheid.ctr.holder.your_events.utils.RemoteProtocol3UtilImpl -import nl.rijksoverheid.ctr.holder.your_events.utils.YourEventsEndStateUtil -import nl.rijksoverheid.ctr.holder.your_events.utils.YourEventsEndStateUtilImpl -import nl.rijksoverheid.ctr.holder.your_events.utils.YourEventsFragmentUtil -import nl.rijksoverheid.ctr.holder.your_events.utils.YourEventsFragmentUtilImpl -import nl.rijksoverheid.ctr.holder.your_events.widgets.YourEventWidgetUtil -import nl.rijksoverheid.ctr.holder.your_events.widgets.YourEventWidgetUtilImpl import nl.rijksoverheid.rdo.modules.luhncheck.TokenValidator import nl.rijksoverheid.rdo.modules.luhncheck.TokenValidatorImpl -import org.koin.android.ext.koin.androidContext import org.koin.dsl.module /* @@ -74,57 +18,8 @@ import org.koin.dsl.module * */ val utilsModule = module { - factory { - DashboardGreenCardAdapterItemUtilImpl( - Clock.systemUTC(), - androidContext(), - get(), - get() - ) - } factory { TokenValidatorImpl() } - factory { CredentialUtilImpl(Clock.systemUTC(), get(), get(), get(), get()) } - factory { OriginUtilImpl(Clock.systemUTC()) } - factory { RemoteEventHolderUtilImpl(get(), get(), get(), get()) } - factory { RemoteProtocol3UtilImpl() } - factory { RemoteEventUtilImpl(get()) } - factory { RemoteEventStringUtilImpl(androidContext()::getString) } - factory { ReadEuropeanCredentialUtilImpl(get()) } - factory { - DashboardItemUtilImpl( - get(), - get(), - get(), - get(), - get(), - get() - ) - } factory { CountryUtilImpl() } factory { LocalDateUtilImpl(get(), get()) } - factory { MultipleQrCodesUtilImpl() } - factory { - DashboardPageInfoItemHandlerUtilImpl( - get(), - get(), - get() - ) - } - factory { QrCodesFragmentUtilImpl(Clock.systemUTC()) } - factory { YourEventsFragmentUtilImpl(get()) } - factory { YourEventWidgetUtilImpl() } - factory { DashboardInfoCardAdapterItemUtilImpl() } - factory { DashboardItemEmptyStateUtilImpl() } - factory { AboutThisAppDataModelImpl(get(), get(), get()) } - factory { HelpMenuDataModelImpl(get(), get(), get()) } - factory { ScopeUtilImpl() } - factory { LoginTypeUtilImpl() } - factory { DashboardHeaderAdapterItemUtilImpl() } - factory { CardItemUtilImpl() } - factory { EventGroupEntityUtilImpl(get()) } - factory { PaperProofUtilImpl(get(), get(), get()) } - factory { NoDigidScreenDataUtilImpl(get(), get(), get()) } factory { StringUtilImpl(get()) } - factory { YourEventsEndStateUtilImpl(get()) } - factory { RemovedEventsBottomSheetUtilImpl(get(), get(), get(), get(), get(), get()) } } diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/ViewModels.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/ViewModels.kt index d00cb9e31..6e367a68f 100644 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/ViewModels.kt +++ b/holder/src/main/java/nl/rijksoverheid/ctr/holder/modules/ViewModels.kt @@ -1,37 +1,12 @@ package nl.rijksoverheid.ctr.holder.modules -import nl.rijksoverheid.ctr.design.menu.MenuViewModel -import nl.rijksoverheid.ctr.holder.HolderMainActivityViewModel -import nl.rijksoverheid.ctr.holder.HolderMainActivityViewModelImpl -import nl.rijksoverheid.ctr.holder.dashboard.DashboardViewModel -import nl.rijksoverheid.ctr.holder.dashboard.DashboardViewModelImpl -import nl.rijksoverheid.ctr.holder.get_events.GetEventsViewModel -import nl.rijksoverheid.ctr.holder.get_events.GetEventsViewModelImpl -import nl.rijksoverheid.ctr.holder.get_events.LoginViewModel -import nl.rijksoverheid.ctr.holder.input_token.InputTokenViewModel -import nl.rijksoverheid.ctr.holder.input_token.InputTokenViewModelImpl -import nl.rijksoverheid.ctr.holder.menu.MenuViewModelImpl -import nl.rijksoverheid.ctr.holder.modules.qualifier.LoginQualifier -import nl.rijksoverheid.ctr.holder.pdf.PdfPreviewViewModel -import nl.rijksoverheid.ctr.holder.pdf.PdfPreviewViewModelImpl -import nl.rijksoverheid.ctr.holder.pdf.PdfWebViewModel -import nl.rijksoverheid.ctr.holder.pdf.PdfWebViewModelImpl -import nl.rijksoverheid.ctr.holder.qrcodes.QrCodesViewModel -import nl.rijksoverheid.ctr.holder.qrcodes.QrCodesViewModelImpl -import nl.rijksoverheid.ctr.holder.saved_events.SavedEventsViewModel -import nl.rijksoverheid.ctr.holder.sync_greencards.SyncGreenCardsViewModel -import nl.rijksoverheid.ctr.holder.sync_greencards.SyncGreenCardsViewModelImpl import nl.rijksoverheid.ctr.holder.ui.device_rooted.DeviceRootedViewModel import nl.rijksoverheid.ctr.holder.ui.device_rooted.DeviceRootedViewModelImpl import nl.rijksoverheid.ctr.holder.ui.device_secure.DeviceSecureViewModel import nl.rijksoverheid.ctr.holder.ui.device_secure.DeviceSecureViewModelImpl import nl.rijksoverheid.ctr.holder.ui.priority_notification.PriorityNotificationViewModel import nl.rijksoverheid.ctr.holder.ui.priority_notification.PriorityNotificationViewModelImpl -import nl.rijksoverheid.ctr.holder.your_events.YourEventsViewModel -import nl.rijksoverheid.ctr.holder.your_events.YourEventsViewModelImpl -import org.koin.android.ext.koin.androidContext import org.koin.androidx.viewmodel.dsl.viewModel -import org.koin.core.qualifier.named import org.koin.dsl.module /* @@ -42,18 +17,7 @@ import org.koin.dsl.module * */ val viewModels = module { - viewModel { QrCodesViewModelImpl(get(), get(), get()) } - viewModel { HolderMainActivityViewModelImpl() } - viewModel { InputTokenViewModelImpl(get(), get()) } viewModel { DeviceRootedViewModelImpl(get(), get()) } viewModel { DeviceSecureViewModelImpl(get(), get()) } - viewModel { YourEventsViewModelImpl(get(), get(), get()) } - viewModel { GetEventsViewModelImpl(get(), get(), get()) } - viewModel { DashboardViewModelImpl(get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get()) } - viewModel { SyncGreenCardsViewModelImpl(get(), get()) } - viewModel { SavedEventsViewModel(get(), get()) } - viewModel { MenuViewModelImpl(get(), get()) } viewModel { PriorityNotificationViewModelImpl(get()) } - viewModel { PdfWebViewModelImpl(androidContext().filesDir.path, get(), get()) } - viewModel { PdfPreviewViewModelImpl(get()) } } diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/no_digid/NoDigidFragment.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/no_digid/NoDigidFragment.kt deleted file mode 100644 index dc0630ff0..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/no_digid/NoDigidFragment.kt +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.no_digid - -import android.os.Bundle -import android.view.View -import androidx.fragment.app.Fragment -import androidx.navigation.fragment.navArgs -import nl.rijksoverheid.ctr.design.utils.InfoFragmentUtil -import nl.rijksoverheid.ctr.design.utils.IntentUtil -import nl.rijksoverheid.ctr.holder.HolderMainFragment -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.databinding.FragmentNoDigidBinding -import nl.rijksoverheid.ctr.holder.ui.create_qr.bind -import nl.rijksoverheid.ctr.shared.ext.navigateSafety -import org.koin.android.ext.android.inject - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -class NoDigidFragment : Fragment(R.layout.fragment_no_digid) { - - private val args: NoDigidFragmentArgs by navArgs() - private val intentUtil: IntentUtil by inject() - private val infoFragmentUtil: InfoFragmentUtil by inject() - - override fun onDestroyView() { - super.onDestroyView() - (parentFragment?.parentFragment as HolderMainFragment).presentLoading(false) - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - val binding = FragmentNoDigidBinding.bind(view) - - with(args.data) { - binding.title.text = title - if (description.isNotEmpty()) { - binding.description.text = description - } else { - binding.description.visibility = View.GONE - } - - binding.firstButton.bind( - title = firstNavigationButtonData.title, - subtitle = firstNavigationButtonData.subtitle, - logo = firstNavigationButtonData.icon - ) { - onButtonClick(firstNavigationButtonData) - } - - binding.secondButton.bind( - title = secondNavigationButtonData.title, - subtitle = secondNavigationButtonData.subtitle, - logo = secondNavigationButtonData.icon - ) { - onButtonClick(secondNavigationButtonData) - } - } - } - - private fun onButtonClick(data: NoDigidNavigationButtonData) { - when (data) { - is NoDigidNavigationButtonData.NoDigid -> { - navigateSafety( - NoDigidFragmentDirections.actionNoDigid(data.noDigidFragmentData) - ) - } - is NoDigidNavigationButtonData.Info -> { - infoFragmentUtil.presentFullScreen( - currentFragment = this, - toolbarTitle = getString(R.string.choose_provider_toolbar), - data = data.infoFragmentData - ) - } - is NoDigidNavigationButtonData.Link -> { - intentUtil.openUrl( - context = requireContext(), - url = data.externalUrl - ) - } - is NoDigidNavigationButtonData.Ggd -> { - navigateSafety( - NoDigidFragmentDirections.actionPap(args.data.originType) - ) - } - } - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/no_digid/NoDigidFragmentArguments.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/no_digid/NoDigidFragmentArguments.kt deleted file mode 100644 index 9d07eb595..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/no_digid/NoDigidFragmentArguments.kt +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.no_digid - -import android.os.Parcelable -import androidx.annotation.DrawableRes -import androidx.annotation.StringRes -import kotlinx.parcelize.Parcelize -import nl.rijksoverheid.ctr.design.fragments.info.InfoFragmentData -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteOriginType - -@Parcelize -data class NoDigidFragmentData( - val title: String, - val description: String, - val firstNavigationButtonData: NoDigidNavigationButtonData, - val secondNavigationButtonData: NoDigidNavigationButtonData, - val originType: RemoteOriginType -) : Parcelable - -sealed class NoDigidNavigationButtonData( - @StringRes open val title: Int, - open val subtitle: String? = null, - @DrawableRes open val icon: Int? = null -) : Parcelable { - - @Parcelize - data class NoDigid( - @StringRes override val title: Int, - override val subtitle: String? = null, - @DrawableRes override val icon: Int? = null, - val noDigidFragmentData: NoDigidFragmentData - ) : NoDigidNavigationButtonData(title, subtitle, icon) - - @Parcelize - data class Info( - @StringRes override val title: Int, - override val subtitle: String? = null, - @DrawableRes override val icon: Int? = null, - val infoFragmentData: InfoFragmentData.TitleDescriptionWithButton - ) : NoDigidNavigationButtonData(title, subtitle, icon) - - @Parcelize - data class Link( - @StringRes override val title: Int, - override val subtitle: String? = null, - @DrawableRes override val icon: Int? = null, - val externalUrl: String - ) : NoDigidNavigationButtonData(title, subtitle, icon) - - @Parcelize - data class Ggd( - @StringRes override val title: Int, - override val subtitle: String? = null, - @DrawableRes override val icon: Int? = null - ) : NoDigidNavigationButtonData(title, subtitle, icon) -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/no_digid/NoDigidScreenDataUtil.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/no_digid/NoDigidScreenDataUtil.kt deleted file mode 100644 index 6a1f432ef..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/no_digid/NoDigidScreenDataUtil.kt +++ /dev/null @@ -1,126 +0,0 @@ -package nl.rijksoverheid.ctr.holder.no_digid - -import android.content.Context -import androidx.annotation.StringRes -import nl.rijksoverheid.ctr.appconfig.usecases.CachedAppConfigUseCase -import nl.rijksoverheid.ctr.design.fragments.info.ButtonData -import nl.rijksoverheid.ctr.design.fragments.info.DescriptionData -import nl.rijksoverheid.ctr.design.fragments.info.InfoFragmentData -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteOriginType -import nl.rijksoverheid.ctr.holder.usecases.HolderFeatureFlagUseCase - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -interface NoDigidScreenDataUtil { - fun requestDigidButton(): NoDigidNavigationButtonData - fun continueWithoutDigidButton(originType: RemoteOriginType): NoDigidNavigationButtonData -} - -class NoDigidScreenDataUtilImpl( - private val context: Context, - private val holderFeatureFlagUseCase: HolderFeatureFlagUseCase, - private val cachedAppConfigUseCase: CachedAppConfigUseCase -) : NoDigidScreenDataUtil { - - private fun getString(@StringRes stringId: Int) = context.getString(stringId) - - private fun getStringArgs(@StringRes stringId: Int, args: Array) = - context.getString(stringId, *args) - - val contactInformation = cachedAppConfigUseCase.getCachedAppConfig().contactInfo - val description = getStringArgs( - R.string.holder_contactCoronaCheckHelpdesk_message, - arrayOf( - PapFragment.openDaysString(context, contactInformation), - contactInformation.startHour, - contactInformation.endHour, - contactInformation.phoneNumber, - contactInformation.phoneNumber, - contactInformation.phoneNumberAbroad, - contactInformation.phoneNumberAbroad - ) - ) - private val doesHaveBSNButton = NoDigidNavigationButtonData.Info( - title = R.string.holder_checkForBSN_buttonTitle_doesHaveBSN, - subtitle = getString(R.string.holder_checkForBSN_buttonSubTitle_doesHaveBSN), - infoFragmentData = InfoFragmentData.TitleDescriptionWithButton( - title = getString(R.string.holder_contactCoronaCheckHelpdesk_title), - descriptionData = DescriptionData( - htmlTextString = description, - htmlLinksEnabled = true - ), - primaryButtonData = ButtonData.NavigationButton( - text = getString(R.string.general_toMyOverview), - navigationActionId = R.id.action_my_overview - ) - ) - ) - - private fun doesNotHaveBSNButton(originType: RemoteOriginType): NoDigidNavigationButtonData { - val title = R.string.holder_checkForBSN_buttonTitle_doesNotHaveBSN - val subtitle = getString( - if (originType == RemoteOriginType.Vaccination) { - R.string.holder_checkForBSN_buttonSubTitle_doesNotHaveBSN_vaccinationFlow - } else { - R.string.holder_checkForBSN_buttonSubTitle_doesNotHaveBSN_testFlow - } - ) - - return if (holderFeatureFlagUseCase.getPapEnabled()) { - NoDigidNavigationButtonData.Ggd( - title = title, - subtitle = subtitle - ) - } else { - NoDigidNavigationButtonData.Info( - title = title, - subtitle = subtitle, - infoFragmentData = InfoFragmentData.TitleDescriptionWithButton( - title = getString( - if (originType == RemoteOriginType.Vaccination) { - R.string.holder_contactProviderHelpdesk_vaccinationFlow_title - } else { - R.string.holder_contactProviderHelpdesk_testFlow_title - } - ), - descriptionData = DescriptionData( - if (originType == RemoteOriginType.Vaccination) { - R.string.holder_contactProviderHelpdesk_vaccinationFlow_message - } else { - R.string.holder_contactProviderHelpdesk_testFlow_message - } - ), - primaryButtonData = ButtonData.NavigationButton( - text = getString(R.string.general_toMyOverview), - navigationActionId = R.id.action_my_overview - ) - ) - ) - } - } - - override fun requestDigidButton() = NoDigidNavigationButtonData.Link( - title = R.string.holder_noDigiD_buttonTitle_requestDigiD, - icon = R.drawable.ic_digid_logo, - externalUrl = getString(R.string.holder_noDigiD_url) - ) - - override fun continueWithoutDigidButton(originType: RemoteOriginType) = - NoDigidNavigationButtonData.NoDigid( - title = R.string.holder_noDigiD_buttonTitle_continueWithoutDigiD, - subtitle = getString(R.string.holder_noDigiD_buttonSubTitle_continueWithoutDigiD), - noDigidFragmentData = NoDigidFragmentData( - title = getString(R.string.holder_checkForBSN_title), - description = getString(R.string.holder_checkForBSN_message), - firstNavigationButtonData = doesHaveBSNButton, - secondNavigationButtonData = doesNotHaveBSNButton(originType), - originType = originType - ) - ) -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/no_digid/PapFragment.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/no_digid/PapFragment.kt deleted file mode 100644 index e0b0ecf14..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/no_digid/PapFragment.kt +++ /dev/null @@ -1,247 +0,0 @@ -package nl.rijksoverheid.ctr.holder.no_digid - -import android.annotation.SuppressLint -import android.content.Context -import android.os.Bundle -import android.view.View -import androidx.core.view.isVisible -import androidx.navigation.fragment.navArgs -import java.time.DayOfWeek -import java.time.format.TextStyle -import nl.rijksoverheid.ctr.appconfig.api.model.AppConfig -import nl.rijksoverheid.ctr.appconfig.usecases.CachedAppConfigUseCase -import nl.rijksoverheid.ctr.design.fragments.info.ButtonData -import nl.rijksoverheid.ctr.design.fragments.info.DescriptionData -import nl.rijksoverheid.ctr.design.fragments.info.InfoFragmentData -import nl.rijksoverheid.ctr.design.utils.DialogFragmentData -import nl.rijksoverheid.ctr.design.utils.InfoFragmentUtil -import nl.rijksoverheid.ctr.holder.HolderMainFragment -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.databinding.FragmentNoDigidBinding -import nl.rijksoverheid.ctr.holder.get_events.DigiDFragment -import nl.rijksoverheid.ctr.holder.get_events.GetEventsFragmentDirections -import nl.rijksoverheid.ctr.holder.get_events.models.EventProvider -import nl.rijksoverheid.ctr.holder.get_events.models.LoginType -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteOriginType -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteProtocol -import nl.rijksoverheid.ctr.holder.models.HolderFlow -import nl.rijksoverheid.ctr.holder.ui.create_qr.bind -import nl.rijksoverheid.ctr.holder.ui.create_qr.setEnabled -import nl.rijksoverheid.ctr.holder.usecases.HolderFeatureFlagUseCase -import nl.rijksoverheid.ctr.holder.your_events.YourEventsFragmentType -import nl.rijksoverheid.ctr.shared.ext.locale -import nl.rijksoverheid.ctr.shared.ext.navigateSafety -import nl.rijksoverheid.ctr.shared.livedata.EventObserver -import nl.rijksoverheid.ctr.shared.models.Flow -import nl.rijksoverheid.ctr.shared.utils.Accessibility.makeIndeterminateAccessible -import org.koin.android.ext.android.inject - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -class PapFragment : DigiDFragment(R.layout.fragment_no_digid) { - - private var _binding: FragmentNoDigidBinding? = null - private val binding: FragmentNoDigidBinding get() = _binding!! - private val args: PapFragmentArgs by navArgs() - private val infoFragmentUtil: InfoFragmentUtil by inject() - private val holderFeatureFlagUseCase: HolderFeatureFlagUseCase by inject() - private val cachedAppConfigUseCase: CachedAppConfigUseCase by inject() - - companion object { - @SuppressLint("StringFormatInvalid") - fun openDaysString(context: Context, contactInformation: AppConfig.ContactInformation): String { - val startDay = contactInformation.startDay - val endDay = contactInformation.endDay - - if (startDay == 1 && endDay == 7) { - return context.getString(R.string.holder_contactCoronaCheckHelpdesk_message_every_day) - } - - val startDayOfWeek = DayOfWeek.of(contactInformation.startDay).getDisplayName(TextStyle.FULL, context.locale()) - val endDayOfWeek = DayOfWeek.of(contactInformation.endDay).getDisplayName(TextStyle.FULL, context.locale()) - - return context.getString(R.string.holder_contactCoronaCheckHelpdesk_message_until, startDayOfWeek, endDayOfWeek) - } - } - - override fun onButtonClickWithRetryAction() { - loginWithDigiD() - } - - override fun getFlow(): Flow { - return when (args.originType) { - RemoteOriginType.Recovery -> HolderFlow.Recovery - RemoteOriginType.Test -> HolderFlow.DigidTest - RemoteOriginType.Vaccination -> HolderFlow.Vaccination - } - } - - override fun onDestroyView() { - super.onDestroyView() - (parentFragment?.parentFragment as HolderMainFragment).presentLoading(false) - } - - @SuppressLint("StringFormatInvalid") - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - _binding = FragmentNoDigidBinding.bind(view) - - if (args.originType is RemoteOriginType.Vaccination) { - binding.title.text = getString(R.string.holder_chooseEventLocation_title) - binding.description.visibility = View.GONE - binding.firstButton.bind( - title = R.string.holder_chooseEventLocation_buttonTitle_GGD, - subtitle = getString(R.string.holder_chooseEventLocation_buttonSubTitle_GGD) - ) { - loginWithDigiD() - } - - binding.secondButton.bind( - title = R.string.holder_chooseEventLocation_buttonTitle_other, - subtitle = getString(R.string.holder_chooseEventLocation_buttonSubTitle_other) - ) { - infoFragmentUtil.presentFullScreen( - currentFragment = this@PapFragment, - toolbarTitle = getString(R.string.choose_provider_toolbar), - data = InfoFragmentData.TitleDescriptionWithButton( - title = getString(R.string.holder_contactProviderHelpdesk_vaccinationFlow_title), - descriptionData = DescriptionData(R.string.holder_contactProviderHelpdesk_message_ggdPortalEnabled), - primaryButtonData = ButtonData.NavigationButton( - text = getString(R.string.general_toMyOverview), - navigationActionId = R.id.action_my_overview - ) - ) - ) - } - } else { - binding.title.text = getString(R.string.holder_checkForBSN_title) - binding.description.text = getString(R.string.holder_checkForBSN_message) - binding.description.visibility = View.VISIBLE - binding.firstButton.bind( - title = R.string.holder_checkForBSN_buttonTitle_doesHaveBSN, - subtitle = getString(R.string.holder_checkForBSN_buttonSubTitle_doesHaveBSN) - ) { - val contactInformation = cachedAppConfigUseCase.getCachedAppConfig().contactInfo - infoFragmentUtil.presentFullScreen( - currentFragment = this@PapFragment, - toolbarTitle = getString(R.string.choose_provider_toolbar), - data = InfoFragmentData.TitleDescriptionWithButton( - title = getString(R.string.holder_contactCoronaCheckHelpdesk_title), - descriptionData = DescriptionData( - htmlTextString = getString( - R.string.holder_contactCoronaCheckHelpdesk_message, - openDaysString(requireContext(), contactInformation), - contactInformation.startHour, - contactInformation.endHour, - contactInformation.phoneNumber, - contactInformation.phoneNumber, - contactInformation.phoneNumberAbroad, - contactInformation.phoneNumberAbroad - ), - htmlLinksEnabled = true - ), - primaryButtonData = ButtonData.NavigationButton( - text = getString(R.string.general_toMyOverview), - navigationActionId = R.id.action_my_overview - ) - ) - ) - } - - binding.secondButton.bind( - title = R.string.holder_checkForBSN_buttonTitle_doesNotHaveBSN, - subtitle = getString(R.string.holder_checkForBSN_buttonSubTitle_doesNotHaveBSN_testFlow) - ) { - if (holderFeatureFlagUseCase.getPapEnabled()) { - /** disable accessibility, otherwise it is announced when loading is finished - * reenable with [dialogPresented] if a dialog is presented cause then the user will again interact with it - */ - binding.secondButton.root.importantForAccessibility = - View.IMPORTANT_FOR_ACCESSIBILITY_NO - loginWithDigiD() - } else { - infoFragmentUtil.presentFullScreen( - currentFragment = this@PapFragment, - toolbarTitle = getString(R.string.choose_provider_toolbar), - data = InfoFragmentData.TitleDescriptionWithButton( - title = getString(R.string.holder_contactProviderHelpdesk_testFlow_title), - descriptionData = DescriptionData(R.string.holder_contactProviderHelpdesk_testFlow_message), - primaryButtonData = ButtonData.NavigationButton( - text = getString(R.string.general_toMyOverview), - navigationActionId = R.id.action_my_overview - ) - ) - ) - } - } - } - } - - override fun getLoginType(): LoginType { - return LoginType.Pap - } - - private fun setEnabled(enabled: Boolean) { - binding.title.isEnabled = enabled - binding.description.isEnabled = enabled - } - - override fun onDigidLoading(loading: Boolean) { - binding.firstButton.setEnabled(!loading) - binding.secondButton.setEnabled(!loading) - setEnabled(!loading) - } - - override fun onGetEventsLoading(loading: Boolean) { - binding.loadingOverlay.progressBar.makeIndeterminateAccessible( - context = requireContext(), - isLoading = loading, - message = R.string.holder_fetchevents_loading - ) - binding.loadingOverlay.root.isVisible = loading - } - - override fun getOriginTypes(): List { - return listOf(args.originType) - } - - override fun onNavigateToYourEvents( - remoteProtocols: Map, - eventProviders: List - ) { - navigateSafety( - GetEventsFragmentDirections.actionYourEvents( - type = YourEventsFragmentType.RemoteProtocol3Type( - remoteEvents = remoteProtocols, - eventProviders = eventProviders - ), - toolbarTitle = getCopyForOriginType().toolbarTitle, - flow = getFlow() - ) - ) - } - - override fun yourEventsFragmentType( - remoteProtocols: Map, - eventProviders: List - ): YourEventsFragmentType { - return YourEventsFragmentType.RemoteProtocol3Type( - remoteEvents = remoteProtocols, - eventProviders = eventProviders - ) - } - - override fun dialogPresented() { - binding.secondButton.root.importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_YES - } - - override fun openDialog(data: DialogFragmentData) { - navigateSafety(PapFragmentDirections.actionDialog(data)) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/paper_proof/models/PaperProofDomesticCodeResult.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/paper_proof/models/PaperProofDomesticCodeResult.kt deleted file mode 100644 index eae0e08bb..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/paper_proof/models/PaperProofDomesticCodeResult.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.paper_proof.models - -import android.os.Parcelable -import kotlinx.parcelize.Parcelize - -sealed class PaperProofDomesticCodeResult : Parcelable { - @Parcelize - object Valid : PaperProofDomesticCodeResult(), Parcelable - - @Parcelize - object Invalid : PaperProofDomesticCodeResult(), Parcelable - - @Parcelize - object Empty : PaperProofDomesticCodeResult(), Parcelable -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/paper_proof/models/PaperProofDomesticResult.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/paper_proof/models/PaperProofDomesticResult.kt deleted file mode 100644 index 5c383924e..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/paper_proof/models/PaperProofDomesticResult.kt +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.paper_proof.models - -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteProtocol -import nl.rijksoverheid.ctr.shared.models.ErrorResult - -sealed class PaperProofDomesticResult { - data class Valid( - val remoteEvent: RemoteProtocol, - val eventGroupJsonData: ByteArray - ) : PaperProofDomesticResult() { - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false - - other as Valid - - if (remoteEvent != other.remoteEvent) return false - if (!eventGroupJsonData.contentEquals(other.eventGroupJsonData)) return false - - return true - } - - override fun hashCode(): Int { - var result = remoteEvent.hashCode() - result = 31 * result + eventGroupJsonData.contentHashCode() - return result - } - } - - sealed class Invalid : PaperProofDomesticResult() { - object RejectedQr : Invalid() - object BlockedQr : Invalid() - data class Error(val errorResult: ErrorResult) : Invalid() - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/paper_proof/models/PaperProofType.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/paper_proof/models/PaperProofType.kt deleted file mode 100644 index c4183a79d..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/paper_proof/models/PaperProofType.kt +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.paper_proof.models - -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteProtocol - -sealed class PaperProofType { - sealed class DCC : PaperProofType() { - data class Foreign( - val remoteProtocol: RemoteProtocol, - val eventGroupJsonData: ByteArray - ) : DCC() { - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false - - other as Foreign - - if (remoteProtocol != other.remoteProtocol) return false - if (!eventGroupJsonData.contentEquals(other.eventGroupJsonData)) return false - - return true - } - - override fun hashCode(): Int { - var result = remoteProtocol.hashCode() - result = 31 * result + eventGroupJsonData.contentHashCode() - return result - } - } - - data class Dutch(val qrContent: String) : DCC() - } - object CTB : PaperProofType() - object Unknown : PaperProofType() -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/paper_proof/models/RemoteCouplingResponse.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/paper_proof/models/RemoteCouplingResponse.kt deleted file mode 100644 index cb843c508..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/paper_proof/models/RemoteCouplingResponse.kt +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.paper_proof.models - -import com.squareup.moshi.JsonClass - -@JsonClass(generateAdapter = true) -data class RemoteCouplingResponse( - val status: RemoteCouplingStatus -) diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/paper_proof/models/RemoteCouplingStatus.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/paper_proof/models/RemoteCouplingStatus.kt deleted file mode 100644 index 4029f2f9d..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/paper_proof/models/RemoteCouplingStatus.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.paper_proof.models - -sealed class RemoteCouplingStatus(val typeString: String) { - - companion object { - const val TYPE_ACCEPTED = "accepted" - const val TYPE_REJECTED = "rejected" - const val TYPE_BLOCKED = "blocked" - const val TYPE_EXPIRED = "expired" - } - - object Accepted : RemoteCouplingStatus(TYPE_ACCEPTED) - object Rejected : RemoteCouplingStatus(TYPE_REJECTED) - object Blocked : RemoteCouplingStatus(TYPE_BLOCKED) - object Expired : RemoteCouplingStatus(TYPE_EXPIRED) -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/paper_proof/usecases/GetDccFromEuropeanCredentialUseCase.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/paper_proof/usecases/GetDccFromEuropeanCredentialUseCase.kt deleted file mode 100644 index a47703377..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/paper_proof/usecases/GetDccFromEuropeanCredentialUseCase.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.paper_proof.usecases - -import nl.rijksoverheid.ctr.shared.MobileCoreWrapper -import org.json.JSONObject - -interface GetDccFromEuropeanCredentialUseCase { - fun get(europeanCredential: ByteArray): JSONObject -} - -class GetDccFromEuropeanCredentialUseCaseImpl( - private val mobileCoreWrapper: MobileCoreWrapper -) : GetDccFromEuropeanCredentialUseCase { - - override fun get(europeanCredential: ByteArray): JSONObject { - val credentials = mobileCoreWrapper.readEuropeanCredential(europeanCredential) - return requireNotNull(credentials.optJSONObject("dcc")) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/paper_proof/usecases/GetEventsFromPaperProofQrUseCase.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/paper_proof/usecases/GetEventsFromPaperProofQrUseCase.kt deleted file mode 100644 index b5101d35e..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/paper_proof/usecases/GetEventsFromPaperProofQrUseCase.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.paper_proof.usecases - -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteConfigProviders -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEventVaccination -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteProtocol -import nl.rijksoverheid.ctr.holder.your_events.utils.RemoteEventUtil -import nl.rijksoverheid.ctr.shared.MobileCoreWrapper -import org.json.JSONException - -interface GetEventsFromPaperProofQrUseCase { - fun get(qrCode: String): RemoteProtocol -} - -class GetEventsFromPaperProofQrUseCaseImpl( - private val mobileCoreWrapper: MobileCoreWrapper, - private val remoteEventUtil: RemoteEventUtil -) : GetEventsFromPaperProofQrUseCase { - - @Throws(NullPointerException::class, JSONException::class) - override fun get(qrCode: String): RemoteProtocol { - val credential = qrCode.toByteArray() - val credentials = mobileCoreWrapper.readEuropeanCredential(credential) - val dcc = credentials.optJSONObject("dcc") - val holder = remoteEventUtil.getHolderFromDcc(dcc!!) - val event = remoteEventUtil.getRemoteEventFromDcc(dcc) - - val providerIdentifier = when (event) { - is RemoteEventVaccination -> { - // For hkvi vaccination events we want to be able to save multiple events (for example you get 2 papers, one with your first vaccination and another with your second) - // The database prevents us from doing so because it has uniques on both providerIdentifier and type - // For hkvi vaccinations we add the unique to the provider identifier so it gets saved as well - RemoteConfigProviders.EventProvider.PROVIDER_IDENTIFIER_DCC_SUFFIX.replace("[unique]", event.unique ?: "") - } - else -> { - RemoteConfigProviders.EventProvider.PROVIDER_IDENTIFIER_DCC - } - } - - return RemoteProtocol( - providerIdentifier = providerIdentifier, - protocolVersion = "3.0", - status = RemoteProtocol.Status.COMPLETE, - holder = holder, - events = listOf(event) - ) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/paper_proof/usecases/GetPaperProofTypeUseCase.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/paper_proof/usecases/GetPaperProofTypeUseCase.kt deleted file mode 100644 index 4f2e78f89..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/paper_proof/usecases/GetPaperProofTypeUseCase.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.paper_proof.usecases - -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import nl.rijksoverheid.ctr.holder.paper_proof.models.PaperProofType -import nl.rijksoverheid.ctr.holder.paper_proof.utils.PaperProofUtil -import nl.rijksoverheid.ctr.shared.MobileCoreWrapper - -interface GetPaperProofTypeUseCase { - suspend fun get(qrContent: String): PaperProofType -} - -class GetPaperProofTypeUseCaseImpl( - private val getEventsFromPaperProofQrUseCase: GetEventsFromPaperProofQrUseCase, - private val paperProofUtil: PaperProofUtil, - private val mobileCoreWrapper: MobileCoreWrapper -) : GetPaperProofTypeUseCase { - override suspend fun get(qrContent: String): PaperProofType { - return withContext(Dispatchers.IO) { - val isForeign = mobileCoreWrapper.isForeignDcc(qrContent.toByteArray()) - val event = try { - getEventsFromPaperProofQrUseCase.get(qrContent) - } catch (exception: Exception) { - return@withContext PaperProofType.Unknown - } - - if (isForeign) { - PaperProofType.DCC.Foreign( - remoteProtocol = event, - eventGroupJsonData = paperProofUtil.getEventGroupJsonData(qrContent = qrContent) - ) - } else { - PaperProofType.DCC.Dutch( - qrContent = qrContent - ) - } - } - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/paper_proof/usecases/ValidatePaperProofDomesticInputCodeUseCase.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/paper_proof/usecases/ValidatePaperProofDomesticInputCodeUseCase.kt deleted file mode 100644 index 7f542e3c5..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/paper_proof/usecases/ValidatePaperProofDomesticInputCodeUseCase.kt +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.paper_proof.usecases - -import nl.rijksoverheid.ctr.holder.paper_proof.models.PaperProofDomesticCodeResult - -interface ValidatePaperProofDomesticInputCodeUseCase { - companion object { - const val CODE_POINTS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567" - } - - fun validate(code: String): PaperProofDomesticCodeResult -} - -class ValidatePaperProofDomesticInputCodeUseCaseImpl : ValidatePaperProofDomesticInputCodeUseCase { - - override fun validate(code: String): PaperProofDomesticCodeResult { - code.toCharArray().forEach { - if (!ValidatePaperProofDomesticInputCodeUseCase.CODE_POINTS.contains(it)) { - return PaperProofDomesticCodeResult.Invalid - } - } - - return when (code.length) { - 0 -> PaperProofDomesticCodeResult.Empty - 6 -> PaperProofDomesticCodeResult.Valid - else -> PaperProofDomesticCodeResult.Invalid - } - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/paper_proof/usecases/ValidatePaperProofDomesticUseCase.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/paper_proof/usecases/ValidatePaperProofDomesticUseCase.kt deleted file mode 100644 index 315a3bdc8..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/paper_proof/usecases/ValidatePaperProofDomesticUseCase.kt +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.paper_proof.usecases - -import nl.rijksoverheid.ctr.holder.api.repositories.CoronaCheckRepository -import nl.rijksoverheid.ctr.holder.models.HolderStep -import nl.rijksoverheid.ctr.holder.paper_proof.models.PaperProofDomesticResult -import nl.rijksoverheid.ctr.holder.paper_proof.models.RemoteCouplingStatus -import nl.rijksoverheid.ctr.holder.paper_proof.utils.PaperProofUtil -import nl.rijksoverheid.ctr.shared.models.AppErrorResult -import nl.rijksoverheid.ctr.shared.models.NetworkRequestResult - -interface ValidatePaperProofDomesticUseCase { - suspend fun validate(qrContent: String, couplingCode: String): PaperProofDomesticResult -} - -class ValidatePaperProofDomesticUseCaseImpl( - private val coronaCheckRepository: CoronaCheckRepository, - private val getEventsFromPaperProofQr: GetEventsFromPaperProofQrUseCase, - private val paperProofUtil: PaperProofUtil -) : ValidatePaperProofDomesticUseCase { - - override suspend fun validate( - qrContent: String, - couplingCode: String - ): PaperProofDomesticResult { - return try { - val networkRequestResult = coronaCheckRepository.getCoupling( - credential = qrContent, - couplingCode = couplingCode - ) - - when (networkRequestResult) { - is NetworkRequestResult.Success -> { - when (networkRequestResult.response.status) { - RemoteCouplingStatus.Accepted -> validateSuccess(qrContent, couplingCode) - RemoteCouplingStatus.Rejected -> PaperProofDomesticResult.Invalid.RejectedQr - RemoteCouplingStatus.Blocked -> PaperProofDomesticResult.Invalid.BlockedQr - RemoteCouplingStatus.Expired -> validateSuccess(qrContent, couplingCode) - } - } - is NetworkRequestResult.Failed -> { - PaperProofDomesticResult.Invalid.Error(networkRequestResult) - } - } - } catch (e: Exception) { - PaperProofDomesticResult.Invalid.Error( - AppErrorResult( - step = HolderStep.CouplingNetworkRequest, - e = e - ) - ) - } - } - - private fun validateSuccess( - qrContent: String, - couplingCode: String - ) = PaperProofDomesticResult.Valid( - remoteEvent = getEventsFromPaperProofQr.get(qrContent), - eventGroupJsonData = paperProofUtil.getEventGroupJsonData( - qrContent = qrContent, - couplingCode = couplingCode - ) - ) -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/paper_proof/utils/PaperProofUtil.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/paper_proof/utils/PaperProofUtil.kt deleted file mode 100644 index dd5eb645f..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/paper_proof/utils/PaperProofUtil.kt +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.paper_proof.utils - -import android.content.Context -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.paper_proof.usecases.GetDccFromEuropeanCredentialUseCase -import nl.rijksoverheid.ctr.shared.MobileCoreWrapper -import nl.rijksoverheid.ctr.shared.ext.getStringOrNull -import org.json.JSONObject - -interface PaperProofUtil { - fun getEventGroupJsonData( - qrContent: String, - couplingCode: String? = null - ): ByteArray - - fun getIssuer( - europeanCredential: ByteArray - ): String - - fun getInfoScreenFooterText( - europeanCredential: ByteArray - ): String -} - -class PaperProofUtilImpl( - private val context: Context, - private val mobileCoreWrapper: MobileCoreWrapper, - private val getDccFromEuropeanCredentialUseCase: GetDccFromEuropeanCredentialUseCase -) : PaperProofUtil { - - override fun getEventGroupJsonData( - qrContent: String, - couplingCode: String? - ): ByteArray = JSONObject( - mutableMapOf("credential" to qrContent) - .also { map -> - couplingCode?.let { couplingCode -> - map["couplingCode"] = couplingCode - } - } - .toMap()) - .toString() - .toByteArray() - - override fun getIssuer(europeanCredential: ByteArray): String { - val dcc = getDccFromEuropeanCredentialUseCase.get(europeanCredential) - val proof = dcc.optJSONArray("v") ?: dcc.optJSONArray("t") ?: dcc.optJSONArray("r") - return proof?.optJSONObject(0)?.getStringOrNull("is") ?: "" - } - - override fun getInfoScreenFooterText(europeanCredential: ByteArray): String { - val resource = if (mobileCoreWrapper.isForeignDcc(europeanCredential)) { - R.string.holder_listRemoteEvents_somethingWrong_foreignDCC_body - } else { - R.string.paper_proof_event_explanation_footer - } - return context.getString(resource) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/pdf/EUPrintAttributes.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/pdf/EUPrintAttributes.kt deleted file mode 100644 index 01eb1c89e..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/pdf/EUPrintAttributes.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2023 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ - -package nl.rijksoverheid.ctr.holder.pdf - -import com.squareup.moshi.JsonClass -import java.time.OffsetDateTime -import org.json.JSONObject - -@JsonClass(generateAdapter = true) -data class EUPrintAttributes( - val dcc: JSONObject, - val expirationTime: OffsetDateTime, - val qr: String -) - -@JsonClass(generateAdapter = true) -data class PrintAttributes(val european: List) diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/pdf/ExportIntroductionFragment.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/pdf/ExportIntroductionFragment.kt deleted file mode 100644 index e013fe1a0..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/pdf/ExportIntroductionFragment.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2023 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ - -package nl.rijksoverheid.ctr.holder.pdf - -import android.os.Bundle -import android.view.View -import androidx.core.view.isVisible -import androidx.fragment.app.Fragment -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.databinding.FragmentExportIntroductionBinding -import nl.rijksoverheid.ctr.shared.ext.navigateSafety -import nl.rijksoverheid.ctr.shared.utils.AndroidUtil -import org.koin.android.ext.android.inject - -class ExportIntroductionFragment : Fragment(R.layout.fragment_export_introduction) { - - private val androidUtil: AndroidUtil by inject() - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - val binding = FragmentExportIntroductionBinding.bind(view) - binding.bottom.setButtonClick { - navigateSafety(ExportIntroductionFragmentDirections.actionPdfWebview()) - } - - if (androidUtil.isSmallScreen()) { - binding.image.isVisible = false - } - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/pdf/PDfPreviewInfo.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/pdf/PDfPreviewInfo.kt deleted file mode 100644 index 316d94d90..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/pdf/PDfPreviewInfo.kt +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright (c) 2023 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -package nl.rijksoverheid.ctr.holder.pdf - -data class PDfPreviewInfo(val content: String, val initialZoom: Int) diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/pdf/PdfExportedFragment.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/pdf/PdfExportedFragment.kt deleted file mode 100644 index 2ddd454db..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/pdf/PdfExportedFragment.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2023 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ - -package nl.rijksoverheid.ctr.holder.pdf - -import android.content.Intent -import android.os.Bundle -import android.view.View -import androidx.core.content.FileProvider -import androidx.fragment.app.Fragment -import java.io.File -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.databinding.FragmentPdfExportedBinding -import nl.rijksoverheid.ctr.shared.ext.navigateSafety - -class PdfExportedFragment : Fragment(R.layout.fragment_pdf_exported) { - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - val binding = FragmentPdfExportedBinding.bind(view) - - binding.previewPdfButton.setOnClickListener { - navigateSafety( - PdfExportedFragmentDirections.actionPdfPreview( - toolbarTitle = PdfWebViewFragment.pdfFileName - ) - ) - } - - binding.savePdfButton.setOnClickListener { - val pdfFile = File(requireContext().filesDir, PdfWebViewFragment.pdfFileName) - startActivity( - Intent.createChooser(Intent().apply { - action = Intent.ACTION_SEND - type = "application/pdf" - putExtra( - Intent.EXTRA_STREAM, - FileProvider.getUriForFile( - requireContext(), - requireContext().applicationContext.packageName + ".provider", - pdfFile - ) - ) - addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) - }, getString(R.string.holder_pdfExport_success_card_action_save)) - ) - } - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/pdf/PdfPreview.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/pdf/PdfPreview.kt deleted file mode 100644 index 5ee745e18..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/pdf/PdfPreview.kt +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright (c) 2023 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -package nl.rijksoverheid.ctr.holder.pdf - -sealed class PdfPreview { - class Success(val info: PDfPreviewInfo) : PdfPreview() - object Error : PdfPreview() -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/pdf/PdfPreviewFragment.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/pdf/PdfPreviewFragment.kt deleted file mode 100644 index 58624901b..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/pdf/PdfPreviewFragment.kt +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2023 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -package nl.rijksoverheid.ctr.holder.pdf - -import android.os.Bundle -import android.view.View -import androidx.fragment.app.Fragment -import nl.rijksoverheid.ctr.design.utils.DialogButtonData -import nl.rijksoverheid.ctr.design.utils.DialogFragmentData -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.databinding.FragmentPdfPreviewBinding -import nl.rijksoverheid.ctr.shared.ext.navigateSafety -import nl.rijksoverheid.ctr.shared.livedata.EventObserver -import org.koin.androidx.viewmodel.ext.android.viewModel - -class PdfPreviewFragment : Fragment(R.layout.fragment_pdf_preview) { - - private val viewModel: PdfPreviewViewModel by viewModel() - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - val binding = FragmentPdfPreviewBinding.bind(view) - - binding.pdfWebView.settings.builtInZoomControls = true - binding.pdfWebView.settings.displayZoomControls = false - binding.pdfWebView.settings.allowFileAccess = true - - viewModel.previewLiveData.observe(viewLifecycleOwner, EventObserver { - when (it) { - is PdfPreview.Success -> { - binding.pdfWebView.setInitialScale(it.info.initialZoom) - binding.pdfWebView.loadDataWithBaseURL( - "file:///android_asset/", - "", - "text/html", - "utf-8", - "" - ) - } - - is PdfPreview.Error -> { - navigateSafety( - PdfPreviewFragmentDirections.actionDialog( - data = DialogFragmentData( - title = R.string.holder_pdfExport_storageFull_errorDialog_title, - message = R.string.holder_pdfExport_storageFull_errorDialog_message, - positiveButtonData = DialogButtonData.NavigateUp(R.string.dialog_close) - ) - ) - ) - } - } - }) - - viewModel.generatePreview( - screenWidth = resources.displayMetrics.widthPixels, - filesDir = requireContext().filesDir - ) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/pdf/PdfPreviewViewModel.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/pdf/PdfPreviewViewModel.kt deleted file mode 100644 index 782e9d831..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/pdf/PdfPreviewViewModel.kt +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2023 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -package nl.rijksoverheid.ctr.holder.pdf - -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import java.io.File -import kotlinx.coroutines.launch -import nl.rijksoverheid.ctr.shared.livedata.Event - -abstract class PdfPreviewViewModel : ViewModel() { - val previewLiveData = MutableLiveData>() - abstract fun generatePreview(screenWidth: Int, filesDir: File) -} - -class PdfPreviewViewModelImpl( - private val previewPdfUseCase: PreviewPdfUseCase -) : PdfPreviewViewModel() { - override fun generatePreview(screenWidth: Int, filesDir: File) { - viewModelScope.launch { - val pdfPreviewResult = previewPdfUseCase.generatePreview(screenWidth, filesDir) - if (pdfPreviewResult != null) { - previewLiveData.postValue(Event(PdfPreview.Success(pdfPreviewResult))) - } else { - previewLiveData.postValue(Event(PdfPreview.Error)) - } - } - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/pdf/PdfWebViewFragment.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/pdf/PdfWebViewFragment.kt deleted file mode 100644 index ae7567c87..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/pdf/PdfWebViewFragment.kt +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (c) 2023 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ - -package nl.rijksoverheid.ctr.holder.pdf - -import android.annotation.SuppressLint -import android.content.Context -import android.os.Bundle -import android.view.View -import android.webkit.JavascriptInterface -import android.webkit.WebView -import android.webkit.WebViewClient -import androidx.core.view.isVisible -import nl.rijksoverheid.ctr.appconfig.usecases.CachedAppConfigUseCase -import nl.rijksoverheid.ctr.holder.BaseFragment -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.databinding.FragmentPdfWebviewBinding -import nl.rijksoverheid.ctr.holder.models.HolderFlow -import nl.rijksoverheid.ctr.holder.models.HolderStep -import nl.rijksoverheid.ctr.shared.exceptions.LoadFileException -import nl.rijksoverheid.ctr.shared.ext.navigateSafety -import nl.rijksoverheid.ctr.shared.livedata.EventObserver -import nl.rijksoverheid.ctr.shared.models.AppErrorResult -import nl.rijksoverheid.ctr.shared.models.ErrorResult -import nl.rijksoverheid.ctr.shared.models.Flow -import nl.rijksoverheid.ctr.shared.utils.Accessibility.makeIndeterminateAccessible -import org.koin.android.ext.android.inject -import org.koin.androidx.viewmodel.ext.android.viewModel - -class PdfWebViewFragment : BaseFragment(R.layout.fragment_pdf_webview) { - - private val pdfWebViewModel: PdfWebViewModel by viewModel() - - private val cachedAppConfigUseCase: CachedAppConfigUseCase by inject() - - override fun onButtonClickWithRetryAction() { - // there is no action to retry in this screen - } - - override fun getFlow(): Flow { - return HolderFlow.Pdf - } - - // local js script, so we are safe - @SuppressLint("SetJavaScriptEnabled") - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - val binding = FragmentPdfWebviewBinding.bind(view) - - binding.loading.makeIndeterminateAccessible( - context = requireContext(), - isLoading = true, - message = R.string.general_loading_description - ) - - pdfWebViewModel.loadingLiveData.observe(viewLifecycleOwner, EventObserver { - binding.loading.isVisible = it - navigateSafety(PdfWebViewFragmentDirections.actionPdfExported()) - }) - - pdfWebViewModel.errorLiveData.observe(viewLifecycleOwner, EventObserver { - error(AppErrorResult(HolderStep.PdfExport, it)) - }) - - binding.pdfWebView.webViewClient = object : WebViewClient() { - override fun onPageFinished(webView: WebView?, url: String?) { - super.onPageFinished(webView, url) - webView?.let { - pdfWebViewModel.generatePdf(it::evaluateJavascript) - } - } - } - binding.pdfWebView.addJavascriptInterface(this, "android") - binding.pdfWebView.settings.allowFileAccess = true - binding.pdfWebView.settings.javaScriptEnabled = true - - binding.pdfWebView.loadUrl("file:///android_res/raw/print_portal.html") - } - - @SuppressLint("StringFormatInvalid") - private fun error(errorResult: ErrorResult) { - val helpdeskNumber = cachedAppConfigUseCase.getCachedAppConfig().contactInfo.phoneNumber - presentError(errorResult, getString( - R.string.holder_pdfExport_error_body, - helpdeskNumber, - helpdeskNumber, - errorCodeStringFactory.get( - flow = getFlow(), - errorResults = listOf(errorResult) - ) - )) - } - - @JavascriptInterface - fun onData(value: String) { - if (value.startsWith(PdfWebViewModel.pdfMimeType)) { - pdfWebViewModel.storePdf( - requireContext().openFileOutput( - pdfFileName, - Context.MODE_PRIVATE - ), value - ) - } else { - val errorResult = AppErrorResult( - HolderStep.PdfExport, - LoadFileException() - ) - error(errorResult) - } - } - - companion object { - const val pdfFileName = "Coronacheck - International.pdf" - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/pdf/PdfWebViewModel.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/pdf/PdfWebViewModel.kt deleted file mode 100644 index d462fbf4c..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/pdf/PdfWebViewModel.kt +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2023 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ - -package nl.rijksoverheid.ctr.holder.pdf - -import android.util.Base64 -import android.webkit.ValueCallback -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import java.io.File -import java.io.FileOutputStream -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import nl.rijksoverheid.ctr.appconfig.persistence.AppConfigStorageManager -import nl.rijksoverheid.ctr.shared.exceptions.AppConfigMissingException -import nl.rijksoverheid.ctr.shared.exceptions.CreatePdfException -import nl.rijksoverheid.ctr.shared.exceptions.NoDccException -import nl.rijksoverheid.ctr.shared.exceptions.StorePdfException -import nl.rijksoverheid.ctr.shared.livedata.Event - -abstract class PdfWebViewModel : ViewModel() { - val loadingLiveData = MutableLiveData>() - val errorLiveData = MutableLiveData>() - abstract fun generatePdf(evaluateJavascript: (script: String, valueCallback: ValueCallback?) -> Unit) - abstract fun storePdf(fileOutputStream: FileOutputStream, contents: String) - - companion object { - const val pdfMimeType = "data:application/pdf;base64," - } -} - -class PdfWebViewModelImpl( - private val filesDirPath: String, - private val appConfigStorageManager: AppConfigStorageManager, - private val printExportDccUseCase: PrintExportDccUseCase -) : PdfWebViewModel() { - - override fun generatePdf(evaluateJavascript: (script: String, valueCallback: ValueCallback?) -> Unit) { - val appConfig = appConfigStorageManager - .getFileAsBufferedSource(File(filesDirPath, "config.json")) - - if (appConfig == null) { - errorLiveData.postValue(Event(AppConfigMissingException())) - return - } - - viewModelScope.launch { - val qrs = try { - printExportDccUseCase.export() - } catch (exception: Exception) { - errorLiveData.postValue(Event(NoDccException())) - return@launch - } - try { - val script = "generatePdf($appConfig, $qrs);" - evaluateJavascript(script, null) - } catch (exception: Exception) { - errorLiveData.postValue(Event(CreatePdfException())) - } - } - } - - override fun storePdf(fileOutputStream: FileOutputStream, contents: String) { - viewModelScope.launch(Dispatchers.IO) { - val base64Content = contents.replace("data:application/pdf;base64,", "") - try { - val base64DecodedContent = Base64.decode(base64Content, Base64.DEFAULT) - fileOutputStream.use { - it.write(base64DecodedContent) - it.flush() - } - } catch (exception: Exception) { - errorLiveData.postValue(Event(StorePdfException())) - } - loadingLiveData.postValue(Event(false)) - } - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/pdf/PreviewPdfUseCase.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/pdf/PreviewPdfUseCase.kt deleted file mode 100644 index 6c6a30a9b..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/pdf/PreviewPdfUseCase.kt +++ /dev/null @@ -1,67 +0,0 @@ -package nl.rijksoverheid.ctr.holder.pdf - -import android.graphics.Bitmap -import android.graphics.Canvas -import android.graphics.pdf.PdfRenderer -import android.os.ParcelFileDescriptor -import android.util.Base64 -import java.io.ByteArrayOutputStream -import java.io.File -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext - -interface PreviewPdfUseCase { - suspend fun generatePreview(screenWidth: Int, filesDir: File): PDfPreviewInfo? -} - -class PreviewPdfUseCaseImpl : PreviewPdfUseCase { - override suspend fun generatePreview(screenWidth: Int, filesDir: File): PDfPreviewInfo? { - return withContext(Dispatchers.IO) { - try { - val pdfFile = File(filesDir, PdfWebViewFragment.pdfFileName) - val parcelFileDescriptor = - ParcelFileDescriptor.open(pdfFile, ParcelFileDescriptor.MODE_READ_ONLY) - val pdfRenderer = PdfRenderer(parcelFileDescriptor) - val bitmaps = mutableListOf() - for (i in 0 until pdfRenderer.pageCount) { - val currentPage = pdfRenderer.openPage(i) - val bitmap = Bitmap.createBitmap( - currentPage.width, - currentPage.height, - Bitmap.Config.ARGB_8888 - ) - currentPage.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY) - bitmaps.add(bitmap) - currentPage.close() - } - pdfRenderer.close() - - val bitmapWidth = bitmaps.first().width - val initialZoom = ((screenWidth.toFloat() / bitmapWidth.toFloat()) * 100).toInt() - - PDfPreviewInfo( - content = pdfBitmap(bitmaps), - initialZoom = initialZoom - ) - } catch (exception: Exception) { - null - } - } - } - - private fun pdfBitmap(bitmaps: List): String { - val width = bitmaps.first().width - val pageHeight = bitmaps.first().height - val height = bitmaps.first().height * bitmaps.size - val comboBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) - val comboImage = Canvas(comboBitmap) - bitmaps.forEachIndexed { index, bitmap -> - comboImage.drawBitmap(bitmap, 0f, (index * pageHeight).toFloat(), null) - } - - val byteArrayOutputStream = ByteArrayOutputStream() - comboBitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream) - val byteArray = byteArrayOutputStream.toByteArray() - return "data:image/png;base64,${Base64.encodeToString(byteArray, Base64.DEFAULT)}" - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/pdf/PrintExportDccUseCase.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/pdf/PrintExportDccUseCase.kt deleted file mode 100644 index bf99f94eb..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/pdf/PrintExportDccUseCase.kt +++ /dev/null @@ -1,37 +0,0 @@ -package nl.rijksoverheid.ctr.holder.pdf - -import com.squareup.moshi.Moshi -import nl.rijksoverheid.ctr.persistence.database.HolderDatabase -import nl.rijksoverheid.ctr.persistence.database.entities.GreenCardType -import nl.rijksoverheid.ctr.shared.MobileCoreWrapper - -interface PrintExportDccUseCase { - suspend fun export(): String -} - -class PrintExportDccUseCaseImpl( - private val holderDatabase: HolderDatabase, - private val mobileCoreWrapper: MobileCoreWrapper, - private val moshi: Moshi -) : PrintExportDccUseCase { - override suspend fun export(): String { - val credentials = holderDatabase.greenCardDao().getAll() - .filter { it.greenCardEntity.type == GreenCardType.Eu && it.credentialEntities.isNotEmpty() } - .sortedBy { - it.origins.firstOrNull()?.eventTime - } - .map { it.credentialEntities.last() } - - val printAttributes = PrintAttributes( - european = credentials.map { - EUPrintAttributes( - dcc = mobileCoreWrapper.readEuropeanCredential(it.data).getJSONObject("dcc"), - expirationTime = it.expirationTime, - qr = String(it.data) - ) - } - ) - - return moshi.adapter(PrintAttributes::class.java).toJson(printAttributes) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/QrCodeAnimationWidget.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/QrCodeAnimationWidget.kt deleted file mode 100644 index 6ed4c71f3..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/QrCodeAnimationWidget.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.qrcodes - -import android.content.Context -import android.util.AttributeSet -import android.widget.FrameLayout -import android.widget.ImageView -import androidx.annotation.RawRes -import com.airbnb.lottie.LottieAnimationView -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.shared.models.Environment - -class QrCodeAnimationWidget(context: Context, attrs: AttributeSet?) : - FrameLayout(context, attrs) { - - private val animationView: LottieAnimationView - - private val background: ImageView - - init { - val view = inflate(context, R.layout.widget_qr_code_animation, this) - animationView = view.findViewById(R.id.animation_view) - background = view.findViewById(R.id.image) - animationView.setIgnoreDisabledSystemAnimations(Environment.get(context) is Environment.Prod) - setOnClickListener { - animationView.run { - scaleX = if (scaleX == 1F) -1F else 1F - playAnimation() - } - } - } - - fun setWidget(@RawRes animation: Int) { - animationView.setAnimation(animation) - animationView.playAnimation() - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/QrCodePagerAdapter.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/QrCodePagerAdapter.kt deleted file mode 100644 index 0576b8eec..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/QrCodePagerAdapter.kt +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.qrcodes - -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.core.view.isVisible -import androidx.recyclerview.widget.RecyclerView -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.databinding.ViewQrCodeBinding -import nl.rijksoverheid.ctr.holder.qrcodes.models.QrCodeData - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -class QrCodePagerAdapter(private val onOverlayExplanationClick: (QrCodeViewHolder.QrCodeVisibility) -> Unit) : - RecyclerView.Adapter() { - - val qrCodeDataList: MutableList = mutableListOf() - - private var currentPosition = 0 - - private val overlayVisibilityStates = mutableListOf() - - fun addData(data: List) { - val hasItems = qrCodeDataList.isNotEmpty() - val hideOverlayInCurrentPosition = - overlayVisibilityStates.getOrNull(currentPosition) == QrCodeViewHolder.QrCodeVisibility.VISIBLE - qrCodeDataList.clear() - overlayVisibilityStates.clear() - data.forEachIndexed { index, it -> - // if user chose to display the QR, don't hide it until scrolled away from it - if (index == currentPosition && hideOverlayInCurrentPosition) { - overlayVisibilityStates.add(QrCodeViewHolder.QrCodeVisibility.VISIBLE) - } else { - overlayVisibilityStates.add(isQrCodeHidden(it)) - } - } - qrCodeDataList.addAll(data) - if (hasItems) { - notifyItemRangeChanged(0, data.size) - } else { - notifyItemRangeInserted(0, data.size) - } - } - - private fun isQrCodeHidden(data: QrCodeData): QrCodeViewHolder.QrCodeVisibility { - val vaccinationData = data as? QrCodeData.European.Vaccination - return when { - (data as? QrCodeData.European)?.isExpired == true -> QrCodeViewHolder.QrCodeVisibility.EXPIRED - vaccinationData?.isDoseNumberSmallerThanTotalDose == true -> QrCodeViewHolder.QrCodeVisibility.HIDDEN - else -> QrCodeViewHolder.QrCodeVisibility.VISIBLE - } - } - - fun onPositionChanged(position: Int) { - currentPosition = position - overlayVisibilityStates.forEachIndexed { index, _ -> - overlayVisibilityStates[index] = isQrCodeHidden(qrCodeDataList[index]) - } - notifyItemChanged(position) - } - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): QrCodeViewHolder { - val view = LayoutInflater.from(parent.context).inflate(R.layout.view_qr_code, parent, false) - return QrCodeViewHolder(view) - } - - override fun onBindViewHolder(holder: QrCodeViewHolder, position: Int) { - holder.bind( - qrCodeDataList[position], - position == currentPosition, - overlayVisibilityStates[position], - onOverlayExplanationClick - ) { - overlayVisibilityStates[currentPosition] = QrCodeViewHolder.QrCodeVisibility.VISIBLE - notifyItemChanged(currentPosition) - } - } - - override fun getItemCount(): Int { - return qrCodeDataList.size - } -} - -class QrCodeViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - - private val binding = ViewQrCodeBinding.bind(itemView) - - fun bind( - qrCodeData: QrCodeData, - isCurrentlyDisplayed: Boolean, - qrCodeVisibility: QrCodeVisibility, - onOverlayExplanationClick: (QrCodeVisibility) -> Unit, - onOverlayButtonClick: () -> Unit - ) { - val showOverlay = qrCodeVisibility != QrCodeVisibility.VISIBLE - - binding.image.setImageBitmap(qrCodeData.bitmap) - binding.overlayShowQrButton.setOnClickListener { - onOverlayButtonClick.invoke() - } - - if (qrCodeData is QrCodeData.European.NonVaccination && !qrCodeData.explanationNeeded) { - binding.overlayButton.isVisible = false - } else { - binding.overlayButton.setOnClickListener { - onOverlayExplanationClick.invoke(qrCodeVisibility) - } - } - - // using View.INVISIBLE instead View.GONE cause the latter breaks - // the click listener for physical keyboards accessibility - setOverlay(showOverlay, qrCodeVisibility) - - // not visible pages can also gain focus, so we have to take care of that for hardware keyboard users - binding.image.isFocusable = isCurrentlyDisplayed && !showOverlay - binding.image.importantForAccessibility = if (isCurrentlyDisplayed && !showOverlay) { - View.IMPORTANT_FOR_ACCESSIBILITY_YES - } else { - View.IMPORTANT_FOR_ACCESSIBILITY_NO - } - binding.overlay.isFocusable = isCurrentlyDisplayed && showOverlay - } - - private fun setOverlay( - showOverlay: Boolean, - qrCodeVisibility: QrCodeVisibility - ) { - binding.overlay.visibility = if (showOverlay) { - View.VISIBLE - } else { - View.INVISIBLE - } - binding.overlayText.text = itemView.context.getString( - if (qrCodeVisibility == QrCodeVisibility.HIDDEN) { - R.string.qr_code_hidden_title } else { - R.string.holder_qr_code_expired_overlay_title - } - ) - binding.overlayText.setCompoundDrawablesWithIntrinsicBounds( - 0, - when (qrCodeVisibility) { - QrCodeVisibility.HIDDEN -> R.drawable.ic_visibility_off - QrCodeVisibility.EXPIRED -> R.drawable.ic_qr_hidden - else -> 0 - }, - 0, - 0 - ) - } - - enum class QrCodeVisibility { - HIDDEN, EXPIRED, VISIBLE - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/QrCodesFragment.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/QrCodesFragment.kt deleted file mode 100644 index 6b9e791a6..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/QrCodesFragment.kt +++ /dev/null @@ -1,446 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.qrcodes - -import android.annotation.SuppressLint -import android.content.ActivityNotFoundException -import android.content.pm.ActivityInfo -import android.os.Bundle -import android.os.Handler -import android.os.Looper -import android.view.View -import android.view.WindowManager -import androidx.core.view.accessibility.AccessibilityNodeInfoCompat -import androidx.fragment.app.Fragment -import androidx.navigation.fragment.navArgs -import androidx.viewpager2.widget.ViewPager2 -import java.util.concurrent.TimeUnit -import nl.rijksoverheid.ctr.appconfig.models.ExternalReturnAppData -import nl.rijksoverheid.ctr.appconfig.usecases.ClockDeviationUseCase -import nl.rijksoverheid.ctr.design.fragments.info.ButtonData -import nl.rijksoverheid.ctr.design.fragments.info.DescriptionData -import nl.rijksoverheid.ctr.design.fragments.info.InfoFragmentData -import nl.rijksoverheid.ctr.design.utils.DialogUtil -import nl.rijksoverheid.ctr.design.utils.InfoFragmentUtil -import nl.rijksoverheid.ctr.holder.BuildConfig -import nl.rijksoverheid.ctr.holder.HolderMainFragment -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.databinding.FragmentQrCodesBinding -import nl.rijksoverheid.ctr.holder.qrcodes.models.QrCodeAnimation -import nl.rijksoverheid.ctr.holder.qrcodes.models.QrCodeData -import nl.rijksoverheid.ctr.holder.qrcodes.models.QrCodesResult -import nl.rijksoverheid.ctr.holder.qrcodes.utils.QrCodesFragmentUtil -import nl.rijksoverheid.ctr.holder.qrcodes.utils.QrInfoScreenUtil -import nl.rijksoverheid.ctr.holder.usecases.HolderFeatureFlagUseCase -import nl.rijksoverheid.ctr.persistence.HolderCachedAppConfigUseCase -import nl.rijksoverheid.ctr.persistence.database.entities.OriginType -import nl.rijksoverheid.ctr.shared.ext.findNavControllerSafety -import nl.rijksoverheid.ctr.shared.utils.Accessibility.addAccessibilityAction -import org.koin.android.ext.android.inject -import org.koin.androidx.viewmodel.ext.android.viewModel - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -class QrCodesFragment : Fragment(R.layout.fragment_qr_codes) { - - private companion object { - const val ORIENTATION_CHANGED = "orientationChanged" - } - - private var _binding: FragmentQrCodesBinding? = null - private val binding get() = _binding!! - private fun safeBindingBlock(block: (binding: FragmentQrCodesBinding) -> Unit) { - _binding?.run(block) - } - - private val args: QrCodesFragmentArgs by navArgs() - private val featureFlagUseCase: HolderFeatureFlagUseCase by inject() - private val infoScreenUtil: QrInfoScreenUtil by inject() - private val dialogUtil: DialogUtil by inject() - private val infoFragmentUtil: InfoFragmentUtil by inject() - private val cachedAppConfigUseCase: HolderCachedAppConfigUseCase by inject() - private val qrCodesFragmentUtil: QrCodesFragmentUtil by inject() - private lateinit var qrCodePagerAdapter: QrCodePagerAdapter - - private val qrCodeHandler = Handler(Looper.getMainLooper()) - private val qrCodeRunnable = Runnable { - generateQrCodes() - } - - private val qrCodeViewModel: QrCodesViewModel by viewModel() - private val clockDeviationUseCase: ClockDeviationUseCase by inject() - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - if (BuildConfig.FLAVOR.lowercase().contains("prod")) { - requireActivity().window.setFlags( - WindowManager.LayoutParams.FLAG_SECURE, - WindowManager.LayoutParams.FLAG_SECURE - ) - } - val params = requireActivity().window.attributes - params?.screenBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_FULL - requireActivity().window.attributes = params - - // If there is a savedInstanceState and it's not because of orientation change, we treat this as process death occurred. - // In that case QrCodesFragment is launched before the init of the app, which we do not want. - if (savedInstanceState != null && - !savedInstanceState.getBoolean(ORIENTATION_CHANGED, false) - ) { - findNavControllerSafety()?.popBackStack() - } - } - - @SuppressLint("SourceLockedOrientationActivity") - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - requireActivity().requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT - - _binding = FragmentQrCodesBinding.bind(view) - - setupViewPager() - dispatchTouchEventDoseInfo() - - qrCodeViewModel.qrCodeDataListLiveData.observe(viewLifecycleOwner, ::bindQrCodeDataList) - qrCodeViewModel.returnAppLivedata.observe(viewLifecycleOwner, ::returnToApp) - qrCodeViewModel.animationLiveData.observe(viewLifecycleOwner, ::applyAnimation) - clockDeviationUseCase.serverTimeSyncedLiveData.observe(viewLifecycleOwner) { onServerTimeSynced() } - - args.returnUri?.let { qrCodeViewModel.onReturnUriGiven(it, args.data.type) } - qrCodeViewModel.getAnimation(args.data.type) - } - - /** - * Whenever we sync the server time, generate new qr codes as the qr code holds the (possibly adjusted) time - */ - private fun onServerTimeSynced() { - generateQrCodes() - } - - /** - * Dispatch touch events on the overlapping dose info view to have the animation view mirror itself. - */ - @SuppressLint("ClickableViewAccessibility") - private fun dispatchTouchEventDoseInfo() { - binding.doseInfo.setOnTouchListener { _, event -> - binding.animation.dispatchTouchEvent(event) - true - } - } - - private fun setupViewPager() { - qrCodePagerAdapter = QrCodePagerAdapter(::onOverlayExplanationClick) - binding.viewPager.adapter = qrCodePagerAdapter - } - - private fun onOverlayExplanationClick(qrCodeVisibility: QrCodeViewHolder.QrCodeVisibility) { - infoFragmentUtil.presentAsBottomSheet( - childFragmentManager, InfoFragmentData.TitleDescriptionWithButton( - title = getString( - if (qrCodeVisibility == QrCodeViewHolder.QrCodeVisibility.EXPIRED) { - R.string.holder_qr_code_expired_explanation_title - } else { - R.string.holder_qr_code_hidden_explanation_title - } - ), - descriptionData = DescriptionData( - htmlTextString = getString( - if (qrCodeVisibility == QrCodeViewHolder.QrCodeVisibility.EXPIRED) { - if (featureFlagUseCase.isInArchiveMode()) { - if (args.data.originType is OriginType.Vaccination) { - R.string.holder_qr_code_expired_explanation_description_archive_vaccination - } else { - R.string.holder_qr_code_expired_explanation_description_archive_recovery - } - } else { - R.string.holder_qr_code_expired_explanation_description - } - } else { - if (featureFlagUseCase.isInArchiveMode()) { - R.string.holder_qr_code_hidden_explanation_description_archive_vaccination - } else { - R.string.holder_qr_code_hidden_explanation_description - } - } - ), - htmlLinksEnabled = true - ), - primaryButtonData = if (featureFlagUseCase.isInArchiveMode()) { - null - } else { - ButtonData.LinkButton( - text = getString( - if (qrCodeVisibility == QrCodeViewHolder.QrCodeVisibility.EXPIRED) { - R.string.holder_qr_code_expired_explanation_action - } else { - R.string.holder_qr_code_hidden_explanation_action - } - ), - link = getString( - if (qrCodeVisibility == QrCodeViewHolder.QrCodeVisibility.EXPIRED) { - R.string.holder_qr_code_expired_explanation_url - } else { - R.string.holder_qr_code_hidden_explanation_url - } - ) - ) - } - ) - ) - } - - private fun applyAnimation(qrCodeAnimation: QrCodeAnimation) { - binding.animation.setWidget(qrCodeAnimation.animationResource) - binding.animation.contentDescription = getString(qrCodeAnimation.contentDescription) - binding.animation.addAccessibilityAction( - AccessibilityNodeInfoCompat.ACTION_CLICK, - getString(R.string.holder_showqr_animation_voiceover_hint) - ) - } - - private fun returnToApp(externalReturnAppData: ExternalReturnAppData) { - binding.button.run { - visibility = View.VISIBLE - text = getString(R.string.qr_code_return_app_button, externalReturnAppData.appName) - setOnClickListener { startIntent(externalReturnAppData) } - } - } - - private fun startIntent(externalReturnAppData: ExternalReturnAppData) { - try { - startActivity(externalReturnAppData.intent) - } catch (exception: ActivityNotFoundException) { - dialogUtil.presentDialog( - context = requireContext(), - title = R.string.dialog_error_title, - message = getString(R.string.dialog_error_message), - positiveButtonText = R.string.dialog_close, - positiveButtonCallback = {} - ) - } - } - - private fun bindQrCodeDataList(qrCodesResult: QrCodesResult) { - presentQrLoading(false) - - when (qrCodesResult) { - is QrCodesResult.SingleQrCode -> { - qrCodePagerAdapter.addData(listOf(qrCodesResult.qrCodeData)) - binding.vaccinationQrsContainer.visibility = View.GONE - } - is QrCodesResult.MultipleQrCodes -> { - qrCodePagerAdapter.addData(qrCodesResult.europeanVaccinationQrCodeDataList) - if (binding.qrVaccinationIndicators.visibility == View.GONE) { - // Setup extra viewpager UI only once - setupEuropeanVaccinationQr( - qrCodesResult.europeanVaccinationQrCodeDataList, - qrCodesResult.mostRelevantVaccinationIndex - ) - } - } - } - - // Nullable so tests don't trip over parentFragment - (parentFragment?.parentFragment as HolderMainFragment?)?.getToolbar().let { toolbar -> - if (toolbar?.menu?.size() == 0) { - toolbar.apply { - inflateMenu(R.menu.my_qr_toolbar) - - setOnMenuItemClickListener { - val qrCodeData = - qrCodePagerAdapter.qrCodeDataList.get(binding.viewPager.currentItem) - if (it.itemId == R.id.action_show_qr_explanation) { - val infoScreen = when (qrCodeData) { - is QrCodeData.European -> { - when (args.data.originType) { - is OriginType.Test -> { - infoScreenUtil.getForEuropeanTestQr( - qrCodeData.readEuropeanCredential - ) - } - is OriginType.Vaccination -> { - infoScreenUtil.getForEuropeanVaccinationQr( - qrCodeData.readEuropeanCredential - ) - } - is OriginType.Recovery -> { - infoScreenUtil.getForEuropeanRecoveryQr( - qrCodeData.readEuropeanCredential - ) - } - } - } - } - - infoFragmentUtil.presentAsBottomSheet( - childFragmentManager, InfoFragmentData.TitleDescriptionWithFooter( - title = infoScreen.title, - descriptionData = DescriptionData( - htmlTextString = infoScreen.description, - htmlLinksEnabled = true - ), - footerText = infoScreen.footer - ) - ) - } - true - } - } - } - } - } - - /** - * Show extra UI when we are dealing with european vaccination qrs - */ - private fun setupEuropeanVaccinationQr( - europeanVaccinations: List, - mostRelevantVaccinationIndex: Int - ) { - // Make extra UI visible to show more information about the QR - binding.vaccinationQrsContainer.visibility = View.VISIBLE - binding.qrVaccinationDose.visibility = View.VISIBLE - val doses = getString( - R.string.qr_code_dosis, - "${europeanVaccinations.first().dose}/${europeanVaccinations.first().ofTotalDoses}" - ) - binding.qrVaccinationDose.text = doses - binding.qrVaccinationDose.contentDescription = doses - - // If there are more then one vaccinations we update UI based on the selected page - if (europeanVaccinations.size > 1) { - // Initialize our viewpager indicators - binding.qrVaccinationIndicators.visibility = View.VISIBLE - binding.qrVaccinationIndicators.initIndicator(europeanVaccinations.size) - - binding.viewPager.registerOnPageChangeCallback(object : - ViewPager2.OnPageChangeCallback() { - override fun onPageSelected(position: Int) { - super.onPageSelected(position) - - // Select current indicator - binding.qrVaccinationIndicators.updateSelected(position) - - binding.root.post { - onPageSelectedPostAction(position, europeanVaccinations) - } - - qrCodePagerAdapter.onPositionChanged(position) - } - }) - - // Default select the last item - binding.viewPager.setCurrentItem(mostRelevantVaccinationIndex, false) - - // Make buttons click to scroll through viewpager - binding.previousQrButton.setOnClickListener { - binding.viewPager.setCurrentItem(binding.viewPager.currentItem - 1, true) - } - - binding.nextQrButton.setOnClickListener { - binding.viewPager.setCurrentItem(binding.viewPager.currentItem + 1, true) - } - } - } - - private fun onPageSelectedPostAction( - position: Int, - europeanVaccinations: List - ) { - safeBindingBlock { binding -> - binding.nextQrButton.visibility = - if (position == europeanVaccinations.size - 1) View.INVISIBLE else View.VISIBLE - binding.previousQrButton.visibility = - if (position == 0) View.INVISIBLE else View.VISIBLE - - val vaccination = europeanVaccinations[position] - val doses = getString( - R.string.qr_code_dosis, - "${vaccination.dose}/${vaccination.ofTotalDoses}" - ) - binding.qrVaccinationDose.text = doses - binding.qrVaccinationDose.contentDescription = doses - } - } - - private fun presentQrLoading(loading: Boolean) { - (parentFragment?.parentFragment as? HolderMainFragment)?.presentLoading(loading) - binding.root.visibility = if (loading) View.GONE else View.VISIBLE - } - - private fun generateQrCodes() { - checkShouldAutomaticallyClose() - qrCodeViewModel.generateQrCodes( - qrCodeFragmentData = args.data, - size = resources.displayMetrics.widthPixels - ) - val refreshMillis = - if (BuildConfig.FLAVOR == "tst") TimeUnit.SECONDS.toMillis(10) else TimeUnit.SECONDS.toMillis( - cachedAppConfigUseCase.getCachedAppConfig().domesticQRRefreshSeconds.toLong() - ) - - // Make sure there is only 1 callback as multiple qr generations can be triggered by onResume and server time LiveData - qrCodeHandler.removeCallbacks(qrCodeRunnable) - qrCodeHandler.postDelayed(qrCodeRunnable, refreshMillis) - } - - /** - * Checks if this fragment should automatically close - */ - private fun checkShouldAutomaticallyClose() { - val shouldClose = qrCodesFragmentUtil.shouldClose( - args.data.credentialsWithExpirationTime.last().second.toEpochSecond(), - args.data.type - ) - if (shouldClose) { - findNavControllerSafety()?.popBackStack() - } - } - - override fun onResume() { - super.onResume() - presentQrLoading(true) - generateQrCodes() - } - - override fun onPause() { - super.onPause() - (parentFragment?.parentFragment as HolderMainFragment).let { - it.getToolbar().menu.clear() - // Reset menu item listener to default - it.resetMenuItemListener() - } - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - qrCodeHandler.removeCallbacks(qrCodeRunnable) - - // Set brightness back to previous - val params = requireActivity().window.attributes - params?.screenBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE - requireActivity().window.attributes = params - - (parentFragment?.parentFragment as HolderMainFragment).presentLoading(false) - - requireActivity().requestedOrientation = - ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED - } - - override fun onSaveInstanceState(outState: Bundle) { - super.onSaveInstanceState(outState) - outState.putBoolean(ORIENTATION_CHANGED, requireActivity().isChangingConfigurations) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/QrCodesViewModel.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/QrCodesViewModel.kt deleted file mode 100644 index c47a7c894..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/QrCodesViewModel.kt +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.qrcodes - -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import kotlinx.coroutines.launch -import nl.rijksoverheid.ctr.appconfig.models.ExternalReturnAppData -import nl.rijksoverheid.ctr.appconfig.usecases.ReturnToExternalAppUseCase -import nl.rijksoverheid.ctr.holder.qrcodes.models.QrCodeAnimation -import nl.rijksoverheid.ctr.holder.qrcodes.models.QrCodeFragmentData -import nl.rijksoverheid.ctr.holder.qrcodes.models.QrCodesResult -import nl.rijksoverheid.ctr.holder.qrcodes.usecases.QrCodeAnimationUseCase -import nl.rijksoverheid.ctr.holder.qrcodes.usecases.QrCodesResultUseCase -import nl.rijksoverheid.ctr.persistence.database.entities.GreenCardType - -abstract class QrCodesViewModel : ViewModel() { - val qrCodeDataListLiveData = MutableLiveData() - val returnAppLivedata = MutableLiveData() - val animationLiveData = MutableLiveData() - abstract fun generateQrCodes( - qrCodeFragmentData: QrCodeFragmentData, - size: Int - ) - - abstract fun onReturnUriGiven(uri: String, type: GreenCardType) - abstract fun getAnimation(greenCardType: GreenCardType) -} - -class QrCodesViewModelImpl( - private val qrCodesResultUseCase: QrCodesResultUseCase, - private val returnToExternalAppUseCase: ReturnToExternalAppUseCase, - private val qrCodeAnimationUseCase: QrCodeAnimationUseCase -) : QrCodesViewModel() { - - override fun generateQrCodes( - qrCodeFragmentData: QrCodeFragmentData, - size: Int - ) { - viewModelScope.launch { - val result = qrCodesResultUseCase.getQrCodesResult( - qrCodeFragmentData = qrCodeFragmentData, - qrCodeWidth = size, - qrCodeHeight = size - ) - qrCodeDataListLiveData.postValue( - result - ) - } - } - - override fun onReturnUriGiven(uri: String, type: GreenCardType) { - } - - override fun getAnimation(greenCardType: GreenCardType) { - animationLiveData.postValue( - qrCodeAnimationUseCase.get(greenCardType) - ) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/models/QrCodeAnimation.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/models/QrCodeAnimation.kt deleted file mode 100644 index 6835f4bbf..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/models/QrCodeAnimation.kt +++ /dev/null @@ -1,18 +0,0 @@ -package nl.rijksoverheid.ctr.holder.qrcodes.models - -import androidx.annotation.RawRes -import androidx.annotation.StringRes -import nl.rijksoverheid.ctr.holder.R - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ -sealed class QrCodeAnimation(@RawRes val animationResource: Int, @StringRes val contentDescription: Int) { - object DomesticWinter : QrCodeAnimation(R.raw.winter_domestic, R.string.holder_showqr_animation_winterctb_voiceover_label) - object EuWinter : QrCodeAnimation(R.raw.winter_international, R.string.holder_showqr_animation_winterdcc_voiceover_label) - object DomesticSummer : QrCodeAnimation(R.raw.summer_domestic, R.string.holder_showqr_animation_summerctb_voiceover_label) - object EuSummer : QrCodeAnimation(R.raw.summer_international, R.string.holder_showqr_animation_summerdcc_voiceover_label) -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/models/QrCodeData.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/models/QrCodeData.kt deleted file mode 100644 index 20b297d96..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/models/QrCodeData.kt +++ /dev/null @@ -1,32 +0,0 @@ -package nl.rijksoverheid.ctr.holder.qrcodes.models - -import android.graphics.Bitmap -import org.json.JSONObject - -sealed class QrCodeData( - open val bitmap: Bitmap -) { - - sealed class European( - override val bitmap: Bitmap, - open val isExpired: Boolean, - open val readEuropeanCredential: JSONObject - ) : QrCodeData(bitmap) { - - data class Vaccination( - val dose: String, - val ofTotalDoses: String, - val isDoseNumberSmallerThanTotalDose: Boolean, - override val isExpired: Boolean, - override val bitmap: Bitmap, - override val readEuropeanCredential: JSONObject - ) : European(bitmap, isExpired, readEuropeanCredential) - - data class NonVaccination( - override val isExpired: Boolean, - override val bitmap: Bitmap, - override val readEuropeanCredential: JSONObject, - val explanationNeeded: Boolean - ) : European(bitmap, isExpired, readEuropeanCredential) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/models/QrCodeFragmentData.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/models/QrCodeFragmentData.kt deleted file mode 100644 index 9a9996cdf..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/models/QrCodeFragmentData.kt +++ /dev/null @@ -1,25 +0,0 @@ -package nl.rijksoverheid.ctr.holder.qrcodes.models - -import android.os.Parcelable -import java.time.OffsetDateTime -import kotlinx.parcelize.Parcelize -import nl.rijksoverheid.ctr.persistence.database.entities.GreenCardType -import nl.rijksoverheid.ctr.persistence.database.entities.OriginType - -@Parcelize -data class QrCodeFragmentData( - val type: GreenCardType, - val originType: OriginType, - val credentialsWithExpirationTime: List>, - val shouldDisclose: ShouldDisclose -) : Parcelable { - - sealed class ShouldDisclose : Parcelable { - - @Parcelize - object DoNotDisclose : ShouldDisclose(), Parcelable - - @Parcelize - data class Disclose(val greenCardId: Int) : ShouldDisclose(), Parcelable - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/models/QrCodesResult.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/models/QrCodesResult.kt deleted file mode 100644 index 28cfa6547..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/models/QrCodesResult.kt +++ /dev/null @@ -1,11 +0,0 @@ -package nl.rijksoverheid.ctr.holder.qrcodes.models - -sealed class QrCodesResult { - data class SingleQrCode(val qrCodeData: QrCodeData) : QrCodesResult() - - // Only european vaccinations support multiple qrs - data class MultipleQrCodes( - val europeanVaccinationQrCodeDataList: List, - val mostRelevantVaccinationIndex: Int - ) : QrCodesResult() -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/models/ReadEuropeanCredentialUtil.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/models/ReadEuropeanCredentialUtil.kt deleted file mode 100644 index a3fa6a75d..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/models/ReadEuropeanCredentialUtil.kt +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.qrcodes.models - -import android.app.Application -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.shared.ext.getStringOrNull -import org.json.JSONObject - -interface ReadEuropeanCredentialUtil { - fun getDose(readEuropeanCredential: JSONObject): String? - fun getOfTotalDoses(readEuropeanCredential: JSONObject): String? - fun getDoseRangeStringForVaccination(readEuropeanCredential: JSONObject): String - fun doseExceedsTotalDoses(readEuropeanCredential: JSONObject): Boolean -} - -class ReadEuropeanCredentialUtilImpl(private val application: Application) : - ReadEuropeanCredentialUtil { - - override fun getDose(readEuropeanCredential: JSONObject): String? { - val vaccination = getVaccination(readEuropeanCredential) - return vaccination?.getStringOrNull("dn") - } - - override fun getOfTotalDoses(readEuropeanCredential: JSONObject): String? { - val vaccination = getVaccination(readEuropeanCredential) - return vaccination?.getStringOrNull("sd") - } - - override fun getDoseRangeStringForVaccination(readEuropeanCredential: JSONObject): String { - val vaccination = getVaccination(readEuropeanCredential) - val dose = vaccination?.getStringOrNull("dn") ?: "" - val totalDoses = vaccination?.getStringOrNull("sd") ?: "" - - val doses = - if (dose.isNotEmpty() && totalDoses.isNotEmpty()) { - application.getString( - R.string.your_vaccination_explanation_doses_answer, dose, totalDoses - ) - } else "" - - return doses - } - - override fun doseExceedsTotalDoses(readEuropeanCredential: JSONObject): Boolean { - val dose = getDose(readEuropeanCredential)?.toInt() ?: 0 - val ofTotalDoses = getOfTotalDoses(readEuropeanCredential)?.toInt() ?: 0 - return dose > ofTotalDoses - } - - private fun getVaccination(readEuropeanCredential: JSONObject): JSONObject? { - val dcc = readEuropeanCredential.optJSONObject("dcc") - val vaccination = dcc?.getJSONArray("v")?.optJSONObject(0) - return vaccination - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/usecases/QrCodeAnimationUseCase.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/usecases/QrCodeAnimationUseCase.kt deleted file mode 100644 index 42363319e..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/usecases/QrCodeAnimationUseCase.kt +++ /dev/null @@ -1,47 +0,0 @@ -package nl.rijksoverheid.ctr.holder.qrcodes.usecases - -import java.time.Clock -import java.util.Calendar -import nl.rijksoverheid.ctr.holder.qrcodes.models.QrCodeAnimation -import nl.rijksoverheid.ctr.persistence.database.entities.GreenCardType - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -interface QrCodeAnimationUseCase { - fun get(greenCardType: GreenCardType): QrCodeAnimation -} - -class QrCodeAnimationUseCaseImpl( - private val clock: Clock -) : QrCodeAnimationUseCase { - - override fun get(greenCardType: GreenCardType): QrCodeAnimation { - val now = Calendar.getInstance().apply { - timeInMillis = clock.millis() - } - val dayOfMonth = now.get(Calendar.DAY_OF_MONTH) - val month = now.get(Calendar.MONTH) - val isSummer = - (dayOfMonth >= startDay && month == Calendar.MARCH) || - month in (Calendar.APRIL..Calendar.NOVEMBER) || - (dayOfMonth <= endDay && month == Calendar.DECEMBER) - - return when (greenCardType) { - GreenCardType.Eu -> if (isSummer) { - QrCodeAnimation.EuSummer - } else { - QrCodeAnimation.EuWinter - } - } - } - - companion object { - private const val startDay = 21 - private const val endDay = 20 - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/usecases/QrCodeUseCase.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/usecases/QrCodeUseCase.kt deleted file mode 100644 index ded02b148..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/usecases/QrCodeUseCase.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.qrcodes.usecases - -import android.graphics.Bitmap -import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import nl.rijksoverheid.ctr.appconfig.usecases.ClockDeviationUseCase -import nl.rijksoverheid.ctr.holder.qrcodes.models.QrCodeFragmentData -import nl.rijksoverheid.ctr.holder.qrcodes.utils.QrCodeUtil -import nl.rijksoverheid.ctr.persistence.database.HolderDatabase -import nl.rijksoverheid.ctr.shared.MobileCoreWrapper - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -interface QrCodeUseCase { - suspend fun qrCode(credential: ByteArray, shouldDisclose: QrCodeFragmentData.ShouldDisclose, qrCodeWidth: Int, qrCodeHeight: Int, errorCorrectionLevel: ErrorCorrectionLevel): Bitmap -} - -class QrCodeUseCaseImpl( - private val holderDatabase: HolderDatabase, - private val qrCodeUtil: QrCodeUtil, - private val mobileCoreWrapper: MobileCoreWrapper, - private val clockDeviationUseCase: ClockDeviationUseCase -) : QrCodeUseCase { - - override suspend fun qrCode( - credential: ByteArray, - shouldDisclose: QrCodeFragmentData.ShouldDisclose, - qrCodeWidth: Int, - qrCodeHeight: Int, - errorCorrectionLevel: ErrorCorrectionLevel - ): Bitmap = - withContext(Dispatchers.IO) { - val qrCodeContent = String(credential) - - qrCodeUtil.createQrCode( - qrCodeContent = qrCodeContent, - width = qrCodeWidth, - height = qrCodeHeight, - errorCorrectionLevel = errorCorrectionLevel - ) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/usecases/QrCodesResultUseCase.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/usecases/QrCodesResultUseCase.kt deleted file mode 100644 index fcde1a6ad..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/usecases/QrCodesResultUseCase.kt +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.qrcodes.usecases - -import java.time.OffsetDateTime -import nl.rijksoverheid.ctr.holder.dashboard.util.CredentialUtil -import nl.rijksoverheid.ctr.holder.dashboard.util.GreenCardUtil -import nl.rijksoverheid.ctr.holder.qrcodes.models.QrCodeData -import nl.rijksoverheid.ctr.holder.qrcodes.models.QrCodeFragmentData -import nl.rijksoverheid.ctr.holder.qrcodes.models.QrCodesResult -import nl.rijksoverheid.ctr.holder.qrcodes.models.ReadEuropeanCredentialUtil -import nl.rijksoverheid.ctr.holder.qrcodes.utils.MultipleQrCodesUtil -import nl.rijksoverheid.ctr.persistence.database.entities.GreenCardType -import nl.rijksoverheid.ctr.persistence.database.entities.OriginType -import nl.rijksoverheid.ctr.shared.MobileCoreWrapper - -/** - * Get all data needed to display QR codes based on data is send from the dashboard - */ -interface QrCodesResultUseCase { - suspend fun getQrCodesResult( - qrCodeFragmentData: QrCodeFragmentData, - qrCodeWidth: Int, - qrCodeHeight: Int - ): QrCodesResult -} - -class QrCodesResultUseCaseImpl( - private val qrCodeUseCase: QrCodeUseCase, - private val greenCardUtil: GreenCardUtil, - private val mobileCoreWrapper: MobileCoreWrapper, - private val readEuropeanCredentialUtil: ReadEuropeanCredentialUtil, - private val credentialUtil: CredentialUtil, - private val multipleQrCodesUtil: MultipleQrCodesUtil -) : QrCodesResultUseCase { - - override suspend fun getQrCodesResult( - qrCodeFragmentData: QrCodeFragmentData, - qrCodeWidth: Int, - qrCodeHeight: Int - ): QrCodesResult { - val greenCardType = qrCodeFragmentData.type - val credentialsWithExpirationTime = qrCodeFragmentData.credentialsWithExpirationTime - val credentials = credentialsWithExpirationTime.map { it.first } - val shouldDisclose = qrCodeFragmentData.shouldDisclose - val originType = qrCodeFragmentData.originType - - return when (greenCardType) { - is GreenCardType.Eu -> { - if (originType is OriginType.Vaccination) { - getQrCodesResultForEuropeanVaccination( - greenCardType = greenCardType, - credentialsWithExpirationTime = credentialsWithExpirationTime, - shouldDisclose = shouldDisclose, - qrCodeWidth = qrCodeWidth, - qrCodeHeight = qrCodeHeight - ) - } else { - getQrCodesResultForNonVaccination( - greenCardType = greenCardType, - originType = originType, - credentialsWithExpirationTime = credentialsWithExpirationTime, - credentials = credentials, - shouldDisclose = shouldDisclose, - qrCodeWidth = qrCodeWidth, - qrCodeHeight = qrCodeHeight - ) - } - } - } - } - - private suspend fun getQrCodesResultForEuropeanVaccination( - greenCardType: GreenCardType, - credentialsWithExpirationTime: List>, - shouldDisclose: QrCodeFragmentData.ShouldDisclose, - qrCodeWidth: Int, - qrCodeHeight: Int - ): QrCodesResult.MultipleQrCodes { - val europeanVaccinationQrCodeDataList = mapToEuropeanVaccinations( - credentialsWithExpirationTime, qrCodeWidth, qrCodeHeight, shouldDisclose, greenCardType - ) - - return QrCodesResult.MultipleQrCodes( - europeanVaccinationQrCodeDataList = europeanVaccinationQrCodeDataList, - mostRelevantVaccinationIndex = multipleQrCodesUtil.getMostRelevantQrCodeIndex( - europeanVaccinationQrCodeDataList - ) - ) - } - - private suspend fun mapToEuropeanVaccinations( - credentialsWithExpirationTime: List>, - qrCodeWidth: Int, - qrCodeHeight: Int, - shouldDisclose: QrCodeFragmentData.ShouldDisclose, - greenCardType: GreenCardType - ): List { - val readEuropeanCredentials = - credentialsWithExpirationTime.map { mobileCoreWrapper.readEuropeanCredential(it.first) } - return credentialsWithExpirationTime.mapIndexed { index, credentialWithExpirationTime -> - val credentials = credentialWithExpirationTime.first - val credentialExpirationTimeSeconds = - credentialWithExpirationTime.second.toEpochSecond() - val qrCodeBitmap = qrCodeUseCase.qrCode( - credential = credentials, - qrCodeWidth = qrCodeWidth, - qrCodeHeight = qrCodeHeight, - shouldDisclose = shouldDisclose, - errorCorrectionLevel = greenCardUtil.getErrorCorrectionLevel(greenCardType) - ) - - val readEuropeanCredential = readEuropeanCredentials[index] - val dose = readEuropeanCredentialUtil.getDose(readEuropeanCredential) ?: "" - val totalDoses = - readEuropeanCredentialUtil.getOfTotalDoses(readEuropeanCredential) ?: "" - - val isExpired = - credentialUtil.europeanCredentialHasExpired(credentialExpirationTimeSeconds) - val isDoseSmaller = - credentialUtil.vaccinationShouldBeHidden(readEuropeanCredentials, index) - QrCodeData.European.Vaccination( - dose = dose, - ofTotalDoses = totalDoses, - bitmap = qrCodeBitmap, - readEuropeanCredential = readEuropeanCredential, - isExpired = isExpired, - isDoseNumberSmallerThanTotalDose = isDoseSmaller - ) - } - } - - private suspend fun getQrCodesResultForNonVaccination( - greenCardType: GreenCardType, - originType: OriginType, - credentialsWithExpirationTime: List>, - credentials: List, - shouldDisclose: QrCodeFragmentData.ShouldDisclose, - qrCodeWidth: Int, - qrCodeHeight: Int - ): QrCodesResult.SingleQrCode { - val credential = credentials.first() - val qrCodeBitmap = qrCodeUseCase.qrCode( - credential = credential, - qrCodeWidth = qrCodeWidth, - qrCodeHeight = qrCodeHeight, - shouldDisclose = shouldDisclose, - errorCorrectionLevel = greenCardUtil.getErrorCorrectionLevel(greenCardType) - ) - - val credentialsExpired = credentialsWithExpirationTime.mapIndexed { _, credentialWithExpirationTime -> - val credentialExpirationTimeSeconds = - credentialWithExpirationTime.second.toEpochSecond() - - credentialUtil.europeanCredentialHasExpired(credentialExpirationTimeSeconds) - } - - return QrCodesResult.SingleQrCode( - QrCodeData.European.NonVaccination( - isExpired = credentialsExpired.all { it }, - bitmap = qrCodeBitmap, - readEuropeanCredential = mobileCoreWrapper.readEuropeanCredential(credential), - explanationNeeded = originType != OriginType.Test - ) - ) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/utils/LastVaccinationDoseUtil.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/utils/LastVaccinationDoseUtil.kt deleted file mode 100644 index 6fed729b7..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/utils/LastVaccinationDoseUtil.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.qrcodes.utils - -import android.content.res.Resources -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEventVaccination - -interface LastVaccinationDoseUtil { - - fun getIsLastDoseAnswer(event: RemoteEventVaccination): String -} - -class LastVaccinationDoseUtilImpl( - private val resources: Resources -) : LastVaccinationDoseUtil { - - override fun getIsLastDoseAnswer(event: RemoteEventVaccination) = - event.vaccination?.run { - when { - completed() && completionReason == "first-vaccination-elsewhere" -> resources.getString(R.string.holder_eventdetails_vaccinationStatus_firstVaccinationElsewhere) - completed() && completionReason == "recovery" -> resources.getString(R.string.holder_eventdetails_vaccinationStatus_recovery) - completed() && completionReason.isNullOrEmpty() -> resources.getString(R.string.holder_eventdetails_vaccinationStatus_complete) - else -> "" - } - } ?: "" - - private fun RemoteEventVaccination.Vaccination.completed() = - completedByMedicalStatement == true || completedByPersonalStatement == true - - private fun RemoteEventVaccination.Vaccination.notCompleted() = - completedByMedicalStatement == false || completedByPersonalStatement == false -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/utils/MultipleQrCodesUtil.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/utils/MultipleQrCodesUtil.kt deleted file mode 100644 index 1e2556da9..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/utils/MultipleQrCodesUtil.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.qrcodes.utils - -import nl.rijksoverheid.ctr.holder.qrcodes.models.QrCodeData - -interface MultipleQrCodesUtil { - fun getMostRelevantQrCodeIndex(vaccinations: List): Int -} - -class MultipleQrCodesUtilImpl : MultipleQrCodesUtil { - - override fun getMostRelevantQrCodeIndex(vaccinations: List): Int { - val mostRelevantVaccination = vaccinations.sortedWith( - compareBy { !it.isDoseNumberSmallerThanTotalDose } - .thenBy { it.dose } - .thenBy { it.ofTotalDoses } - ).last() - return vaccinations.indexOfFirst { it == mostRelevantVaccination } - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/utils/QrCodeUtil.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/utils/QrCodeUtil.kt deleted file mode 100644 index 1ad1b34f3..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/utils/QrCodeUtil.kt +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.qrcodes.utils - -import android.graphics.Bitmap -import android.graphics.Color -import com.google.zxing.BarcodeFormat -import com.google.zxing.EncodeHintType -import com.google.zxing.MultiFormatWriter -import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel -import java.util.EnumMap - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -interface QrCodeUtil { - fun createQrCode( - qrCodeContent: String, - width: Int, - height: Int, - errorCorrectionLevel: ErrorCorrectionLevel - ): Bitmap -} - -class QrCodeUtilImpl : QrCodeUtil { - override fun createQrCode( - qrCodeContent: String, - width: Int, - height: Int, - errorCorrectionLevel: ErrorCorrectionLevel - ): Bitmap { - val multiFormatWriter = MultiFormatWriter() - val hints: MutableMap = EnumMap( - EncodeHintType::class.java - ) - hints[EncodeHintType.MARGIN] = 0 - hints[EncodeHintType.ERROR_CORRECTION] = errorCorrectionLevel - val bitMatrix = multiFormatWriter.encode( - qrCodeContent, - BarcodeFormat.QR_CODE, - 0, - 0, - hints - ) - val bitmap = Bitmap.createBitmap( - width, - height, - Bitmap.Config.RGB_565 - ) - val pixels = IntArray(width * height) - for (y in 0 until height) { - val offset = y * width - for (x in 0 until width) { - val xf: Float = x.toFloat() / width - val yf: Float = y.toFloat() / height - pixels[offset + x] = if (bitMatrix.get( - (xf * bitMatrix.width.toFloat()).toInt(), - (yf * bitMatrix.height.toFloat()).toInt() - ) - ) Color.BLACK else Color.WHITE - } - } - bitmap.setPixels(pixels, 0, width, 0, 0, width, height) - return bitmap - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/utils/QrCodesFragmentUtil.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/utils/QrCodesFragmentUtil.kt deleted file mode 100644 index d54ec7b20..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/utils/QrCodesFragmentUtil.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.qrcodes.utils - -import java.time.Clock -import java.time.Instant -import nl.rijksoverheid.ctr.holder.qrcodes.QrCodesFragment -import nl.rijksoverheid.ctr.persistence.database.entities.GreenCardType - -interface QrCodesFragmentUtil { - /** - * If [QrCodesFragment] should close - */ - fun shouldClose(credentialExpirationTimeSeconds: Long, type: GreenCardType): Boolean -} - -class QrCodesFragmentUtilImpl( - private val utcClock: Clock -) : QrCodesFragmentUtil { - - override fun shouldClose(credentialExpirationTimeSeconds: Long, type: GreenCardType): Boolean { - if (type == GreenCardType.Eu) { - return false - } - val now = Instant.now(utcClock) - val expiration = Instant.ofEpochSecond(credentialExpirationTimeSeconds) - return now.isAfter(expiration) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/utils/QrInfoScreenUtil.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/utils/QrInfoScreenUtil.kt deleted file mode 100644 index 66693966a..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/qrcodes/utils/QrInfoScreenUtil.kt +++ /dev/null @@ -1,406 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ -package nl.rijksoverheid.ctr.holder.qrcodes.utils - -import android.app.Application -import android.text.TextUtils -import androidx.core.text.HtmlCompat -import java.time.LocalDate -import java.time.OffsetDateTime -import java.time.format.DateTimeFormatter -import java.time.format.DateTimeParseException -import nl.rijksoverheid.ctr.design.ext.formatDateTimeWithTimeZone -import nl.rijksoverheid.ctr.design.ext.formatDayMonthYearNumerical -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.qrcodes.models.ReadEuropeanCredentialUtil -import nl.rijksoverheid.ctr.holder.utils.CountryUtil -import nl.rijksoverheid.ctr.holder.utils.LocalDateUtil -import nl.rijksoverheid.ctr.persistence.HolderCachedAppConfigUseCase -import nl.rijksoverheid.ctr.shared.ext.getStringOrNull -import nl.rijksoverheid.ctr.shared.ext.locale -import org.json.JSONObject - -interface QrInfoScreenUtil { - - fun getForEuropeanTestQr(readEuropeanCredential: JSONObject): QrInfoScreen - fun getForEuropeanVaccinationQr(readEuropeanCredential: JSONObject): QrInfoScreen - fun getForEuropeanRecoveryQr(readEuropeanCredential: JSONObject): QrInfoScreen -} - -class QrInfoScreenUtilImpl( - private val application: Application, - private val readEuropeanCredentialUtil: ReadEuropeanCredentialUtil, - private val countryUtil: CountryUtil, - private val localDateUtil: LocalDateUtil, - cachedAppConfigUseCase: HolderCachedAppConfigUseCase -) : QrInfoScreenUtil { - - private val holderConfig = cachedAppConfigUseCase.getCachedAppConfig() - - override fun getForEuropeanTestQr(readEuropeanCredential: JSONObject): QrInfoScreen { - val dcc = requireNotNull(readEuropeanCredential.optJSONObject("dcc")) - val test = dcc.getJSONArray("t").optJSONObject(0) - - val title = application.getString(R.string.qr_explanation_title_eu) - - val fullName = "${dcc.optJSONObject("nam").getStringOrNull("fn")}, ${ - dcc.optJSONObject("nam").getStringOrNull("gn") - }" - - val birthDate = dcc.getStringOrNull("dob")?.let { birthDate -> - try { - LocalDate.parse(birthDate, DateTimeFormatter.ISO_DATE).formatDayMonthYearNumerical() - } catch (e: Exception) { - "" - } - } ?: "" - - val disease = application.getString(R.string.your_vaccination_explanation_covid_19_answer) - - val testType = holderConfig.euTestTypes.firstOrNull { - it.code == test.getStringOrNull("tt") - }?.name ?: test.getStringOrNull("tt") ?: "" - - val testName = test.getStringOrNull("nm") ?: "" - - val testDate = test.getStringOrNull("sc")?.let { - try { - OffsetDateTime.parse(it, DateTimeFormatter.ISO_OFFSET_DATE_TIME) - .formatDateTimeWithTimeZone(application) - } catch (e: Exception) { - "" - } - } ?: "" - - val testResult = - application.getString(R.string.holder_showqr_eu_about_test_negative) - - val testLocation = test.getStringOrNull("tc") ?: "" - - val manufacturer = - holderConfig.euTestManufacturers.firstOrNull { - it.code == test.getStringOrNull("ma") - }?.name ?: test.getStringOrNull("ma") ?: "" - - val testCountry = - countryUtil.getCountryForQrInfoScreen( - test.getStringOrNull("co"), - application.applicationContext.locale() - ) - - val issuerValue = test.getStringOrNull("is") - val issuer = if (issuerValue == issuerVWS) { - application.getString(R.string.qr_explanation_certificate_issuer) - } else { - issuerValue - } - - val uniqueCode = test.getStringOrNull("ci") - - val texts = mutableListOf( - application.getString(R.string.qr_explanation_description_eu_test_header), - "

", - application.getString(R.string.qr_explanation_description_eu_test_name), - createQrAnswer(fullName), - application.getString(R.string.qr_explanation_description_eu_test_birth_date), - createQrAnswer(birthDate), - application.getString(R.string.qr_explanation_description_eu_test_disease), - createQrAnswer(disease) - ) - - if (testType.isNotBlank()) { - texts.addAll( - listOf( - application.getString(R.string.qr_explanation_description_eu_test_test_type), - createQrAnswer(testType) - ) - ) - } - - if (testName.isNotBlank()) { - texts.addAll( - listOf( - application.getString(R.string.qr_explanation_description_eu_test_test_name), - createQrAnswer(testName) - ) - ) - } - - if (testDate.isNotBlank()) { - texts.addAll( - listOf( - application.getString(R.string.qr_explanation_description_eu_test_test_date), - createQrAnswer(testDate) - ) - ) - } - - if (testResult.isNotBlank()) { - texts.addAll( - listOf( - application.getString(R.string.qr_explanation_description_eu_test_test_result), - createQrAnswer(testResult) - ) - ) - } - - if (manufacturer.isNotBlank()) { - texts.addAll( - listOf( - application.getString(R.string.qr_explanation_description_eu_test_manufacturer), - createQrAnswer(manufacturer) - ) - ) - } - - if (testLocation.isNotBlank()) { - texts.addAll( - listOf( - application.getString(R.string.qr_explanation_description_eu_test_test_centre), - createQrAnswer(testLocation) - ) - ) - } - - if (testCountry.isNotBlank()) { - texts.addAll( - listOf( - application.getString(R.string.qr_explanation_description_eu_test_test_country), - createQrAnswer(testCountry) - ) - ) - } - - if (issuer?.isNotBlank() == true) { - texts.addAll( - listOf( - application.getString(R.string.qr_explanation_description_eu_test_issuer), - createQrAnswer(issuer) - ) - ) - } - - if (uniqueCode?.isNotBlank() == true) { - texts.addAll( - listOf( - application.getString(R.string.qr_explanation_description_eu_test_certificate_identifier), - createQrAnswer(uniqueCode) - ) - ) - } - - return QrInfoScreen( - title = title, - description = (TextUtils.concat(*texts.toTypedArray()) as String), - footer = application.getString(R.string.qr_explanation_description_eu_test_footer) - ) - } - - override fun getForEuropeanVaccinationQr(readEuropeanCredential: JSONObject): QrInfoScreen { - val dcc = requireNotNull(readEuropeanCredential.optJSONObject("dcc")) - val vaccination = dcc.getJSONArray("v").optJSONObject(0) - - val fullName = "${dcc.optJSONObject("nam").getStringOrNull("fn")}, ${ - dcc.optJSONObject("nam").getStringOrNull("gn") - }" - - val birthDate = dcc.getStringOrNull("dob")?.let { birthDate -> - try { - LocalDate.parse(birthDate, DateTimeFormatter.ISO_DATE).formatDayMonthYearNumerical() - } catch (e: DateTimeParseException) { - // Check if date has removed content, if so return year or string only - if (birthDate.contains("XX")) { - // Retrieve birth year only - birthDate.split("-").first() - } else birthDate - } catch (e: Exception) { - "" - } - } ?: "" - - val disease = application.getString(R.string.your_vaccination_explanation_covid_19_answer) - - val vaccin = holderConfig.euBrands.firstOrNull { - it.code == vaccination.getStringOrNull("mp") - }?.name ?: vaccination.getStringOrNull("mp") ?: "" - - val vaccinType = holderConfig.euVaccinations.firstOrNull { - it.code == vaccination.getStringOrNull("vp") - }?.name ?: vaccination.getStringOrNull("vp") ?: "" - - val manufacturer = - holderConfig.euManufacturers.firstOrNull { - it.code == vaccination.getStringOrNull("ma") - }?.name ?: vaccination.getStringOrNull("ma") ?: "" - - val doses = - readEuropeanCredentialUtil.getDoseRangeStringForVaccination(readEuropeanCredential) - val overDoseLink = - if (readEuropeanCredentialUtil.doseExceedsTotalDoses(readEuropeanCredential)) { - application.getString(R.string.holder_showqr_eu_about_vaccination_dosage_message) - } else "" - - val (vaccinationDate, vaccinationDays) = vaccination.getStringOrNull("dt") - ?.let { vaccinationDate -> - localDateUtil.dateAndDaysSince(vaccinationDate) - } ?: Pair("", "") - - val countryCode = vaccination.getStringOrNull("co") - val vaccinationCountry = - countryUtil.getCountryForQrInfoScreen( - countryCode, - application.applicationContext.locale() - ) - - val issuerValue = vaccination.getStringOrNull("is") - val issuer = if (issuerValue == issuerVWS) { - application.getString(R.string.qr_explanation_certificate_issuer) - } else { - issuerValue - } - - val uniqueCode = vaccination.getStringOrNull("ci") - - val title = application.getString(R.string.qr_explanation_title_eu_vaccination, doses) - - return QrInfoScreen( - title = title, - description = (TextUtils.concat( - application.getString(R.string.qr_explanation_description_eu_vaccination_header), - "

", - application.getString(R.string.qr_explanation_description_eu_vaccination_name), - createQrAnswer(fullName), - application.getString(R.string.qr_explanation_description_eu_vaccination_birth_date), - createQrAnswer(birthDate), - application.getString(R.string.qr_explanation_description_eu_vaccination_disease), - createQrAnswer(disease), - application.getString(R.string.qr_explanation_description_eu_vaccination_vaccine), - createQrAnswer(vaccin), - application.getString(R.string.qr_explanation_description_eu_vaccination_vaccine_type), - createQrAnswer(vaccinType), - application.getString(R.string.qr_explanation_description_eu_vaccination_producer), - createQrAnswer(manufacturer), - application.getString(R.string.qr_explanation_description_eu_vaccination_doses), - createQrAnswer(doses, overDoseLink), - application.getString(R.string.qr_explanation_description_eu_vaccination_vaccination_date), - createQrAnswer(vaccinationDate), - application.getString(R.string.holder_showQR_euAboutVaccination_daysSince), - createQrAnswer(vaccinationDays), - application.getString(R.string.qr_explanation_description_eu_vaccination_vaccinated_in), - createQrAnswer(vaccinationCountry), - application.getString(R.string.qr_explanation_description_eu_vaccination_certificate_issuer), - createQrAnswer(issuer ?: ""), - application.getString(R.string.qr_explanation_description_eu_vaccination_unique_certificate), - createQrAnswer(uniqueCode ?: "") - ) as String), - footer = application.getString(R.string.qr_explanation_description_eu_vaccination_footer) - ) - } - - override fun getForEuropeanRecoveryQr(readEuropeanCredential: JSONObject): QrInfoScreen { - val dcc = requireNotNull(readEuropeanCredential.optJSONObject("dcc")) - val recovery = dcc.getJSONArray("r").optJSONObject(0) - - val title = application.getString(R.string.qr_explanation_title_eu) - - val fullName = "${dcc.optJSONObject("nam").getStringOrNull("fn")}, ${ - dcc.optJSONObject("nam").getStringOrNull("gn") - }" - - val birthDate = dcc.getStringOrNull("dob")?.let { birthDate -> - try { - LocalDate.parse(birthDate, DateTimeFormatter.ISO_DATE).formatDayMonthYearNumerical() - } catch (e: Exception) { - "" - } - } ?: "" - - val disease = application.getString(R.string.your_vaccination_explanation_covid_19_answer) - - val testDate = recovery.getStringOrNull("fr")?.let { testDate -> - try { - LocalDate.parse(testDate, DateTimeFormatter.ISO_DATE).formatDayMonthYearNumerical() - } catch (e: Exception) { - "" - } - } ?: "" - - val country = countryUtil.getCountryForQrInfoScreen( - recovery.getStringOrNull("co"), - application.applicationContext.locale() - ) - - val issuerValue = recovery.getStringOrNull("is") - val issuer = if (issuerValue == issuerVWS) { - application.getString(R.string.qr_explanation_certificate_issuer) - } else { - issuerValue - } - - val validFromDate = recovery.getStringOrNull("df")?.let { - try { - LocalDate.parse(it, DateTimeFormatter.ISO_DATE).formatDayMonthYearNumerical() - } catch (e: Exception) { - "" - } - } ?: "" - - val validUntilDate = recovery.getStringOrNull("du")?.let { - try { - LocalDate.parse(it, DateTimeFormatter.ISO_DATE).formatDayMonthYearNumerical() - } catch (e: Exception) { - "" - } - } ?: "" - - val uniqueCode = recovery.getStringOrNull("ci") - - return QrInfoScreen( - title = title, - description = (TextUtils.concat( - application.getString(R.string.qr_explanation_description_eu_recovery_header), - "

", - application.getString(R.string.qr_explanation_description_eu_recovery_name), - createQrAnswer(fullName), - application.getString(R.string.qr_explanation_description_eu_recovery_birth_date), - createQrAnswer(birthDate), - application.getString(R.string.qr_explanation_description_eu_recovery_disease), - createQrAnswer(disease), - application.getString(R.string.qr_explanation_description_eu_recovery_test_date), - createQrAnswer(testDate), - application.getString(R.string.qr_explanation_description_eu_recovery_country), - createQrAnswer(country), - application.getString(R.string.qr_explanation_description_eu_recovery_producer), - createQrAnswer(issuer ?: ""), - application.getString(R.string.qr_explanation_description_eu_recovery_valid_from_date), - createQrAnswer(validFromDate), - application.getString(R.string.qr_explanation_description_eu_recovery_valid_until_date), - createQrAnswer(validUntilDate), - application.getString(R.string.qr_explanation_description_eu_recovery_unique_code), - createQrAnswer(uniqueCode ?: "") - ) as String), - footer = application.getString(R.string.qr_explanation_description_eu_recovery_footer) - ) - } - - private fun createQrAnswer(answer: String, answerDescription: String = ""): String { - val sanitizedAnswer = HtmlCompat.fromHtml(answer, HtmlCompat.FROM_HTML_MODE_LEGACY).toString() - val sanitizedAnswerDescription = - HtmlCompat.fromHtml(answerDescription, HtmlCompat.FROM_HTML_MODE_LEGACY).toString() - return "
$sanitizedAnswer
${if (answerDescription.isEmpty()) "
" else "$sanitizedAnswerDescription

"}" - } - - companion object { - private const val issuerVWS = "Ministry of Health Welfare and Sport" - } -} - -data class QrInfoScreen( - val title: String, - val description: String, - val footer: String = "" -) diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/saved_events/SavedEvents.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/saved_events/SavedEvents.kt deleted file mode 100644 index 0017b640d..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/saved_events/SavedEvents.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.saved_events - -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEvent -import nl.rijksoverheid.ctr.holder.your_events.utils.InfoScreen -import nl.rijksoverheid.ctr.persistence.database.entities.EventGroupEntity - -data class SavedEvents( - val providerName: String, - val eventGroupEntity: EventGroupEntity, - val events: List -) { - data class SavedEvent( - val remoteEvent: RemoteEvent, - val infoScreen: InfoScreen - ) -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/saved_events/SavedEventsFragment.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/saved_events/SavedEventsFragment.kt deleted file mode 100644 index 17dee9f71..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/saved_events/SavedEventsFragment.kt +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.saved_events - -import android.os.Bundle -import android.view.View -import androidx.fragment.app.Fragment -import com.xwray.groupie.GroupAdapter -import com.xwray.groupie.GroupieViewHolder -import com.xwray.groupie.Section -import nl.rijksoverheid.ctr.design.utils.DialogUtil -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.databinding.FragmentSavedEventsBinding -import nl.rijksoverheid.ctr.holder.saved_events.items.SavedEventsHeaderAdapterItem -import nl.rijksoverheid.ctr.holder.saved_events.items.SavedEventsNoSavedEventsItem -import nl.rijksoverheid.ctr.holder.saved_events.items.SavedEventsSectionAdapterItem -import nl.rijksoverheid.ctr.holder.usecases.HolderFeatureFlagUseCase -import nl.rijksoverheid.ctr.shared.ext.navigateSafety -import nl.rijksoverheid.ctr.shared.livedata.EventObserver -import org.koin.android.ext.android.inject -import org.koin.androidx.viewmodel.ext.android.viewModel - -class SavedEventsFragment : Fragment(R.layout.fragment_saved_events) { - - private val sections: MutableList
= mutableListOf() - private val adapter = GroupAdapter() - private val savedEventsViewModel: SavedEventsViewModel by viewModel() - private val dialogUtil: DialogUtil by inject() - private val featureFlagUseCase: HolderFeatureFlagUseCase by inject() - private val isInArchiveMode: Boolean = featureFlagUseCase.isInArchiveMode() - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - val binding = FragmentSavedEventsBinding.bind(view) - initRecyclerView(binding) - - listenToSavedEvents() - listenToRemoveSavedEvents() - savedEventsViewModel.getSavedEvents() - } - - private fun initRecyclerView(binding: FragmentSavedEventsBinding) { - sections.clear() - - binding.savedEventsRecyclerView.adapter = adapter - binding.savedEventsRecyclerView.itemAnimator = null - } - - private fun listenToSavedEvents() { - savedEventsViewModel.savedEventsLiveData.observe( - viewLifecycleOwner, - EventObserver { savedEvents -> - sections.clear() - adapter.clear() - val headerSection = Section() - headerSection.add(SavedEventsHeaderAdapterItem()) - sections.add(headerSection) - - if (savedEvents.isEmpty()) { - val emptyItemsSection = Section() - emptyItemsSection.add(SavedEventsNoSavedEventsItem()) - sections.add(emptyItemsSection) - } else { - savedEvents.forEach { - val item = SavedEventsSectionAdapterItem( - isNotInArchiveMode = !isInArchiveMode, - savedEvents = it, - onClickEvent = { toolbarTitle, infoScreen -> - navigateSafety( - SavedEventsFragmentDirections.actionYourEventExplanation( - toolbarTitle = toolbarTitle, - data = arrayOf(infoScreen) - ) - ) - }, - onClickClearData = { eventGroupEntity -> - presentClearDataDialog { - savedEventsViewModel.removeSavedEvents(eventGroupEntity) - } - } - ) - val itemSection = item.section(it) - itemSection.setHeader(item) - sections.add(itemSection) - } - } - adapter.addAll(sections) - }) - } - - private fun listenToRemoveSavedEvents() { - savedEventsViewModel.removedSavedEventsLiveData.observe(viewLifecycleOwner) { - navigateSafety( - SavedEventsFragmentDirections.actionSavedEventsSyncGreenCards() - ) - } - } - - private fun presentClearDataDialog(onClear: () -> Unit) { - dialogUtil.presentDialog( - context = requireContext(), - title = R.string.holder_storedEvent_alert_removeEvents_title, - message = getString(R.string.holder_storedEvent_alert_removeEvents_message), - positiveButtonText = R.string.general_delete, - negativeButtonText = R.string.general_cancel, - positiveButtonCallback = { - onClear.invoke() - } - ) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/saved_events/SavedEventsSyncGreenCardsFragment.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/saved_events/SavedEventsSyncGreenCardsFragment.kt deleted file mode 100644 index 6df1d00ec..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/saved_events/SavedEventsSyncGreenCardsFragment.kt +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.saved_events - -import android.os.Bundle -import android.view.View -import nl.rijksoverheid.ctr.holder.BaseFragment -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.fuzzy_matching.MatchingBlobIds -import nl.rijksoverheid.ctr.holder.models.HolderFlow -import nl.rijksoverheid.ctr.holder.sync_greencards.SyncGreenCardsViewModel -import nl.rijksoverheid.ctr.persistence.database.DatabaseSyncerResult -import nl.rijksoverheid.ctr.shared.ext.navigateSafety -import nl.rijksoverheid.ctr.shared.livedata.EventObserver -import nl.rijksoverheid.ctr.shared.models.Flow -import org.koin.androidx.viewmodel.ext.android.viewModel - -class SavedEventsSyncGreenCardsFragment : BaseFragment(R.layout.fragment_saved_events_sync_green_cards) { - - private val syncGreenCardsViewModel: SyncGreenCardsViewModel by viewModel() - - override fun onButtonClickWithRetryAction() { - // This screen does not have a retry button - } - - override fun getFlow(): Flow { - return HolderFlow.ClearEvents - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - syncGreenCardsViewModel.refresh() - - syncGreenCardsViewModel.databaseSyncerResultLiveData.observe(viewLifecycleOwner, EventObserver { - when (it) { - is DatabaseSyncerResult.Success -> { - navigateSafety( - SavedEventsSyncGreenCardsFragmentDirections.actionSavedEvents() - ) - } - is DatabaseSyncerResult.Failed -> { - presentError( - errorResult = it.errorResult - ) - } - is DatabaseSyncerResult.FuzzyMatchingError -> { - navigateSafety(SavedEventsSyncGreenCardsFragmentDirections.actionFuzzyMatching( - MatchingBlobIds(it.matchingBlobIds) - )) - } - } - }) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/saved_events/SavedEventsViewModel.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/saved_events/SavedEventsViewModel.kt deleted file mode 100644 index e2842332f..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/saved_events/SavedEventsViewModel.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.saved_events - -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import nl.rijksoverheid.ctr.holder.saved_events.usecases.GetSavedEventsUseCase -import nl.rijksoverheid.ctr.persistence.database.HolderDatabase -import nl.rijksoverheid.ctr.persistence.database.entities.EventGroupEntity -import nl.rijksoverheid.ctr.persistence.database.entities.RemovedEventReason -import nl.rijksoverheid.ctr.shared.livedata.Event - -class SavedEventsViewModel( - private val holderDatabase: HolderDatabase, - private val getSavedEventsUseCase: GetSavedEventsUseCase -) : ViewModel() { - - val savedEventsLiveData: LiveData>> = MutableLiveData() - val removedSavedEventsLiveData: LiveData = MutableLiveData() - - fun getSavedEvents() { - viewModelScope.launch(Dispatchers.IO) { - val savedEvents = getSavedEventsUseCase.getSavedEvents() - (savedEventsLiveData as MutableLiveData).postValue(Event(savedEvents)) - } - } - - fun removeSavedEvents(eventGroupEntity: EventGroupEntity) { - viewModelScope.launch { - holderDatabase.eventGroupDao().delete(eventGroupEntity) - // the user deleted consciously a stored event and is aware of the currently stored events - // so no point to communicate anymore which conflicted events were deleted - holderDatabase.removedEventDao().deleteAll(RemovedEventReason.FuzzyMatched) - (removedSavedEventsLiveData as MutableLiveData).postValue(Unit) - } - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/saved_events/items/SavedEventAdapterItem.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/saved_events/items/SavedEventAdapterItem.kt deleted file mode 100644 index 4d01665ca..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/saved_events/items/SavedEventAdapterItem.kt +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.saved_events.items - -import android.view.View -import com.xwray.groupie.viewbinding.BindableItem -import nl.rijksoverheid.ctr.design.ext.formatDayMonthYear -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.databinding.AdapterItemSavedEventBinding -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEventNegativeTest -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEventPositiveTest -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEventRecovery -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEventVaccination -import nl.rijksoverheid.ctr.holder.saved_events.SavedEvents -import nl.rijksoverheid.ctr.holder.your_events.utils.InfoScreen -import nl.rijksoverheid.ctr.shared.ext.capitalize - -class SavedEventAdapterItem( - private val savedEvent: SavedEvents.SavedEvent, - private val onClick: (toolbarTitle: String, infoScreen: InfoScreen) -> Unit -) : BindableItem() { - - override fun bind(viewBinding: AdapterItemSavedEventBinding, position: Int) { - val context = viewBinding.root.context - val title = when (savedEvent.remoteEvent) { - is RemoteEventVaccination -> context.getString(R.string.general_vaccination).capitalize() - is RemoteEventNegativeTest -> context.getString(R.string.general_negativeTest).capitalize() - is RemoteEventPositiveTest -> context.getString(R.string.general_positiveTest).capitalize() - is RemoteEventRecovery -> context.getString(R.string.general_recoverycertificate).capitalize() - else -> "" - } - viewBinding.title.text = title - viewBinding.subtitle.text = savedEvent.remoteEvent.getDate()?.toLocalDate()?.formatDayMonthYear() - viewBinding.root.setOnClickListener { - onClick.invoke(title, savedEvent.infoScreen) - } - } - - override fun getLayout(): Int { - return R.layout.adapter_item_saved_event - } - - override fun initializeViewBinding(view: View): AdapterItemSavedEventBinding { - return AdapterItemSavedEventBinding.bind(view) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/saved_events/items/SavedEventsClearDataAdapterItem.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/saved_events/items/SavedEventsClearDataAdapterItem.kt deleted file mode 100644 index ef9e9e855..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/saved_events/items/SavedEventsClearDataAdapterItem.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.saved_events.items - -import android.view.View -import com.xwray.groupie.viewbinding.BindableItem -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.databinding.AdapterItemSavedEventsClearDataBinding -import nl.rijksoverheid.ctr.persistence.database.entities.EventGroupEntity - -class SavedEventsClearDataAdapterItem( - private val eventGroupEntity: EventGroupEntity, - private val onClick: (eventGroupEntity: EventGroupEntity) -> Unit -) : BindableItem() { - - override fun bind(viewBinding: AdapterItemSavedEventsClearDataBinding, position: Int) { - viewBinding.root.setOnClickListener { - onClick.invoke(eventGroupEntity) - } - } - - override fun getLayout(): Int { - return R.layout.adapter_item_saved_events_clear_data - } - - override fun initializeViewBinding(view: View): AdapterItemSavedEventsClearDataBinding { - return AdapterItemSavedEventsClearDataBinding.bind(view) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/saved_events/items/SavedEventsHeaderAdapterItem.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/saved_events/items/SavedEventsHeaderAdapterItem.kt deleted file mode 100644 index ca3cc1ec8..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/saved_events/items/SavedEventsHeaderAdapterItem.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.saved_events.items - -import android.view.View -import com.xwray.groupie.viewbinding.BindableItem -import nl.rijksoverheid.ctr.design.utils.IntentUtil -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.databinding.AdapterItemSavedEventsHeaderBinding -import org.koin.core.component.KoinComponent -import org.koin.core.component.inject - -class SavedEventsHeaderAdapterItem : BindableItem(), KoinComponent { - - private val intentUtil: IntentUtil by inject() - - override fun bind(viewBinding: AdapterItemSavedEventsHeaderBinding, position: Int) { - val context = viewBinding.root.context - - viewBinding.button.setOnClickListener { - intentUtil.openUrl( - context = context, - url = context.getString(R.string.holder_storedEvents_url) - ) - } - } - - override fun getLayout(): Int { - return R.layout.adapter_item_saved_events_header - } - - override fun initializeViewBinding(view: View): AdapterItemSavedEventsHeaderBinding { - return AdapterItemSavedEventsHeaderBinding.bind(view) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/saved_events/items/SavedEventsNoSavedEventsItem.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/saved_events/items/SavedEventsNoSavedEventsItem.kt deleted file mode 100644 index a85abd936..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/saved_events/items/SavedEventsNoSavedEventsItem.kt +++ /dev/null @@ -1,27 +0,0 @@ - /* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.saved_events.items - -import android.view.View -import com.xwray.groupie.viewbinding.BindableItem -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.databinding.AdapterItemSavedEventsNoSavedEventsBinding - -class SavedEventsNoSavedEventsItem : BindableItem() { - - override fun bind(viewBinding: AdapterItemSavedEventsNoSavedEventsBinding, position: Int) { - } - - override fun getLayout(): Int { - return R.layout.adapter_item_saved_events_no_saved_events - } - - override fun initializeViewBinding(view: View): AdapterItemSavedEventsNoSavedEventsBinding { - return AdapterItemSavedEventsNoSavedEventsBinding.bind(view) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/saved_events/items/SavedEventsSectionAdapterItem.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/saved_events/items/SavedEventsSectionAdapterItem.kt deleted file mode 100644 index d7f12097b..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/saved_events/items/SavedEventsSectionAdapterItem.kt +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.saved_events.items - -import android.view.View -import com.xwray.groupie.Section -import com.xwray.groupie.viewbinding.BindableItem -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.databinding.AdapterItemSavedEventsSectionBinding -import nl.rijksoverheid.ctr.holder.saved_events.SavedEvents -import nl.rijksoverheid.ctr.holder.your_events.utils.InfoScreen -import nl.rijksoverheid.ctr.holder.your_events.utils.RemoteEventUtil -import nl.rijksoverheid.ctr.persistence.database.entities.EventGroupEntity -import org.koin.core.component.KoinComponent -import org.koin.core.component.inject - -class SavedEventsSectionAdapterItem( - private val isNotInArchiveMode: Boolean, - private val savedEvents: SavedEvents, - private val onClickEvent: (toolbarTitle: String, infoScreen: InfoScreen) -> Unit, - private val onClickClearData: (eventGroupEntity: EventGroupEntity) -> Unit -) : BindableItem(), KoinComponent { - - private val remoteEventUtil: RemoteEventUtil by inject() - - override fun bind(viewBinding: AdapterItemSavedEventsSectionBinding, position: Int) { - setReceivedAt( - viewBinding = viewBinding, - providerName = savedEvents.providerName - ) - } - - fun section( - savedEvents: SavedEvents - ): Section { - - val section = Section() - - val items = savedEvents.events.map { - SavedEventAdapterItem( - savedEvent = it, - onClick = onClickEvent - ) - } - section.addAll(items) - - if (isNotInArchiveMode) { - section.add( - SavedEventsClearDataAdapterItem( - eventGroupEntity = savedEvents.eventGroupEntity, - onClick = onClickClearData - ) - ) - } - - return section - } - - private fun setReceivedAt( - viewBinding: AdapterItemSavedEventsSectionBinding, - providerName: String - ) { - - val context = viewBinding.root.context - - viewBinding.retrievedAt.text = if (remoteEventUtil.isDccEvent(providerName)) { - context.getString(R.string.holder_storedEvents_listHeader_paperFlow) - } else { - context.getString(R.string.holder_storedEvents_listHeader_fetchedFromProvider, providerName) - } - } - - override fun getLayout(): Int { - return R.layout.adapter_item_saved_events_section - } - - override fun initializeViewBinding(view: View): AdapterItemSavedEventsSectionBinding { - return AdapterItemSavedEventsSectionBinding.bind(view) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/saved_events/usecases/GetSavedEventsUseCase.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/saved_events/usecases/GetSavedEventsUseCase.kt deleted file mode 100644 index f67207ddc..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/saved_events/usecases/GetSavedEventsUseCase.kt +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.saved_events.usecases - -import android.app.Application -import nl.rijksoverheid.ctr.design.ext.formatDateTime -import nl.rijksoverheid.ctr.design.ext.formatDayMonthYear -import nl.rijksoverheid.ctr.design.ext.formatDayMonthYearTime -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEventNegativeTest -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEventPositiveTest -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEventRecovery -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEventVaccination -import nl.rijksoverheid.ctr.holder.get_events.usecases.GetRemoteProtocolFromEventGroupUseCase -import nl.rijksoverheid.ctr.holder.saved_events.SavedEvents -import nl.rijksoverheid.ctr.holder.your_events.utils.EventGroupEntityUtil -import nl.rijksoverheid.ctr.holder.your_events.utils.InfoScreenUtil -import nl.rijksoverheid.ctr.holder.your_events.utils.RemoteEventUtil -import nl.rijksoverheid.ctr.holder.your_events.utils.YourEventsFragmentUtil -import nl.rijksoverheid.ctr.persistence.database.HolderDatabase -import org.json.JSONObject - -interface GetSavedEventsUseCase { - suspend fun getSavedEvents(): List -} - -class GetSavedEventsUseCaseImpl( - private val application: Application, - private val holderDatabase: HolderDatabase, - private val remoteEventUtil: RemoteEventUtil, - private val eventGroupEntityUtil: EventGroupEntityUtil, - private val getRemoteProtocolFromEventGroupUseCase: GetRemoteProtocolFromEventGroupUseCase, - private val infoScreenUtil: InfoScreenUtil, - private val yourEventsFragmentUtil: YourEventsFragmentUtil -) : GetSavedEventsUseCase { - - override suspend fun getSavedEvents(): List { - val eventGroups = holderDatabase.eventGroupDao().getAll() - - return eventGroups.map { eventGroupEntity -> - val isDccEvent = remoteEventUtil.isDccEvent( - providerIdentifier = eventGroupEntity.providerIdentifier - ) - val remoteProtocol = getRemoteProtocolFromEventGroupUseCase.get(eventGroupEntity) - - val fullName = yourEventsFragmentUtil.getFullName(remoteProtocol?.holder) - val birthDate = yourEventsFragmentUtil.getBirthDate(remoteProtocol?.holder) - - val providerName = eventGroupEntityUtil.getProviderName( - providerIdentifier = eventGroupEntity.providerIdentifier - ) - SavedEvents( - providerName = providerName, - eventGroupEntity = eventGroupEntity, - events = remoteProtocol?.events?.sortedByDescending { it.getDate() } - ?.mapNotNull { remoteEvent -> - val europeanCredential = if (isDccEvent) { - JSONObject(eventGroupEntity.jsonData.decodeToString()).getString("credential") - .toByteArray() - } else null - - val infoScreen = when (remoteEvent) { - is RemoteEventVaccination -> { - infoScreenUtil.getForVaccination( - event = remoteEvent, - fullName = fullName, - birthDate = birthDate, - providerIdentifier = providerName, - europeanCredential = europeanCredential, - addExplanation = false - ) - } - is RemoteEventRecovery -> { - infoScreenUtil.getForRecovery( - event = remoteEvent, - testDate = remoteEvent.recovery?.sampleDate?.formatDayMonthYear() - ?: "", - fullName = fullName, - birthDate = birthDate, - europeanCredential = europeanCredential, - addExplanation = false - ) - } - is RemoteEventPositiveTest -> { - infoScreenUtil.getForPositiveTest( - event = remoteEvent, - testDate = remoteEvent.positiveTest?.sampleDate?.formatDayMonthYearTime( - application - ) ?: "", - fullName = fullName, - birthDate = birthDate - ) - } - is RemoteEventNegativeTest -> { - infoScreenUtil.getForNegativeTest( - event = remoteEvent, - fullName = fullName, - testDate = remoteEvent.negativeTest?.sampleDate?.formatDateTime( - application - ) ?: "", - birthDate = birthDate, - europeanCredential = europeanCredential, - addExplanation = false - ) - } - else -> { - null - } - } - - if (infoScreen != null) { - SavedEvents.SavedEvent( - remoteEvent = remoteEvent, - infoScreen = infoScreen - ) - } else { - null - } - } ?: listOf() - ) - }.sortedByDescending { it.eventGroupEntity.id } - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/sync_greencards/SyncGreenCardsViewModel.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/sync_greencards/SyncGreenCardsViewModel.kt deleted file mode 100644 index 4dd3dbae9..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/sync_greencards/SyncGreenCardsViewModel.kt +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.sync_greencards - -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import kotlinx.coroutines.launch -import nl.rijksoverheid.ctr.holder.models.HolderStep -import nl.rijksoverheid.ctr.persistence.PersistenceManager -import nl.rijksoverheid.ctr.persistence.database.DatabaseSyncerResult -import nl.rijksoverheid.ctr.persistence.database.HolderDatabaseSyncer -import nl.rijksoverheid.ctr.shared.livedata.Event -import nl.rijksoverheid.ctr.shared.models.AppErrorResult - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -abstract class SyncGreenCardsViewModel : ViewModel() { - val loading: LiveData> = MutableLiveData() - val databaseSyncerResultLiveData: LiveData> = MutableLiveData() - - abstract fun refresh() -} - -class SyncGreenCardsViewModelImpl( - private val holderDatabaseSyncer: HolderDatabaseSyncer, - private val persistenceManager: PersistenceManager -) : SyncGreenCardsViewModel() { - override fun refresh() { - (loading as MutableLiveData).value = Event(true) - viewModelScope.launch { - try { - val databaseSyncerResult = holderDatabaseSyncer.sync() - if (databaseSyncerResult is DatabaseSyncerResult.Success) { - persistenceManager.setShowSyncGreenCardsItem(false) - } - (databaseSyncerResultLiveData as MutableLiveData).value = Event(databaseSyncerResult) - } catch (e: Exception) { - (databaseSyncerResultLiveData as MutableLiveData).value = Event( - DatabaseSyncerResult.Failed.Error(AppErrorResult(HolderStep.StoringEvents, e)) - ) - } finally { - loading.value = Event(false) - } - } - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/workers/ConfigFetchWorker.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/workers/ConfigFetchWorker.kt deleted file mode 100644 index c2b359aaf..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/workers/ConfigFetchWorker.kt +++ /dev/null @@ -1,58 +0,0 @@ -package nl.rijksoverheid.ctr.holder.workers - -import android.content.Context -import androidx.work.CoroutineWorker -import androidx.work.WorkManager -import androidx.work.WorkerParameters -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import nl.rijksoverheid.ctr.appconfig.models.ConfigResult -import nl.rijksoverheid.ctr.appconfig.usecases.CachedAppConfigUseCase -import nl.rijksoverheid.ctr.appconfig.usecases.ConfigResultUseCase -import nl.rijksoverheid.ctr.holder.models.HolderStep -import nl.rijksoverheid.ctr.holder.usecases.HolderFeatureFlagUseCase -import nl.rijksoverheid.ctr.shared.models.NetworkRequestResult - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -open class ConfigFetchWorker( - private val context: Context, - params: WorkerParameters, - private val cachedAppConfigUseCase: CachedAppConfigUseCase, - private val holderFeatureFlagUseCase: HolderFeatureFlagUseCase, - private val configResultUseCase: ConfigResultUseCase -) : CoroutineWorker(context, params) { - - override suspend fun doWork(): Result = withContext(Dispatchers.IO) { - val configResult = try { - configResultUseCase.fetch() - } catch (exception: Exception) { - ConfigResult.Error(NetworkRequestResult.Failed.ClientNetworkError(HolderStep.ConfigurationNetworkRequest)) - } - when (configResult) { - is ConfigResult.Error -> { - WorkManager.getInstance(context).cancelAllWork() - Result.failure() - } - is ConfigResult.Success -> { - val appDeactivated = cachedAppConfigUseCase.getCachedAppConfig().appDeactivated - val appInArchiveMode = holderFeatureFlagUseCase.isInArchiveMode() - if (appDeactivated || appInArchiveMode) { - WorkManager.getInstance(context).cancelAllWork() - Result.failure() - } else { - Result.success() - } - } - } - } - - companion object { - const val uniqueWorkNameTag = "fetch_config_worker" - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/workers/CredentialRefreshWorker.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/workers/CredentialRefreshWorker.kt deleted file mode 100644 index 2ebf0f15a..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/workers/CredentialRefreshWorker.kt +++ /dev/null @@ -1,56 +0,0 @@ -package nl.rijksoverheid.ctr.holder.workers - -import android.content.Context -import androidx.work.WorkerParameters -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import nl.rijksoverheid.ctr.appconfig.usecases.CachedAppConfigUseCase -import nl.rijksoverheid.ctr.appconfig.usecases.ConfigResultUseCase -import nl.rijksoverheid.ctr.holder.models.HolderFlow -import nl.rijksoverheid.ctr.holder.usecases.HolderFeatureFlagUseCase -import nl.rijksoverheid.ctr.persistence.database.DatabaseSyncerResult -import nl.rijksoverheid.ctr.persistence.database.HolderDatabaseSyncer - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -class CredentialRefreshWorker( - context: Context, - params: WorkerParameters, - configResultUseCase: ConfigResultUseCase, - cachedAppConfigUseCase: CachedAppConfigUseCase, - holderFeatureFlagUseCase: HolderFeatureFlagUseCase, - private val holderDatabaseSyncer: HolderDatabaseSyncer -) : ConfigFetchWorker(context, params, cachedAppConfigUseCase, holderFeatureFlagUseCase, configResultUseCase) { - - override suspend fun doWork(): Result = withContext(Dispatchers.IO) { - when (val configWorkResult = super.doWork()) { - Result.success() -> { - credentialsRefresh() - } - else -> configWorkResult - } - } - - private suspend fun credentialsRefresh(): Result { - return when (holderDatabaseSyncer.sync( - flow = HolderFlow.SyncGreenCards, - syncWithRemote = true - )) { - is DatabaseSyncerResult.Failed.Error -> Result.failure() - is DatabaseSyncerResult.Failed.NetworkError -> Result.retry() - is DatabaseSyncerResult.Failed.ServerError.FirstTime -> Result.retry() - is DatabaseSyncerResult.Failed.ServerError.MultipleTimes -> Result.failure() - is DatabaseSyncerResult.FuzzyMatchingError -> Result.success() - is DatabaseSyncerResult.Success -> Result.success() - } - } - - companion object { - const val uniqueWorkNameTag = "credentials_refresh_worker" - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/workers/HolderWorkerFactory.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/workers/HolderWorkerFactory.kt deleted file mode 100644 index b9c53220e..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/workers/HolderWorkerFactory.kt +++ /dev/null @@ -1,49 +0,0 @@ -package nl.rijksoverheid.ctr.holder.workers - -import android.content.Context -import androidx.work.ListenableWorker -import androidx.work.WorkerFactory -import androidx.work.WorkerParameters -import nl.rijksoverheid.ctr.appconfig.usecases.CachedAppConfigUseCase -import nl.rijksoverheid.ctr.appconfig.usecases.ConfigResultUseCase -import nl.rijksoverheid.ctr.holder.usecases.HolderFeatureFlagUseCase -import nl.rijksoverheid.ctr.persistence.database.HolderDatabaseSyncer - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -class HolderWorkerFactory( - private val configResultUseCase: ConfigResultUseCase, - private val cachedAppConfigUseCase: CachedAppConfigUseCase, - private val holderFeatureFlagUseCase: HolderFeatureFlagUseCase, - private val holderDatabaseSyncer: HolderDatabaseSyncer -) : WorkerFactory() { - override fun createWorker( - appContext: Context, - workerClassName: String, - workerParameters: WorkerParameters - ): ListenableWorker? { - return when (workerClassName) { - ConfigFetchWorker::class.java.name -> ConfigFetchWorker( - appContext, - workerParameters, - cachedAppConfigUseCase, - holderFeatureFlagUseCase, - configResultUseCase - ) - CredentialRefreshWorker::class.java.name -> CredentialRefreshWorker( - appContext, - workerParameters, - configResultUseCase, - cachedAppConfigUseCase, - holderFeatureFlagUseCase, - holderDatabaseSyncer - ) - else -> null - } - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/workers/WorkerManagerUtil.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/workers/WorkerManagerUtil.kt deleted file mode 100644 index 1ae9ef421..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/workers/WorkerManagerUtil.kt +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ - -package nl.rijksoverheid.ctr.holder.workers - -import android.content.Context -import androidx.work.Constraints -import androidx.work.ExistingPeriodicWorkPolicy -import androidx.work.NetworkType -import androidx.work.PeriodicWorkRequest -import androidx.work.PeriodicWorkRequestBuilder -import androidx.work.WorkManager -import java.util.concurrent.TimeUnit -import nl.rijksoverheid.ctr.holder.dashboard.util.GreenCardRefreshUtil -import nl.rijksoverheid.ctr.holder.dashboard.util.RefreshState -import nl.rijksoverheid.ctr.persistence.HolderCachedAppConfigUseCase -import nl.rijksoverheid.ctr.shared.models.Environment - -interface WorkerManagerUtil { - suspend fun scheduleRefreshCredentialsJob(): PeriodicWorkRequest? - fun cancelRefreshCredentialsJob(context: Context) -} - -class WorkerManagerUtilImpl( - private val context: Context, - private val greenCardRefreshUtil: GreenCardRefreshUtil, - private val appConfigUseCase: HolderCachedAppConfigUseCase, - private val environment: Environment = Environment.get(context) -) : WorkerManagerUtil { - - val acc: Boolean = environment == Environment.Acc - - // for testing, use minutes in acc builds - private val intervalUnit = if (acc) { - TimeUnit.MINUTES - } else { - TimeUnit.DAYS - } - - private fun interval(): Long = if (acc) { - 15 - } else { - appConfigUseCase.getCachedAppConfig().internationalQRRelevancyDays.toLong() - } - - override suspend fun scheduleRefreshCredentialsJob(): PeriodicWorkRequest? { - val refreshState = greenCardRefreshUtil.refreshState() - val appDeactivated = appConfigUseCase.getCachedAppConfig().appDeactivated - - if (refreshState is RefreshState.Refreshable && !appDeactivated) { - val credentialsRefreshInDays = refreshState.days - - val constraints = Constraints.Builder() - .setRequiredNetworkType(NetworkType.CONNECTED) - .setRequiresBatteryNotLow(true) - .build() - - val request = PeriodicWorkRequestBuilder( - repeatInterval = interval(), - repeatIntervalTimeUnit = intervalUnit) - .setInitialDelay(credentialsRefreshInDays, intervalUnit) - .setConstraints(constraints) - .build() - - WorkManager.getInstance(context) - .enqueueUniquePeriodicWork( - CredentialRefreshWorker.uniqueWorkNameTag, - ExistingPeriodicWorkPolicy.UPDATE, - request - ) - return request - } - return null - } - - override fun cancelRefreshCredentialsJob(context: Context) { - WorkManager.getInstance(context).cancelUniqueWork(CredentialRefreshWorker.uniqueWorkNameTag) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/YourEventExplanationFragment.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/YourEventExplanationFragment.kt deleted file mode 100644 index 2a3c58226..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/YourEventExplanationFragment.kt +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.your_events - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.TextView -import androidx.fragment.app.Fragment -import androidx.navigation.fragment.navArgs -import androidx.recyclerview.widget.DividerItemDecoration -import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView -import nl.rijksoverheid.ctr.design.widgets.HtmlTextViewWidget -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.databinding.FragmentYourEventExplanationBinding -import nl.rijksoverheid.ctr.holder.your_events.utils.InfoScreen - -class YourEventExplanationAdapter(private val dataSet: Array) : - RecyclerView.Adapter() { - - class ViewHolder(view: View) : RecyclerView.ViewHolder(view) { - val textView: TextView = view.findViewById(R.id.subheader) - val htmlTextViewWidget: HtmlTextViewWidget = view.findViewById(R.id.description) - } - - override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder { - val view = LayoutInflater.from(viewGroup.context) - .inflate(R.layout.your_event_explanation_item, viewGroup, false) - - return ViewHolder(view) - } - - override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) { - viewHolder.htmlTextViewWidget.setHtmlText( - htmlText = dataSet[position].description - ) - } - - override fun getItemCount() = dataSet.size -} - -class YourEventExplanationFragment : Fragment(R.layout.fragment_your_event_explanation) { - - private val args: YourEventExplanationFragmentArgs by navArgs() - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - val binding = FragmentYourEventExplanationBinding.bind(view) - - val adapter = YourEventExplanationAdapter( - dataSet = args.data - ) - - binding.scroll.adapter = adapter - val linearLayoutManager = LinearLayoutManager(requireContext()) - val dividerItemDecoration = DividerItemDecoration(requireContext(), linearLayoutManager.orientation) - binding.scroll.layoutManager = linearLayoutManager - if (args.data.size > 1) { - binding.scroll.addItemDecoration(dividerItemDecoration) - } - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/YourEventsFragment.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/YourEventsFragment.kt deleted file mode 100644 index f1c593c0a..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/YourEventsFragment.kt +++ /dev/null @@ -1,739 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.your_events - -import android.os.Bundle -import android.view.View -import androidx.activity.OnBackPressedCallback -import androidx.core.view.forEachIndexed -import androidx.navigation.fragment.navArgs -import nl.rijksoverheid.ctr.appconfig.usecases.CachedAppConfigUseCase -import nl.rijksoverheid.ctr.design.ext.formatDayMonthYear -import nl.rijksoverheid.ctr.design.ext.formatDayMonthYearTime -import nl.rijksoverheid.ctr.design.fragments.info.ButtonData -import nl.rijksoverheid.ctr.design.fragments.info.DescriptionData -import nl.rijksoverheid.ctr.design.fragments.info.InfoFragmentData -import nl.rijksoverheid.ctr.design.utils.DialogUtil -import nl.rijksoverheid.ctr.design.utils.InfoFragmentUtil -import nl.rijksoverheid.ctr.holder.BaseFragment -import nl.rijksoverheid.ctr.holder.HolderMainFragment -import nl.rijksoverheid.ctr.holder.MainNavDirections -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.databinding.FragmentYourEventsBinding -import nl.rijksoverheid.ctr.holder.fuzzy_matching.MatchingBlobIds -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEventNegativeTest -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEventPositiveTest -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEventRecovery -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEventVaccination -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteProtocol -import nl.rijksoverheid.ctr.holder.models.HolderFlow -import nl.rijksoverheid.ctr.holder.models.HolderStep -import nl.rijksoverheid.ctr.holder.your_events.models.ConflictingEventResult -import nl.rijksoverheid.ctr.holder.your_events.models.YourEventsEndState -import nl.rijksoverheid.ctr.holder.your_events.models.YourEventsEndStateWithCustomTitle -import nl.rijksoverheid.ctr.holder.your_events.utils.InfoScreenUtil -import nl.rijksoverheid.ctr.holder.your_events.utils.RemoteEventUtil -import nl.rijksoverheid.ctr.holder.your_events.utils.RemoteProtocol3Util -import nl.rijksoverheid.ctr.holder.your_events.utils.YourEventsEndStateUtil -import nl.rijksoverheid.ctr.holder.your_events.utils.YourEventsFragmentUtil -import nl.rijksoverheid.ctr.holder.your_events.widgets.YourEventWidget -import nl.rijksoverheid.ctr.holder.your_events.widgets.YourEventWidgetUtil -import nl.rijksoverheid.ctr.persistence.database.DatabaseSyncerResult -import nl.rijksoverheid.ctr.persistence.database.entities.OriginType -import nl.rijksoverheid.ctr.shared.ext.capitalize -import nl.rijksoverheid.ctr.shared.ext.findNavControllerSafety -import nl.rijksoverheid.ctr.shared.ext.navigateSafety -import nl.rijksoverheid.ctr.shared.livedata.EventObserver -import nl.rijksoverheid.ctr.shared.models.AppErrorResult -import nl.rijksoverheid.ctr.shared.models.BlockedEventException -import nl.rijksoverheid.ctr.shared.models.ErrorResultFragmentData -import nl.rijksoverheid.ctr.shared.models.Flow -import org.json.JSONObject -import org.koin.android.ext.android.inject -import org.koin.androidx.viewmodel.ext.android.viewModel - -class YourEventsFragment : BaseFragment(R.layout.fragment_your_events) { - - private val args: YourEventsFragmentArgs by navArgs() - - private val infoScreenUtil: InfoScreenUtil by inject() - private val dialogUtil: DialogUtil by inject() - private val infoFragmentUtil: InfoFragmentUtil by inject() - - private val remoteProtocol3Util: RemoteProtocol3Util by inject() - private val remoteEventUtil: RemoteEventUtil by inject() - private val yourEventsFragmentUtil: YourEventsFragmentUtil by inject() - private val yourEventWidgetUtil: YourEventWidgetUtil by inject() - private val yourEventsEndStateUtil: YourEventsEndStateUtil by inject() - - private val cachedAppConfigUseCase: CachedAppConfigUseCase by inject() - - private val yourEventsViewModel: YourEventsViewModel by viewModel() - - override fun onButtonClickWithRetryTitle(): Int { - return R.string.dialog_retry - } - - override fun onButtonClickWithRetryAction() { - findNavControllerSafety()?.popBackStack() - } - - override fun getFlow(): Flow { - return args.flow - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - val binding = FragmentYourEventsBinding.bind(view) - - presentHeader( - binding = binding - ) - - presentEvents( - binding = binding - ) - - presentFooter( - binding = binding - ) - - handleButton( - binding = binding - ) - - blockBackButton() - - yourEventsViewModel.loading.observe(viewLifecycleOwner, EventObserver { - (parentFragment?.parentFragment as HolderMainFragment).presentLoading(it) - binding.bottom.setButtonEnabled(!it) - binding.eventsGroup.forEachIndexed { index, _ -> - val eventGroup = binding.eventsGroup.getChildAt(index) as YourEventWidget - eventGroup.setButtonsEnabled(!it) - } - }) - - yourEventsViewModel.yourEventsResult.observe( - viewLifecycleOwner, - EventObserver { databaseSyncerResult -> - val fragmentType = args.type - - when (databaseSyncerResult) { - is DatabaseSyncerResult.Success -> { - if (getFlow() == HolderFlow.Migration) { - infoFragmentUtil.presentFullScreen( - currentFragment = this, - toolbarTitle = "", - data = InfoFragmentData.TitleDescriptionWithButton( - title = getString(R.string.holder_migrationFlow_migrationSuccessful_title), - descriptionData = DescriptionData( - htmlText = R.string.holder_migrationFlow_migrationSuccessful_message, - htmlLinksEnabled = true - ), - primaryButtonData = ButtonData.NavigationButton( - text = getString(R.string.back_to_overview), - navigationActionId = MainNavDirections.actionMyOverview().actionId - ) - ), - hideNavigationIcon = true - ) - } else { - handleEndState( - endState = yourEventsEndStateUtil.getEndState( - context = requireContext(), - hints = databaseSyncerResult.hints, - blockedEvents = databaseSyncerResult.blockedEvents, - newEvents = when (fragmentType) { - is YourEventsFragmentType.DCC -> fragmentType.remoteEvent.events - ?: listOf() - is YourEventsFragmentType.RemoteProtocol3Type -> fragmentType.remoteEvents.keys.toList() - .map { it.events ?: listOf() }.flatten() - } - ) - ) - } - } - is DatabaseSyncerResult.Failed -> { - presentError( - errorResult = databaseSyncerResult.errorResult - ) - } - is DatabaseSyncerResult.FuzzyMatchingError -> { - navigateSafety( - YourEventsFragmentDirections.actionFuzzyMatching( - MatchingBlobIds(databaseSyncerResult.matchingBlobIds) - ) - ) - } - } - }) - - yourEventsViewModel.conflictingEventsResult.observe( - viewLifecycleOwner, - EventObserver { - when (it) { - ConflictingEventResult.Existing -> { - infoFragmentUtil.presentFullScreen( - currentFragment = this, - toolbarTitle = args.toolbarTitle, - data = InfoFragmentData.TitleDescriptionWithButton( - title = getString(R.string.holder_listRemoteEvents_endStateDuplicate_title), - descriptionData = DescriptionData( - htmlText = R.string.holder_listRemoteEvents_endStateDuplicate_message - ), - primaryButtonData = ButtonData.NavigationButton( - text = getString(R.string.general_toMyOverview), - navigationActionId = R.id.action_my_overview - ) - ), - hideNavigationIcon = true - ) - } - ConflictingEventResult.Holder -> replaceCertificateDialog(getEventsFromType()) - ConflictingEventResult.None -> yourEventsViewModel.saveRemoteProtocolEvents( - getFlow(), getEventsFromType(), false - ) - } - } - ) - } - - private fun getEventsFromType() = when (val type = args.type) { - is YourEventsFragmentType.DCC -> type.getRemoteEvents() - is YourEventsFragmentType.RemoteProtocol3Type -> type.remoteEvents - } - - private fun handleEndState(endState: YourEventsEndState) { - when (endState) { - is YourEventsEndState.BlockedEvent -> { - val helpdeskPhoneNumber = - cachedAppConfigUseCase.getCachedAppConfig().contactInfo.phoneNumber - infoFragmentUtil.presentFullScreen( - currentFragment = this, - toolbarTitle = getString(R.string.holder_listRemoteEvents_endStateCantCreateCertificate_title), - data = InfoFragmentData.TitleDescriptionWithButton( - title = getString(R.string.holder_listRemoteEvents_endStateNoValidCertificate_title), - descriptionData = DescriptionData( - htmlTextString = getString( - R.string.holder_listRemoteEvents_endStateNoValidCertificate_body, - helpdeskPhoneNumber, - helpdeskPhoneNumber, - errorCodeStringFactory.get( - getFlow(), - listOf( - AppErrorResult( - HolderStep.GetCredentialsNetworkRequest, - BlockedEventException() - ) - ) - ) - ), - htmlLinksEnabled = true - ), - primaryButtonData = ButtonData.NavigationButton( - text = getString(R.string.general_toMyOverview), - navigationActionId = R.id.action_my_overview - ) - ) - ) - } - is YourEventsEndState.Hints -> { - infoFragmentUtil.presentFullScreen( - currentFragment = this, - toolbarTitle = getString(R.string.certificate_created_toolbar_title), - data = InfoFragmentData.TitleDescriptionWithButton( - title = getString(R.string.certificate_created_toolbar_title), - descriptionData = DescriptionData( - htmlTextString = endState.localisedHints.joinToString("

"), - htmlLinksEnabled = true - ), - primaryButtonData = ButtonData.NavigationButton( - text = getString(R.string.general_toMyOverview), - navigationActionId = R.id.action_my_overview - ) - ), - hideNavigationIcon = true - ) - } - is YourEventsEndState.WeCouldntMakeACertificateError -> { - val errorCode = errorCodeStringFactory.get( - flow = getFlow(), - errorResults = listOf( - AppErrorResult(HolderStep.GetCredentialsNetworkRequest, endState.exception) - ) - ) - presentError( - data = ErrorResultFragmentData( - title = getString(R.string.holder_listRemoteEvents_endStateCantCreateCertificate_title), - description = getString( - R.string.holder_listRemoteEvents_endStateCantCreateCertificate_message, - yourEventsEndStateUtil.getErrorStateSubstring( - requireContext(), - getFlow() - ), - errorCode - ), - buttonTitle = getString(R.string.general_toMyOverview), - buttonAction = ErrorResultFragmentData.ButtonAction.Destination(R.id.action_my_overview) - ) - ) - } - is YourEventsEndStateWithCustomTitle -> { - infoFragmentUtil.presentFullScreen( - currentFragment = this, - toolbarTitle = if (endState is YourEventsEndStateWithCustomTitle.RecoveryTooOld || - endState is YourEventsEndStateWithCustomTitle.NoRecoveryButDosisCorrection || - endState is YourEventsEndStateWithCustomTitle.RecoveryAndDosisCorrection - ) { - getString(R.string.your_positive_test_toolbar_title) - } else { - getString(R.string.certificate_created_toolbar_title) - }, - data = InfoFragmentData.TitleDescriptionWithButton( - title = getString(endState.title), - descriptionData = DescriptionData( - htmlTextString = getString(endState.description), - htmlLinksEnabled = true - ), - primaryButtonData = ButtonData.NavigationButton( - text = getString(R.string.general_toMyOverview), - navigationActionId = R.id.action_my_overview - ) - ), - hideNavigationIcon = true - ) - } - else -> { - navigateSafety(YourEventsFragmentDirections.actionMyOverview()) - } - } - } - - private fun replaceCertificateDialog( - remoteEvents: Map - ) { - dialogUtil.presentDialog( - context = requireContext(), - title = R.string.your_events_replace_dialog_title, - message = getString(R.string.your_events_replace_dialog_message), - positiveButtonText = R.string.your_events_replace_dialog_positive_button, - positiveButtonCallback = { - yourEventsViewModel.saveRemoteProtocolEvents( - flow = getFlow(), - remoteProtocols = remoteEvents, - removePreviousEvents = true - ) - }, - negativeButtonText = R.string.your_events_replace_dialog_negative_button, - negativeButtonCallback = { - findNavControllerSafety()?.popBackStack() - } - ) - } - - private fun presentEvents(binding: FragmentYourEventsBinding) { - when (val type = args.type) { - is YourEventsFragmentType.RemoteProtocol3Type -> presentEvents( - type.remoteEvents, - binding - ) - is YourEventsFragmentType.DCC -> presentEvents( - type.getRemoteEvents(), - binding, - isDccEvent = true - ) - } - } - - private fun presentEvents( - remoteEvents: Map, - binding: FragmentYourEventsBinding, - isDccEvent: Boolean = false - ) { - val protocols = remoteEvents.map { it.key } - - val groupedEvents = remoteProtocol3Util.groupEvents(protocols) - - groupedEvents.forEach { protocolGroupedEvent -> - val holder = protocolGroupedEvent.value.firstOrNull()?.holder - val providerIdentifiers = - protocolGroupedEvent.value.map { it.providerIdentifier } - .map { - yourEventsFragmentUtil.getProviderName( - providers = cachedAppConfigUseCase.getCachedAppConfig().providers, - providerIdentifier = it - ) - } - - val allSameEvents = protocolGroupedEvent.value.map { it.remoteEvent } - val allEventsInformation = protocolGroupedEvent.value.map { - RemoteEventInformation(it.providerIdentifier, holder, it.remoteEvent) - } - remoteEventUtil.removeDuplicateEvents(allSameEvents).forEach { remoteEvent -> - when (remoteEvent) { - is RemoteEventVaccination -> { - presentVaccinationEvent( - binding = binding, - providerIdentifiers = providerIdentifiers.toSet() - .joinToString(" ${getString(R.string.your_events_and)} "), - vaccinationDate = yourEventsFragmentUtil.getVaccinationDate(remoteEvent.vaccination?.date), - fullName = yourEventsFragmentUtil.getFullName(holder), - birthDate = yourEventsFragmentUtil.getBirthDate(holder), - currentEvent = remoteEvent, - allEventsInformation = allEventsInformation, - isDccEvent = isDccEvent || providerIdentifiers.any { it.contains("dcc") } - ) - } - is RemoteEventNegativeTest -> { - presentNegativeTestEvent( - binding = binding, - providerIdentifiers = providerIdentifiers.toSet() - .joinToString(" ${getString(R.string.your_events_and)} "), - fullName = yourEventsFragmentUtil.getFullName(holder), - birthDate = yourEventsFragmentUtil.getBirthDate(holder), - event = remoteEvent - ) - } - is RemoteEventPositiveTest -> { - presentPositiveTestEvent( - binding = binding, - providerIdentifiers = providerIdentifiers.toSet() - .joinToString(" ${getString(R.string.your_events_and)} "), - fullName = yourEventsFragmentUtil.getFullName(holder), - birthDate = yourEventsFragmentUtil.getBirthDate(holder), - event = remoteEvent - ) - } - is RemoteEventRecovery -> { - presentRecoveryEvent( - binding = binding, - providerIdentifiers = providerIdentifiers.toSet() - .joinToString(" ${getString(R.string.your_events_and)} "), - fullName = yourEventsFragmentUtil.getFullName(holder), - birthDate = yourEventsFragmentUtil.getBirthDate(holder), - event = remoteEvent - ) - } - } - } - } - } - - private fun presentVaccinationEvent( - binding: FragmentYourEventsBinding, - providerIdentifiers: String, - vaccinationDate: String, - fullName: String, - birthDate: String, - currentEvent: RemoteEventVaccination, - allEventsInformation: List, - isDccEvent: Boolean - ) { - val type = args.type - val infoScreen = infoScreenUtil.getForVaccination( - event = currentEvent, - fullName = fullName, - birthDate = birthDate, - providerIdentifier = allEventsInformation.first().providerIdentifier, - europeanCredential = if (type is YourEventsFragmentType.DCC) { - JSONObject(type.eventGroupJsonData.decodeToString()).getString("credential") - .toByteArray() - } else { - null - } - ) - - val eventWidget = YourEventWidget(requireContext()).apply { - setContent( - title = yourEventWidgetUtil.getVaccinationEventTitle( - context, - isDccEvent, - currentEvent - ), - subtitle = yourEventWidgetUtil.getVaccinationEventSubtitle( - context, - isDccEvent, - providerIdentifiers, - vaccinationDate, - fullName, - birthDate - ), - infoClickListener = { - navigateSafety( - YourEventsFragmentDirections.actionShowExplanation( - toolbarTitle = infoScreen.title, - data = allEventsInformation.map { - val vaccinationEvent = - it.remoteEvent as RemoteEventVaccination - infoScreenUtil.getForVaccination( - event = vaccinationEvent, - fullName = fullName, - birthDate = birthDate, - providerIdentifier = yourEventsFragmentUtil.getProviderName( - providers = cachedAppConfigUseCase.getCachedAppConfig().providers, - providerIdentifier = it.providerIdentifier - ), - europeanCredential = if (type is YourEventsFragmentType.DCC) { - JSONObject(type.eventGroupJsonData.decodeToString()).getString( - "credential" - ).toByteArray() - } else { - null - } - ) - }.toTypedArray() - ) - ) - } - ) - } - binding.eventsGroup.addView(eventWidget) - } - - private fun presentNegativeTestEvent( - binding: FragmentYourEventsBinding, - providerIdentifiers: String, - fullName: String, - birthDate: String, - event: RemoteEventNegativeTest - ) { - val type = args.type - - val testDate = - event.negativeTest?.sampleDate?.formatDayMonthYearTime(requireContext()) ?: "" - - val infoScreen = infoScreenUtil.getForNegativeTest( - event = event, - fullName = fullName, - testDate = testDate, - birthDate = birthDate, - europeanCredential = if (type is YourEventsFragmentType.DCC) { - JSONObject(type.eventGroupJsonData.decodeToString()).getString("credential") - .toByteArray() - } else { - null - } - ) - - val eventWidget = YourEventWidget(requireContext()).apply { - setContent( - title = getString(R.string.your_negative_test_results_row_title), - subtitle = getString( - R.string.your_negative_test_3_0_results_row_subtitle, - testDate, - fullName, - birthDate, - providerIdentifiers - ), - infoClickListener = { - navigateSafety( - YourEventsFragmentDirections.actionShowExplanation( - toolbarTitle = infoScreen.title, - data = arrayOf(infoScreen) - ) - ) - } - ) - } - binding.eventsGroup.addView(eventWidget) - } - - private fun presentPositiveTestEvent( - binding: FragmentYourEventsBinding, - providerIdentifiers: String, - fullName: String, - birthDate: String, - event: RemoteEventPositiveTest - ) { - val testDate = - event.positiveTest?.sampleDate?.formatDayMonthYearTime(requireContext()) ?: "" - - val infoScreen = infoScreenUtil.getForPositiveTest( - event = event, - testDate = testDate, - fullName = fullName, - birthDate = birthDate - ) - - val eventWidget = YourEventWidget(requireContext()).apply { - setContent( - title = getString(R.string.positive_test_title), - subtitle = getString( - R.string.your_negative_test_3_0_results_row_subtitle, - testDate, - fullName, - birthDate, - providerIdentifiers - ), - infoClickListener = { - navigateSafety( - YourEventsFragmentDirections.actionShowExplanation( - toolbarTitle = infoScreen.title, - data = arrayOf(infoScreen) - ) - ) - } - ) - } - binding.eventsGroup.addView(eventWidget) - } - - private fun presentRecoveryEvent( - binding: FragmentYourEventsBinding, - providerIdentifiers: String, - fullName: String, - birthDate: String, - event: RemoteEventRecovery - ) { - val type = args.type - val testDate = event.recovery?.sampleDate?.formatDayMonthYear() ?: "" - - val infoScreen = infoScreenUtil.getForRecovery( - event = event, - fullName = fullName, - testDate = testDate, - birthDate = birthDate, - europeanCredential = if (type is YourEventsFragmentType.DCC) { - JSONObject(type.eventGroupJsonData.decodeToString()).getString("credential") - .toByteArray() - } else { - null - } - ) - - val eventWidget = YourEventWidget(requireContext()).apply { - setContent( - title = getString(R.string.general_recoverycertificate).capitalize(), - subtitle = getString( - R.string.your_negative_test_3_0_results_row_subtitle, - testDate, - fullName, - birthDate, - providerIdentifiers - ), - infoClickListener = { - navigateSafety( - YourEventsFragmentDirections.actionShowExplanation( - toolbarTitle = infoScreen.title, - data = arrayOf(infoScreen) - ) - ) - } - ) - } - binding.eventsGroup.addView(eventWidget) - } - - private fun handleButton(binding: FragmentYourEventsBinding) { - binding.bottom.setButtonClick { - yourEventsViewModel.checkForConflictingEvents( - remoteProtocols = getEventsFromType() - ) - } - binding.bottom.setButtonText( - getString( - if (getFlow() == HolderFlow.Migration) { - R.string.holder_migrationFlow_scannedDetailsOverview_transferButton - } else { - R.string.my_overview_add_qr_button - } - ) - ) - } - - private fun presentHeader(binding: FragmentYourEventsBinding) { - binding.description.setText(yourEventsFragmentUtil.getHeaderCopy(args.type, args.flow)) - } - - private fun presentFooter(binding: FragmentYourEventsBinding) { - binding.somethingWrongButton.run { - visibility = if ( - args.type is YourEventsFragmentType.DCC || args.flow is HolderFlow.Migration - ) View.GONE else View.VISIBLE - setOnClickListener { - val type = args.type - infoFragmentUtil.presentAsBottomSheet( - childFragmentManager, InfoFragmentData.TitleDescription( - title = getString(R.string.holder_listRemoteEvents_somethingWrong_title), - descriptionData = DescriptionData( - htmlText = if (type is YourEventsFragmentType.RemoteProtocol3Type) { - val origins = type.remoteEvents.keys - .flatMap { it.events ?: emptyList() } - .map { remoteEventUtil.getOriginType(it) } - when { - origins.all { it == OriginType.Vaccination } -> { - if (getFlow() == HolderFlow.VaccinationAndPositiveTest) { - R.string.holder_listRemoteEvents_somethingWrong_vaccinationAndPositiveTest_body - } else { - R.string.holder_listRemoteEvents_somethingWrong_vaccination_body - } - } - origins.all { it == OriginType.Recovery } -> { - R.string.dialog_negative_test_result_something_wrong_description - } - origins.contains(OriginType.Vaccination) && - origins.contains(OriginType.Recovery) -> { - R.string.holder_listRemoteEvents_somethingWrong_vaccinationAndPositiveTest_body - } - else -> R.string.dialog_negative_test_result_something_wrong_description - } - } else { - R.string.dialog_negative_test_result_something_wrong_description - }, - htmlLinksEnabled = true - ) - ) - ) - } - } - } - - private fun blockBackButton() { - // Catch back button to show modal instead - requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, object : - OnBackPressedCallback(true) { - override fun handleOnBackPressed() { - if (isAdded) { - if (getFlow() == HolderFlow.Migration) { - dialogUtil.presentDialog( - context = requireContext(), - title = R.string.holder_migrationFlow_goBack_dialog_title, - message = getString(R.string.holder_migrationFlow_goBack_dialog_message), - positiveButtonText = R.string.holder_migrationFlow_goBack_dialog_yesButton, - positiveButtonCallback = { - findNavControllerSafety()?.popBackStack() - }, - negativeButtonText = R.string.holder_migrationFlow_goBack_dialog_noButton - ) - } else { - dialogUtil.presentDialog( - context = requireContext(), - title = R.string.your_events_block_back_dialog_title, - message = getString( - yourEventsFragmentUtil.getCancelDialogDescription( - type = args.type - ) - ), - positiveButtonText = R.string.your_events_block_back_dialog_positive_button, - positiveButtonCallback = { - findNavControllerSafety()?.popBackStack() - }, - negativeButtonText = R.string.your_events_block_back_dialog_negative_button - ) - } - } - } - }) - } - - override fun onDestroyView() { - super.onDestroyView() - (parentFragment?.parentFragment as? HolderMainFragment)?.presentLoading(false) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/YourEventsFragmentType.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/YourEventsFragmentType.kt deleted file mode 100644 index 89d3600e5..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/YourEventsFragmentType.kt +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.your_events - -import android.os.Parcelable -import kotlinx.parcelize.Parcelize -import nl.rijksoverheid.ctr.holder.get_events.models.EventProvider -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteProtocol -import nl.rijksoverheid.ctr.persistence.database.entities.OriginType - -sealed class YourEventsFragmentType : Parcelable { - - @Parcelize - data class RemoteProtocol3Type( - val remoteEvents: Map, - val eventProviders: List = emptyList() - ) : YourEventsFragmentType() - - @Parcelize - data class DCC( - val remoteEvent: RemoteProtocol, - val eventGroupJsonData: ByteArray, - val originType: OriginType - ) : YourEventsFragmentType(), Parcelable { - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false - - other as DCC - - if (remoteEvent != other.remoteEvent) return false - if (!eventGroupJsonData.contentEquals(other.eventGroupJsonData)) return false - if (originType != other.originType) return false - - return true - } - - override fun hashCode(): Int { - var result = remoteEvent.hashCode() - result = 31 * result + eventGroupJsonData.contentHashCode() - result = 31 * result + originType.hashCode() - return result - } - - fun getRemoteEvents(): Map = - mapOf(remoteEvent to eventGroupJsonData) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/YourEventsViewModel.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/YourEventsViewModel.kt deleted file mode 100644 index b509e9602..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/YourEventsViewModel.kt +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.your_events - -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import kotlinx.coroutines.launch -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEvent -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteProtocol -import nl.rijksoverheid.ctr.holder.models.HolderStep -import nl.rijksoverheid.ctr.holder.your_events.models.ConflictingEventResult -import nl.rijksoverheid.ctr.holder.your_events.usecases.SaveEventsUseCase -import nl.rijksoverheid.ctr.holder.your_events.usecases.SaveEventsUseCaseImpl -import nl.rijksoverheid.ctr.persistence.database.DatabaseSyncerResult -import nl.rijksoverheid.ctr.persistence.database.HolderDatabaseSyncer -import nl.rijksoverheid.ctr.persistence.database.usecases.DraftEventUseCase -import nl.rijksoverheid.ctr.shared.livedata.Event -import nl.rijksoverheid.ctr.shared.models.AppErrorResult -import nl.rijksoverheid.ctr.shared.models.Flow - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -abstract class YourEventsViewModel : ViewModel() { - val loading: LiveData> = MutableLiveData() - val yourEventsResult: LiveData> = MutableLiveData() - val conflictingEventsResult: LiveData> = MutableLiveData() - - abstract fun saveRemoteProtocolEvents( - flow: Flow, - remoteProtocols: Map, - removePreviousEvents: Boolean - ) - - abstract fun checkForConflictingEvents(remoteProtocols: Map) -} - -data class RemoteEventInformation( - val providerIdentifier: String, - val holder: RemoteProtocol.Holder?, - val remoteEvent: RemoteEvent -) - -class YourEventsViewModelImpl( - private val saveEventsUseCase: SaveEventsUseCase, - private val holderDatabaseSyncer: HolderDatabaseSyncer, - private val draftEventUseCase: DraftEventUseCase -) : YourEventsViewModel() { - - override fun checkForConflictingEvents(remoteProtocols: Map) { - (loading as MutableLiveData).value = Event(true) - viewModelScope.launch { - draftEventUseCase.remove() - try { - val conflictingEvents = - saveEventsUseCase.remoteProtocols3AreConflicting(remoteProtocols) - - (conflictingEventsResult as MutableLiveData).postValue(Event(conflictingEvents)) - } catch (e: Exception) { - (yourEventsResult as MutableLiveData).value = Event( - DatabaseSyncerResult.Failed.Error(AppErrorResult(HolderStep.StoringEvents, e)) - ) - } finally { - loading.value = Event(false) - } - } - } - - override fun saveRemoteProtocolEvents( - flow: Flow, - remoteProtocols: Map, - removePreviousEvents: Boolean - ) { - (loading as MutableLiveData).value = Event(true) - viewModelScope.launch { - try { - // Save the events in the database - val result = saveEventsUseCase.saveRemoteProtocols3( - remoteProtocols = remoteProtocols, - removePreviousEvents = removePreviousEvents, - flow = flow - ) - - when (result) { - is SaveEventsUseCaseImpl.SaveEventResult.Success -> { - // Send all events to database and create green cards, origins and credentials - val databaseSyncerResult = holderDatabaseSyncer.sync( - flow = flow, - newEvents = remoteProtocols.keys.flatMap { it.events ?: listOf() } - ) - - (yourEventsResult as MutableLiveData).value = Event( - databaseSyncerResult - ) - } - is SaveEventsUseCaseImpl.SaveEventResult.Failed -> { - (yourEventsResult as MutableLiveData).value = - Event(DatabaseSyncerResult.Failed.Error(result.errorResult)) - } - } - } catch (e: Exception) { - (yourEventsResult as MutableLiveData).value = Event( - DatabaseSyncerResult.Failed.Error(AppErrorResult(HolderStep.StoringEvents, e)) - ) - } finally { - loading.value = Event(false) - } - } - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/models/ConflictingEventResult.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/models/ConflictingEventResult.kt deleted file mode 100644 index b528eba12..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/models/ConflictingEventResult.kt +++ /dev/null @@ -1,7 +0,0 @@ -package nl.rijksoverheid.ctr.holder.your_events.models - -sealed class ConflictingEventResult { - object Holder : ConflictingEventResult() - object Existing : ConflictingEventResult() - object None : ConflictingEventResult() -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/models/RemoteGreenCards.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/models/RemoteGreenCards.kt deleted file mode 100644 index 06482f5aa..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/models/RemoteGreenCards.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.your_events.models - -import com.squareup.moshi.JsonClass -import java.time.OffsetDateTime -import nl.rijksoverheid.ctr.persistence.database.entities.OriginType - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -@JsonClass(generateAdapter = true) -data class RemoteGreenCards( - val euGreencards: List?, - val blobExpireDates: List?, - val context: Context? = null, - val hints: List? = listOf() -) { - - data class EuGreenCard( - val origins: List, - val credential: String - ) - - data class Origin( - val type: OriginType, - val eventTime: OffsetDateTime, - val expirationTime: OffsetDateTime, - val validFrom: OffsetDateTime, - val doseNumber: Int?, - val hints: List? = listOf() - ) - - data class BlobExpiry( - val id: Int, - val expiry: OffsetDateTime, - val reason: String = "" - ) - - data class Context(val matchingBlobIds: List>) -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/models/RemoteNonce.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/models/RemoteNonce.kt deleted file mode 100644 index 47b912acc..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/models/RemoteNonce.kt +++ /dev/null @@ -1,17 +0,0 @@ -package nl.rijksoverheid.ctr.holder.your_events.models - -import com.squareup.moshi.Json -import com.squareup.moshi.JsonClass - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -@JsonClass(generateAdapter = true) -data class RemoteNonce( - val nonce: String, - @Json(name = "stoken") val sToken: String -) diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/models/RemotePrepareIssue.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/models/RemotePrepareIssue.kt deleted file mode 100644 index 7b652dab5..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/models/RemotePrepareIssue.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.your_events.models - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -data class RemotePrepareIssue( - val stoken: String, - val prepareIssueMessage: ByteArray -) { - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false - - other as RemotePrepareIssue - - if (stoken != other.stoken) return false - if (!prepareIssueMessage.contentEquals(other.prepareIssueMessage)) return false - - return true - } - - override fun hashCode(): Int { - var result = stoken.hashCode() - result = 31 * result + prepareIssueMessage.contentHashCode() - return result - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/models/YourEventsEndState.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/models/YourEventsEndState.kt deleted file mode 100644 index 417c118c1..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/models/YourEventsEndState.kt +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.your_events.models - -import androidx.annotation.StringRes -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.shared.models.WeCouldntCreateCertificateException - -sealed class YourEventsEndState { - object None : YourEventsEndState() - object BlockedEvent : YourEventsEndState() - data class Hints(val localisedHints: List) : YourEventsEndState() - // endstate showing an error code - data class WeCouldntMakeACertificateError(val exception: WeCouldntCreateCertificateException) : YourEventsEndState() -} - -// additional endstates with custom title and description which cannot be generated by the hints system yet -sealed class YourEventsEndStateWithCustomTitle(@StringRes val title: Int, @StringRes val description: Int) : YourEventsEndState() { - object InternationalQROnly : YourEventsEndStateWithCustomTitle( - R.string.holder_listRemoteEvents_endStateInternationalQROnly_title, - R.string.holder_listRemoteEvents_endStateInternationalQROnly_message) - object VaccinationsAndRecovery : YourEventsEndStateWithCustomTitle( - R.string.holder_listRemoteEvents_endStateVaccinationsAndRecovery_title, - R.string.holder_listRemoteEvents_endStateVaccinationsAndRecovery_message) - object InternationalVaccinationAndRecovery : YourEventsEndStateWithCustomTitle( - R.string.holder_listRemoteEvents_endStateInternationalVaccinationAndRecovery_title, - R.string.holder_listRemoteEvents_endStateInternationalVaccinationAndRecovery_message) - object RecoveryOnly : YourEventsEndStateWithCustomTitle( - R.string.holder_listRemoteEvents_endStateRecoveryOnly_title, - R.string.holder_listRemoteEvents_endStateRecoveryOnly_message) - object NoRecoveryButDosisCorrection : YourEventsEndStateWithCustomTitle( - R.string.holder_listRemoteEvents_endStateNoRecoveryButDosisCorrection_title, - R.string.holder_listRemoteEvents_endStateNoRecoveryButDosisCorrection_message) - object RecoveryTooOld : YourEventsEndStateWithCustomTitle( - R.string.holder_listRemoteEvents_endStateRecoveryTooOld_title, - R.string.holder_listRemoteEvents_endStateRecoveryTooOld_message) - object RecoveryAndDosisCorrection : YourEventsEndStateWithCustomTitle( - R.string.holder_listRemoteEvents_endStateRecoveryAndDosisCorrection_title, - R.string.holder_listRemoteEvents_endStateRecoveryAndDosisCorrection_message) - object WeCouldntMakeACertificate : YourEventsEndStateWithCustomTitle( - R.string.holder_listRemoteEvents_endStateCantCreateCertificate_title, - R.string.holder_listRemoteEvents_endStateCantCreateCertificate_message) -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/usecases/SaveEventsUseCase.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/usecases/SaveEventsUseCase.kt deleted file mode 100644 index 49f0fbf92..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/usecases/SaveEventsUseCase.kt +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.your_events.usecases - -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEvent -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteProtocol -import nl.rijksoverheid.ctr.holder.get_events.utils.ScopeUtil -import nl.rijksoverheid.ctr.holder.models.HolderFlow -import nl.rijksoverheid.ctr.holder.models.HolderStep -import nl.rijksoverheid.ctr.holder.your_events.models.ConflictingEventResult -import nl.rijksoverheid.ctr.holder.your_events.utils.RemoteEventHolderUtil -import nl.rijksoverheid.ctr.holder.your_events.utils.RemoteEventUtil -import nl.rijksoverheid.ctr.holder.your_events.utils.RemoteProtocol3Util -import nl.rijksoverheid.ctr.persistence.database.HolderDatabase -import nl.rijksoverheid.ctr.persistence.database.entities.EventGroupEntity -import nl.rijksoverheid.ctr.shared.models.AppErrorResult -import nl.rijksoverheid.ctr.shared.models.ErrorResult -import nl.rijksoverheid.ctr.shared.models.Flow - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -interface SaveEventsUseCase { - - suspend fun saveRemoteProtocols3( - remoteProtocols: Map, - removePreviousEvents: Boolean, - flow: Flow - ): SaveEventsUseCaseImpl.SaveEventResult - - suspend fun remoteProtocols3AreConflicting(remoteProtocols: Map): ConflictingEventResult -} - -class SaveEventsUseCaseImpl( - private val holderDatabase: HolderDatabase, - private val remoteEventHolderUtil: RemoteEventHolderUtil, - private val scopeUtil: ScopeUtil, - private val remoteEventUtil: RemoteEventUtil, - private val remoteProtocol3Util: RemoteProtocol3Util -) : SaveEventsUseCase { - - private suspend fun remoteEventExistsAlready(remoteEvents: List): Boolean { - val remoteEventUniques = remoteEvents.mapNotNull { it.unique } - val storedEventIdentifiers = holderDatabase.eventGroupDao().getAll().map { it.providerIdentifier } - return storedEventIdentifiers.any { identifier -> - remoteEventUniques.any { remoteEventUtil.isDccEvent(identifier) && identifier.contains(it) } - } - } - - override suspend fun remoteProtocols3AreConflicting(remoteProtocols: Map): ConflictingEventResult { - if (remoteEventExistsAlready(remoteProtocols.map { it.key }.flatMap { it.events ?: emptyList() })) { - return ConflictingEventResult.Existing - } - - val storedEventHolders = holderDatabase.eventGroupDao().getAll() - .mapNotNull { remoteEventHolderUtil.holder(it.jsonData, it.providerIdentifier) } - .distinct() - val incomingEventHolders = remoteProtocols.mapNotNull { it.key.holder }.distinct() - - return if (remoteEventHolderUtil.conflicting(storedEventHolders, incomingEventHolders)) { - ConflictingEventResult.Holder - } else { - ConflictingEventResult.None - } - } - - override suspend fun saveRemoteProtocols3( - remoteProtocols: Map, - removePreviousEvents: Boolean, - flow: Flow - ): SaveEventResult { - try { - if (removePreviousEvents) { - holderDatabase.eventGroupDao().deleteAll() - } - - val entities = remoteProtocols.map { - val remoteProtocol = it.key - val remoteEvents = remoteProtocol.events ?: listOf() - val originType = remoteEventUtil.getOriginType(remoteEvents.first()) - EventGroupEntity( - walletId = 1, - providerIdentifier = remoteProtocol3Util.getProviderIdentifier(remoteProtocol), - type = originType, - jsonData = it.value, - scope = scopeUtil.getScopeForOriginType( - originType = originType, - getPositiveTestWithVaccination = flow == HolderFlow.VaccinationAndPositiveTest - ), - expiryDate = null, - draft = true - ) - } - - // Save entity in database - holderDatabase.eventGroupDao().insertAll(entities) - } catch (e: Exception) { - return SaveEventResult.Failed( - errorResult = AppErrorResult( - step = HolderStep.StoringEvents, - e = e - ) - ) - } - return SaveEventResult.Success - } - - sealed class SaveEventResult { - object Success : SaveEventResult() - data class Failed(val errorResult: ErrorResult) : SaveEventResult() - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/CreateInfoLineUtil.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/CreateInfoLineUtil.kt deleted file mode 100644 index 70c7283ff..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/CreateInfoLineUtil.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2023 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -package nl.rijksoverheid.ctr.holder.your_events.utils - -import androidx.core.text.HtmlCompat - -abstract class CreateInfoLineUtil { - fun createdLine( - name: String, - nameAnswer: String, - isOptional: Boolean = false - ): String { - val sanitizedName = HtmlCompat.fromHtml(name, HtmlCompat.FROM_HTML_MODE_LEGACY).toString() - val sanitizedAnswer = - HtmlCompat.fromHtml(nameAnswer, HtmlCompat.FROM_HTML_MODE_LEGACY).toString() - return if (isOptional && nameAnswer.isEmpty()) "" else "$sanitizedName $sanitizedAnswer
" - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/EventGroupEntityUtil.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/EventGroupEntityUtil.kt deleted file mode 100644 index b8811c3b4..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/EventGroupEntityUtil.kt +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.your_events.utils - -import nl.rijksoverheid.ctr.persistence.HolderCachedAppConfigUseCase - -interface EventGroupEntityUtil { - fun getProviderName(providerIdentifier: String): String -} - -class EventGroupEntityUtilImpl( - private val cachedAppConfigUseCase: HolderCachedAppConfigUseCase -) : EventGroupEntityUtil { - - override fun getProviderName(providerIdentifier: String): String { - // Some provider identifiers have a unique appended to it, the first part is the actual provider identifier - val providerIdentifierWithoutUnique = providerIdentifier.split("_").first() - - return cachedAppConfigUseCase.getCachedAppConfig().providerIdentifiers - .firstOrNull { it.code == providerIdentifierWithoutUnique } - ?.name - ?: providerIdentifier - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/InfoScreenUtil.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/InfoScreenUtil.kt deleted file mode 100644 index fe4d6d3ae..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/InfoScreenUtil.kt +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ -package nl.rijksoverheid.ctr.holder.your_events.utils - -import android.os.Parcelable -import kotlinx.parcelize.Parcelize -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEventNegativeTest -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEventPositiveTest -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEventRecovery -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEventVaccination - -interface InfoScreenUtil { - - fun getForNegativeTest( - event: RemoteEventNegativeTest, - fullName: String, - testDate: String, - birthDate: String, - europeanCredential: ByteArray?, - addExplanation: Boolean = true - ): InfoScreen - - fun getForVaccination( - event: RemoteEventVaccination, - fullName: String, - birthDate: String, - providerIdentifier: String, - europeanCredential: ByteArray?, - addExplanation: Boolean = true - ): InfoScreen - - fun getForPositiveTest( - event: RemoteEventPositiveTest, - testDate: String, - fullName: String, - birthDate: String - ): InfoScreen - - fun getForRecovery( - event: RemoteEventRecovery, - testDate: String, - fullName: String, - birthDate: String, - europeanCredential: ByteArray?, - addExplanation: Boolean = true - ): InfoScreen -} - -class InfoScreenUtilImpl( - private val vaccinationInfoScreenUtil: VaccinationInfoScreenUtil, - private val testInfoScreenUtil: TestInfoScreenUtil, - private val recoveryInfoScreenUtil: RecoveryInfoScreenUtil -) : InfoScreenUtil { - - override fun getForNegativeTest( - event: RemoteEventNegativeTest, - fullName: String, - testDate: String, - birthDate: String, - europeanCredential: ByteArray?, - addExplanation: Boolean - ) = testInfoScreenUtil.getForNegativeTest(event, fullName, testDate, birthDate, europeanCredential, addExplanation) - - override fun getForVaccination( - event: RemoteEventVaccination, - fullName: String, - birthDate: String, - providerIdentifier: String, - europeanCredential: ByteArray?, - addExplanation: Boolean - ) = vaccinationInfoScreenUtil.getForVaccination(event, fullName, birthDate, providerIdentifier, europeanCredential, addExplanation) - - override fun getForPositiveTest( - event: RemoteEventPositiveTest, - testDate: String, - fullName: String, - birthDate: String - ) = testInfoScreenUtil.getForPositiveTest(event, testDate, fullName, birthDate) - - override fun getForRecovery( - event: RemoteEventRecovery, - testDate: String, - fullName: String, - birthDate: String, - europeanCredential: ByteArray?, - addExplanation: Boolean - ) = recoveryInfoScreenUtil.getForRecovery(event, testDate, fullName, birthDate, europeanCredential, addExplanation) -} - -@Parcelize -data class InfoScreen( - val title: String, - val description: String -) : Parcelable diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/RecoveryInfoScreenUtil.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/RecoveryInfoScreenUtil.kt deleted file mode 100644 index 0f8ef8d11..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/RecoveryInfoScreenUtil.kt +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (c) 2023 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ -package nl.rijksoverheid.ctr.holder.your_events.utils - -import android.content.res.Resources -import android.text.TextUtils -import java.util.Locale -import nl.rijksoverheid.ctr.design.ext.formatDayMonthYear -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEventRecovery -import nl.rijksoverheid.ctr.holder.paper_proof.utils.PaperProofUtil -import nl.rijksoverheid.ctr.holder.utils.CountryUtil - -interface RecoveryInfoScreenUtil { - - fun getForRecovery( - event: RemoteEventRecovery, - testDate: String, - fullName: String, - birthDate: String, - europeanCredential: ByteArray?, - addExplanation: Boolean = true - ): InfoScreen -} - -class RecoveryInfoScreenUtilImpl( - val resources: Resources, - private val paperProofUtil: PaperProofUtil, - private val countryUtil: CountryUtil -) : CreateInfoLineUtil(), RecoveryInfoScreenUtil { - - override fun getForRecovery( - event: RemoteEventRecovery, - testDate: String, - fullName: String, - birthDate: String, - europeanCredential: ByteArray?, - addExplanation: Boolean - ): InfoScreen { - - val validFromDate = event.recovery?.validFrom?.formatDayMonthYear() ?: "" - val validUntilDate = event.recovery?.validUntil?.formatDayMonthYear() ?: "" - - val isPaperCertificate = europeanCredential != null - - val title = - if (europeanCredential != null) resources.getString(R.string.your_vaccination_explanation_toolbar_title) else resources.getString( - R.string.your_test_result_explanation_toolbar_title - ) - val header = if (europeanCredential != null) { - resources.getString(R.string.paper_proof_event_explanation_header) - } else { - resources.getString(R.string.recovery_explanation_description_header) - } - - val countryValue = event.recovery?.country - val country = when { - countryValue.isNullOrEmpty() -> "NL" - else -> countryValue - } - - val description = (TextUtils.concat( - header, - "

", - createdLine( - resources.getString(R.string.recovery_explanation_description_name), - fullName - ), - createdLine( - resources.getString(R.string.recovery_explanation_description_birth_date), - birthDate, - isOptional = true - ), - "
", - createdLine( - resources.getString(R.string.recovery_explanation_description_test_date), - testDate - ), - createdLine( - resources.getString(R.string.holder_event_about_test_countrytestedin), - countryUtil.getCountryForInfoScreen(Locale.getDefault().language, country), - isOptional = true - ), - if (europeanCredential != null) { - val issuerAnswer = paperProofUtil.getIssuer(europeanCredential) - createdLine( - resources.getString(R.string.holder_dcc_issuer), - if (issuerAnswer == "Ministry of Health Welfare and Sport") { - resources.getString(R.string.qr_explanation_certificate_issuer) - } else { - issuerAnswer - }, - isOptional = true - ) - } else { - "" - }, - "
", - createdLine( - resources.getString(R.string.recovery_explanation_description_valid_from), - validFromDate - ), - createdLine( - resources.getString(R.string.recovery_explanation_description_valid_until), - validUntilDate - ), - "
", - createdLine( - resources.getString( - if (isPaperCertificate) { - R.string.holder_dcc_test_identifier - } else { - R.string.your_test_result_explanation_description_unique_identifier - } - ), - event.unique - ), - if (europeanCredential != null && addExplanation) { - paperProofUtil.getInfoScreenFooterText(europeanCredential) - } else { - "" - } - ) as String) - - return InfoScreen( - title = title, - description = description - ) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/RemoteEventHolderUtil.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/RemoteEventHolderUtil.kt deleted file mode 100644 index dd0284c0f..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/RemoteEventHolderUtil.kt +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.your_events.utils - -import android.util.Base64 -import com.squareup.moshi.JsonClass -import com.squareup.moshi.Moshi -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteProtocol -import nl.rijksoverheid.ctr.holder.paper_proof.usecases.GetEventsFromPaperProofQrUseCase -import nl.rijksoverheid.ctr.shared.models.JSON -import org.json.JSONObject - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -interface RemoteEventHolderUtil { - fun holder(data: ByteArray, providerIdentifier: String): RemoteProtocol.Holder? - fun conflicting( - storedEventHolders: List, - incomingEventHolders: List - ): Boolean -} - -class RemoteEventHolderUtilImpl( - private val moshi: Moshi, - private val getEventsFromPaperProofQrUseCase: GetEventsFromPaperProofQrUseCase, - private val remoteEventUtil: RemoteEventUtil, - private val yourEventsFragmentUtil: YourEventsFragmentUtil -) : RemoteEventHolderUtil { - override fun holder(data: ByteArray, providerIdentifier: String): RemoteProtocol.Holder? { - val remoteEvent = - if (remoteEventUtil.isDccEvent(providerIdentifier)) { - val qr = JSONObject(String(data)).optString("credential") - getEventsFromPaperProofQrUseCase.get(qr) - } else { - val payload = - moshi.adapter(SignedResponse::class.java).fromJson(String(data))!!.payload - val decodedPayload = String(Base64.decode(payload, Base64.DEFAULT)) - moshi.adapter(RemoteProtocol::class.java).fromJson(decodedPayload)!! - } - return remoteEvent.holder - } - - /** - * Compare the holder of the currently stored events with the holder of the new importing events - * If the birth date or month are different, then the holders are conflicting and - * we should keep only one of them. - */ - override fun conflicting( - storedEventHolders: List, - incomingEventHolders: List - ): Boolean { - storedEventHolders.forEach { storedEventHolder -> - val storedBirthdate = yourEventsFragmentUtil.getBirthDate(storedEventHolder) - incomingEventHolders.forEach { incomingEventHolder -> - val incomingBirthdate = yourEventsFragmentUtil.getBirthDate(incomingEventHolder) - return birthDateIsNotMatching(storedBirthdate, incomingBirthdate) - } - } - return false - } - - private fun birthDateIsNotMatching(stored: String, incoming: String): Boolean { - if (stored == incoming) { - return false - } - - val storedBirthdayParts = stored.split(" ") - val incomingBirthdayParts = incoming.split(" ") - - val storedBirthDay: String? = storedBirthdayParts.getOrNull(0) - val storedBirthMonth: String? = storedBirthdayParts.getOrNull(1) - val incomingBirthDay: String? = incomingBirthdayParts.getOrNull(0) - val incomingBirthMonth: String? = incomingBirthdayParts.getOrNull(1) - - return storedBirthDay != incomingBirthDay || storedBirthMonth != incomingBirthMonth - } -} - -@JsonClass(generateAdapter = true) -data class SignedResponse(val signature: String, val payload: String) : JSON() diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/RemoteEventStringUtil.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/RemoteEventStringUtil.kt deleted file mode 100644 index 65adfc81a..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/RemoteEventStringUtil.kt +++ /dev/null @@ -1,34 +0,0 @@ -package nl.rijksoverheid.ctr.holder.your_events.utils - -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEvent -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEventNegativeTest -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEventPositiveTest -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEventRecovery -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEventVaccination -import nl.rijksoverheid.ctr.shared.ext.capitalize - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -interface RemoteEventStringUtil { - fun remoteEventTitle(remoteEventClass: Class): String -} - -class RemoteEventStringUtilImpl( - private val getString: (Int) -> String -) : RemoteEventStringUtil { - override fun remoteEventTitle(remoteEventClass: Class): String { - return when (remoteEventClass) { - RemoteEventVaccination::class.java -> getString(R.string.general_vaccination) - RemoteEventNegativeTest::class.java -> getString(R.string.general_negativeTest) - RemoteEventPositiveTest::class.java -> getString(R.string.general_positiveTest) - RemoteEventRecovery::class.java -> getString(R.string.general_recoverycertificate) - else -> "" - }.capitalize() - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/RemoteEventUtil.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/RemoteEventUtil.kt deleted file mode 100644 index d46967518..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/RemoteEventUtil.kt +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.your_events.utils - -import android.util.Base64 -import com.squareup.moshi.Moshi -import java.time.LocalDate -import java.time.OffsetDateTime -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteConfigProviders -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEvent -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEventNegativeTest -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEventPositiveTest -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEventRecovery -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEventVaccination -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteProtocol -import nl.rijksoverheid.ctr.persistence.database.entities.EventGroupEntity -import nl.rijksoverheid.ctr.persistence.database.entities.OriginType -import nl.rijksoverheid.ctr.shared.ext.getStringOrNull -import org.json.JSONException -import org.json.JSONObject - -interface RemoteEventUtil { - fun isDccEvent(providerIdentifier: String): Boolean - fun getHolderFromDcc(dcc: JSONObject): RemoteProtocol.Holder - fun removeDuplicateEvents(remoteEvents: List): List - fun getRemoteEventFromDcc(dcc: JSONObject): RemoteEvent - fun getRemoteVaccinationFromDcc(dcc: JSONObject): RemoteEventVaccination? - fun getRemoteRecoveryFromDcc(dcc: JSONObject): RemoteEventRecovery? - fun getRemoteTestFromDcc(dcc: JSONObject): RemoteEventNegativeTest? - fun getRemoteProtocol3FromNonDcc(eventGroupEntity: EventGroupEntity): RemoteProtocol? - fun getOriginType(remoteEvent: RemoteEvent): OriginType -} - -class RemoteEventUtilImpl( - private val moshi: Moshi -) : RemoteEventUtil { - - /** - * Only remove duplicate events for vaccination events - */ - override fun removeDuplicateEvents(remoteEvents: List): List { - return if (remoteEvents.all { it is RemoteEventVaccination }) { - return remoteEvents.filterIsInstance().distinct() - } else { - remoteEvents - } - } - - override fun isDccEvent(providerIdentifier: String): Boolean { - return providerIdentifier.startsWith(RemoteConfigProviders.EventProvider.PROVIDER_IDENTIFIER_DCC) - } - - @Throws(NullPointerException::class) - override fun getHolderFromDcc(dcc: JSONObject): RemoteProtocol.Holder { - val fullName = dcc.optJSONObject("nam") ?: throw NullPointerException("can't parse name") - return RemoteProtocol.Holder( - infix = "", - firstName = fullName.getStringOrNull("gn"), - lastName = fullName.getStringOrNull("fn"), - birthDate = dcc.getStringOrNull("dob") - ) - } - - @Throws(JSONException::class) - override fun getRemoteEventFromDcc(dcc: JSONObject): RemoteEvent { - return getRemoteVaccinationFromDcc(dcc) ?: getRemoteRecoveryFromDcc(dcc) ?: getRemoteTestFromDcc(dcc) - ?: throw JSONException("can't parse event type") - } - - override fun getRemoteVaccinationFromDcc(dcc: JSONObject): RemoteEventVaccination? { - return getEventByType(dcc, "v")?.let { - RemoteEventVaccination( - type = "vaccination", - unique = it.getStringOrNull("ci"), - vaccination = RemoteEventVaccination.Vaccination( - doseNumber = it.getStringOrNull("dn"), - totalDoses = it.getStringOrNull("sd"), - date = try { LocalDate.parse(it.getStringOrNull("dt")?.take(10)) } catch (e: Exception) { null }, - country = it.getStringOrNull("co"), - type = it.getStringOrNull("vp"), - brand = it.getStringOrNull("mp"), - manufacturer = it.getStringOrNull("ma"), - completedByMedicalStatement = null, - hpkCode = null, - completedByPersonalStatement = null, - completionReason = null - ) - ) - } - } - - override fun getRemoteRecoveryFromDcc(dcc: JSONObject): RemoteEventRecovery? { - return getEventByType(dcc, "r")?.let { - RemoteEventRecovery( - type = "recovery", - unique = it.getStringOrNull("ci") ?: "", - isSpecimen = false, - recovery = RemoteEventRecovery.Recovery( - sampleDate = try { LocalDate.parse(it.getStringOrNull("fr")?.take(10)) } catch (e: Exception) { null }, - validFrom = try { LocalDate.parse(it.getStringOrNull("df")?.take(10)) } catch (e: Exception) { null }, - validUntil = try { LocalDate.parse(it.getStringOrNull("du")?.take(10)) } catch (e: Exception) { null }, - country = it.getStringOrNull("co") - ) - ) - } - } - - override fun getRemoteTestFromDcc(dcc: JSONObject): RemoteEventNegativeTest? { - return getEventByType(dcc, "t")?.let { jsonObject -> - RemoteEventNegativeTest( - type = "test", - unique = jsonObject.getStringOrNull("ci"), - isSpecimen = false, - negativeTest = RemoteEventNegativeTest.NegativeTest( - sampleDate = OffsetDateTime.parse(jsonObject.getStringOrNull("sc")), - negativeResult = jsonObject.getStringOrNull("tr") == "260415000", - facility = jsonObject.getStringOrNull("tc"), - type = jsonObject.getStringOrNull("tt"), - name = jsonObject.getStringOrNull("nm") - .takeIf { it?.isNotEmpty() ?: false }, - country = jsonObject.getStringOrNull("co") - .takeIf { it?.isNotEmpty() ?: false }, - manufacturer = jsonObject.getStringOrNull("ma") - .takeIf { it?.isNotEmpty() ?: false } - ) - ) - } - } - - override fun getRemoteProtocol3FromNonDcc(eventGroupEntity: EventGroupEntity): RemoteProtocol? { - val payload = moshi.adapter(SignedResponse::class.java) - .fromJson(String(eventGroupEntity.jsonData))?.payload - val decodedPayload = String(Base64.decode(payload, Base64.DEFAULT)) - return moshi.adapter(RemoteProtocol::class.java).fromJson(decodedPayload) - } - - private fun getEventByType(dcc: JSONObject, key: String) = try { - dcc.getJSONArray(key).optJSONObject(0) - } catch (exception: JSONException) { - null - } - - override fun getOriginType(remoteEvent: RemoteEvent): OriginType { - return when (remoteEvent) { - is RemoteEventVaccination -> OriginType.Vaccination - is RemoteEventRecovery -> OriginType.Recovery - is RemoteEventPositiveTest -> OriginType.Recovery - is RemoteEventNegativeTest -> OriginType.Test - else -> error("remote event not supported as origin type") - } - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/RemoteProtocol3Util.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/RemoteProtocol3Util.kt deleted file mode 100644 index 71d5e61a2..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/RemoteProtocol3Util.kt +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.your_events.utils - -import java.lang.StringBuilder -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEvent -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteProtocol -import nl.rijksoverheid.ctr.holder.your_events.RemoteEventInformation - -interface RemoteProtocol3Util { - fun areGGDEvents(providerIdentifier: String): Boolean - fun areRIVMEvents(providerIdentifier: String): Boolean - fun getProviderIdentifier(remoteProtocol: RemoteProtocol): String - fun groupEvents(remoteEvents: List): Map> -} - -class RemoteProtocol3UtilImpl : RemoteProtocol3Util { - - override fun getProviderIdentifier(remoteProtocol: RemoteProtocol): String { - return if (!areGGDEvents(remoteProtocol.providerIdentifier) && !areRIVMEvents(remoteProtocol.providerIdentifier)) { - val providerIdentifierBuilder = StringBuilder() - providerIdentifierBuilder.append(remoteProtocol.providerIdentifier) - providerIdentifierBuilder.append("_") - remoteProtocol.events?.forEach { remoteEvent -> - run { - providerIdentifierBuilder.append(remoteEvent.unique) - } - } - providerIdentifierBuilder.toString() - } else { - remoteProtocol.providerIdentifier - } - } - - /** - * Group all events that have the same: - * - the same date - * AND - * hpkcodes are not null and match - * OR - * manifacturer are not null and match - * It's possible that your vaccination is known at both the GGD or RIVM - * so this merges the two - */ - override fun groupEvents(remoteEvents: List): Map> { - val sameEventsGrouped = mutableMapOf>() - - remoteEvents.sortedBy { it.providerIdentifier }.forEach { - val provider = it.providerIdentifier - val holder = it.holder - it.events?.forEach { remoteEvent -> - if (sameEventsGrouped.contains(remoteEvent)) { - sameEventsGrouped[remoteEvent]?.add(RemoteEventInformation(provider, holder, remoteEvent)) - } else { - sameEventsGrouped[remoteEvent] = mutableListOf(RemoteEventInformation(provider, holder, remoteEvent)) - } - } - } - - // Sort events descending by date - return sameEventsGrouped.entries - .sortedByDescending { it.key.getDate() } - .associate { it.key to it.value } - } - - override fun areGGDEvents(providerIdentifier: String): Boolean { - return providerIdentifier.lowercase() == "ggd" - } - - override fun areRIVMEvents(providerIdentifier: String): Boolean { - return providerIdentifier.lowercase() == "rivm" - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/TestInfoScreenUtil.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/TestInfoScreenUtil.kt deleted file mode 100644 index 71ebdca1f..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/TestInfoScreenUtil.kt +++ /dev/null @@ -1,269 +0,0 @@ -/* - * Copyright (c) 2023 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -package nl.rijksoverheid.ctr.holder.your_events.utils - -import android.content.res.Resources -import android.text.TextUtils -import java.util.Locale -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEventNegativeTest -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEventPositiveTest -import nl.rijksoverheid.ctr.holder.paper_proof.utils.PaperProofUtil -import nl.rijksoverheid.ctr.holder.utils.CountryUtil -import nl.rijksoverheid.ctr.persistence.HolderCachedAppConfigUseCase - -interface TestInfoScreenUtil { - - fun getForNegativeTest( - event: RemoteEventNegativeTest, - fullName: String, - testDate: String, - birthDate: String, - europeanCredential: ByteArray?, - addExplanation: Boolean = true - ): InfoScreen - - fun getForPositiveTest( - event: RemoteEventPositiveTest, - testDate: String, - fullName: String, - birthDate: String - ): InfoScreen -} - -class TestInfoScreenUtilImpl( - private val resources: Resources, - private val paperProofUtil: PaperProofUtil, - private val countryUtil: CountryUtil, - cachedAppConfigUseCase: HolderCachedAppConfigUseCase -) : CreateInfoLineUtil(), TestInfoScreenUtil { - - private val holderConfig = cachedAppConfigUseCase.getCachedAppConfig() - - override fun getForNegativeTest( - event: RemoteEventNegativeTest, - fullName: String, - testDate: String, - birthDate: String, - europeanCredential: ByteArray?, - addExplanation: Boolean - ): InfoScreen { - val testType = holderConfig.euTestTypes.firstOrNull { - it.code == event.negativeTest?.type - }?.name ?: event.negativeTest?.type ?: "" - - val isRat = event.negativeTest?.type == "LP217198-3" - - val testName = if (isRat) { - holderConfig.euTestNames.firstOrNull { - it.code == event.negativeTest?.manufacturer - }?.name ?: "" - } else { - event.negativeTest?.name ?: "" - } - - val testLocation = event.negativeTest?.facility ?: "" - - val testManufacturer = - holderConfig.euTestManufacturers.firstOrNull { - it.code == event.negativeTest?.manufacturer - }?.name ?: event.negativeTest?.manufacturer ?: "" - - val unique = event.unique ?: "" - - val country = getCountry(event.negativeTest?.country) - - val isPaperCertificate = europeanCredential != null - - val title = - if (europeanCredential != null) resources.getString(R.string.your_vaccination_explanation_toolbar_title) else resources.getString( - R.string.your_test_result_explanation_toolbar_title - ) - val header = if (isPaperCertificate) { - resources.getString(R.string.paper_proof_event_explanation_header) - } else { - resources.getString(R.string.your_test_result_explanation_description_header) - } - - val description = (TextUtils.concat( - header, - "

", - createdLine( - resources.getString(R.string.your_test_result_explanation_description_name), - fullName - ), - createdLine( - resources.getString(R.string.your_test_result_explanation_description_date_of_birth), - birthDate, - isOptional = true - ), - "
", - createdLine( - resources.getString(R.string.your_test_result_explanation_description_test_type), - testType, - isOptional = true - ), - createdLine( - resources.getString(R.string.your_test_result_explanation_description_test_name), - testName, - isOptional = true - ), - createdLine( - resources.getString(R.string.your_test_result_explanation_description_test_date), - testDate, - isOptional = true - ), - createdLine( - resources.getString(R.string.your_test_result_explanation_description_test_result), - resources.getString(R.string.your_test_result_explanation_negative_test_result), - isOptional = true - ), - createdLine( - resources.getString(R.string.your_test_result_explanation_description_test_manufacturer), - testManufacturer, - isOptional = true - ), - createdLine( - resources.getString(R.string.your_test_result_explanation_description_test_location), - testLocation, - isOptional = true - ), - createdLine( - resources.getString(R.string.holder_event_about_test_countrytestedin), - countryUtil.getCountryForInfoScreen(Locale.getDefault().language, country), - isOptional = true - ), - if (europeanCredential != null) { - val issuerAnswer = paperProofUtil.getIssuer(europeanCredential) - createdLine( - resources.getString(R.string.holder_dcc_issuer), - if (issuerAnswer == "Ministry of Health Welfare and Sport") { - resources.getString(R.string.qr_explanation_certificate_issuer) - } else { - issuerAnswer - }, - isOptional = true - ) - } else { - "" - }, - "
", - createdLine( - resources.getString( - if (isPaperCertificate) { - R.string.holder_dcc_test_identifier - } else { - R.string.your_test_result_explanation_description_unique_identifier - } - ), - unique - ), - if (europeanCredential != null && addExplanation) { - paperProofUtil.getInfoScreenFooterText(europeanCredential) - } else { - "" - } - ) as String) - - return InfoScreen( - title = title, - description = description - ) - } - - private fun getCountry(country: String?) = when { - country.isNullOrEmpty() -> "NL" - else -> country - } - - override fun getForPositiveTest( - event: RemoteEventPositiveTest, - testDate: String, - fullName: String, - birthDate: String - ): InfoScreen { - - val testType = holderConfig.euTestTypes.firstOrNull { - it.code == event.positiveTest?.type - }?.name ?: event.positiveTest?.type ?: "" - - val testName = event.positiveTest?.name ?: "" - - val testLocation = event.positiveTest?.facility ?: "" - - val testManufacturer = - holderConfig.euTestManufacturers.firstOrNull { - it.code == event.positiveTest?.manufacturer - }?.name ?: event.positiveTest?.manufacturer ?: "" - - val unique = event.unique ?: "" - - val country = getCountry(event.positiveTest?.country) - - val title = resources.getString(R.string.your_test_result_explanation_toolbar_title) - val description = (TextUtils.concat( - resources.getString(R.string.your_test_result_explanation_description_header), - "

", - createdLine( - resources.getString(R.string.your_test_result_explanation_description_name), - fullName - ), - createdLine( - resources.getString(R.string.your_test_result_explanation_description_date_of_birth), - birthDate, - isOptional = true - ), - "
", - createdLine( - resources.getString(R.string.your_test_result_explanation_description_test_type), - testType, - isOptional = true - ), - createdLine( - resources.getString(R.string.your_test_result_explanation_description_test_name), - testName, - isOptional = true - ), - createdLine( - resources.getString(R.string.your_test_result_explanation_description_test_date), - testDate, - isOptional = true - ), - createdLine( - resources.getString(R.string.your_test_result_explanation_description_test_result), - resources.getString(R.string.your_test_result_explanation_positive_test_result), - isOptional = true - ), - createdLine( - resources.getString(R.string.your_test_result_explanation_description_test_manufacturer), - testManufacturer, - isOptional = true - ), - createdLine( - resources.getString(R.string.your_test_result_explanation_description_test_location), - testLocation, - isOptional = true - ), - createdLine( - resources.getString(R.string.holder_event_about_test_countrytestedin), - countryUtil.getCountryForInfoScreen(Locale.getDefault().language, country), - isOptional = true - ), - "
", - createdLine( - resources.getString(R.string.your_test_result_explanation_description_unique_identifier), - unique - ) - ) as String) - - return InfoScreen( - title = title, - description = description - ) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/VaccinationInfoScreenUtil.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/VaccinationInfoScreenUtil.kt deleted file mode 100644 index e01b7c37d..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/VaccinationInfoScreenUtil.kt +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright (c) 2023 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.your_events.utils - -import android.content.res.Resources -import android.text.TextUtils -import java.util.Locale -import nl.rijksoverheid.ctr.appconfig.api.model.AppConfig -import nl.rijksoverheid.ctr.design.ext.formatDayMonthYear -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEventVaccination -import nl.rijksoverheid.ctr.holder.paper_proof.utils.PaperProofUtil -import nl.rijksoverheid.ctr.holder.qrcodes.utils.LastVaccinationDoseUtil -import nl.rijksoverheid.ctr.holder.utils.CountryUtil -import nl.rijksoverheid.ctr.persistence.HolderCachedAppConfigUseCase - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -interface VaccinationInfoScreenUtil { - - fun getForVaccination( - event: RemoteEventVaccination, - fullName: String, - birthDate: String, - providerIdentifier: String, - europeanCredential: ByteArray?, - addExplanation: Boolean = true - ): InfoScreen -} - -class VaccinationInfoScreenUtilImpl( - private val lastVaccinationDoseUtil: LastVaccinationDoseUtil, - private val resources: Resources, - private val countryUtil: CountryUtil, - private val paperProofUtil: PaperProofUtil, - cachedAppConfigUseCase: HolderCachedAppConfigUseCase -) : CreateInfoLineUtil(), VaccinationInfoScreenUtil { - - private val holderConfig = cachedAppConfigUseCase.getCachedAppConfig() - - override fun getForVaccination( - event: RemoteEventVaccination, - fullName: String, - birthDate: String, - providerIdentifier: String, - europeanCredential: ByteArray?, - addExplanation: Boolean - ): InfoScreen { - val title = - if (europeanCredential != null) resources.getString(R.string.your_vaccination_explanation_toolbar_title) else resources.getString( - R.string.your_test_result_explanation_toolbar_title - ) - - val name = resources.getString(R.string.your_vaccination_explanation_name) - - val birthDateQuestion = - resources.getString(R.string.your_vaccination_explanation_birthday) - - val disease = resources.getString(R.string.your_vaccination_explanation_covid_19) - val diseaseAnswer = - resources.getString(R.string.your_vaccination_explanation_covid_19_answer) - - val hpkCode = holderConfig.hpkCodes.firstOrNull { it.code == event.vaccination?.hpkCode } - - val vaccine = resources.getString(R.string.your_vaccination_explanation_vaccine) - val vaccineAnswer = getVaccineAnswer(hpkCode, event) - - val vaccineDisplayName = - resources.getString(R.string.holder_event_aboutVaccination_productName) - val vaccineDisplayNameAnswer = hpkCode?.displayName ?: "" - - val vaccineType = resources.getString(R.string.your_vaccination_explanation_vaccine_type) - val vaccineTypeAnswer = getVaccineTypeAnswer(hpkCode, event) - - val producer = resources.getString(R.string.your_vaccination_explanation_producer) - val producerAnswer = getProducerAnswer(hpkCode, event) - - val doses = resources.getString(R.string.your_vaccination_explanation_doses) - val dosesAnswer = getDosesAnswer(event, event.vaccination) - - val lastDose = resources.getString(R.string.your_vaccination_explanation_last_dose) - val lastDoseAnswer = lastVaccinationDoseUtil.getIsLastDoseAnswer(event) - - val vaccinationDate = - resources.getString(R.string.your_vaccination_explanation_vaccination_date) - val vaccinationDateAnswer = event.vaccination?.date?.formatDayMonthYear() ?: "" - - val fullCountryName = if (event.vaccination?.country != null) { - countryUtil.getCountryForInfoScreen( - Locale.getDefault().language, - event.vaccination.country - ) - } else { - "" - } - - val vaccinationCountry = - resources.getString(R.string.your_vaccination_explanation_vaccination_country) - - val uniqueCode = resources.getString(R.string.your_vaccination_explanation_unique_code) - val uniqueCodeAnswer = event.unique ?: "" - - val header = if (europeanCredential != null || providerIdentifier.contains("dcc")) { - resources.getString(R.string.paper_proof_event_explanation_header) - } else { - resources.getString(R.string.your_vaccination_explanation_header, providerIdentifier) - } - - return InfoScreen( - title = title, - description = (TextUtils.concat( - header, - "

", - createdLine(name, fullName), - createdLine(birthDateQuestion, birthDate, isOptional = true), - "
", - createdLine(disease, diseaseAnswer), - createdLine(vaccine, vaccineAnswer), - createdLine(vaccineDisplayName, vaccineDisplayNameAnswer, isOptional = true), - createdLine(vaccineType, vaccineTypeAnswer, isOptional = true), - createdLine(producer, producerAnswer, isOptional = true), - createdLine(doses, dosesAnswer, isOptional = true), - createdLine(lastDose, lastDoseAnswer, isOptional = true), - createdLine(vaccinationDate, vaccinationDateAnswer, isOptional = true), - createdLine(vaccinationCountry, fullCountryName, isOptional = true), - if (europeanCredential != null) { - val issuerAnswer = paperProofUtil.getIssuer(europeanCredential) - createdLine( - resources.getString(R.string.holder_dcc_issuer), - if (issuerAnswer == "Ministry of Health Welfare and Sport") { - resources.getString(R.string.qr_explanation_certificate_issuer) - } else { - issuerAnswer - }, - isOptional = true - ) - } else { - "" - }, - "
", - createdLine(uniqueCode, uniqueCodeAnswer), - if (europeanCredential != null && addExplanation) { - paperProofUtil.getInfoScreenFooterText(europeanCredential) - } else { - "" - } - ) as String) - ) - } - - private fun getDosesAnswer( - event: RemoteEventVaccination, - vaccination: RemoteEventVaccination.Vaccination? - ) = if (event.vaccination?.doseNumber != null && vaccination?.totalDoses != null) { - resources.getString( - R.string.your_vaccination_explanation_doses_answer, - vaccination.doseNumber, - vaccination.totalDoses - ) - } else "" - - private fun getProducerAnswer( - hpkCode: AppConfig.HpkCode?, - event: RemoteEventVaccination - ) = - (holderConfig.euManufacturers.firstOrNull { it.code == event.vaccination?.manufacturer }?.name - ?: holderConfig.euManufacturers.firstOrNull { it.code == hpkCode?.ma }?.name - ?: event.vaccination?.manufacturer - ?: "") - - private fun getVaccineTypeAnswer( - hpkCode: AppConfig.HpkCode?, - event: RemoteEventVaccination - ) = (holderConfig.euVaccinations.firstOrNull { it.code == event.vaccination?.type }?.name - ?: holderConfig.euVaccinations.firstOrNull { it.code == hpkCode?.vp }?.name - ?: event.vaccination?.type - ?: "") - - private fun getVaccineAnswer( - hpkCode: AppConfig.HpkCode?, - event: RemoteEventVaccination - ): String { - val hpkCodeName = hpkCode?.name ?: "" - val brand = - holderConfig.euBrands.firstOrNull { it.code == event.vaccination?.brand }?.name - ?: holderConfig.euBrands.firstOrNull { it.code == hpkCode?.mp }?.name - ?: event.vaccination?.brand - ?: "" - return when { - hpkCodeName.isNotEmpty() -> hpkCodeName - brand.isNotEmpty() -> brand - else -> "" - } - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/YourEventsEndStateUtil.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/YourEventsEndStateUtil.kt deleted file mode 100644 index 8d1fda39a..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/YourEventsEndStateUtil.kt +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.your_events.utils - -import android.content.Context -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEvent -import nl.rijksoverheid.ctr.holder.models.HolderFlow -import nl.rijksoverheid.ctr.holder.utils.StringUtil -import nl.rijksoverheid.ctr.holder.your_events.models.YourEventsEndState -import nl.rijksoverheid.ctr.holder.your_events.models.YourEventsEndStateWithCustomTitle -import nl.rijksoverheid.ctr.shared.models.Flow -import nl.rijksoverheid.ctr.shared.models.WeCouldntCreateCertificateException - -interface YourEventsEndStateUtil { - fun getEndState(context: Context, newEvents: List = listOf(), hints: List, blockedEvents: List = listOf()): YourEventsEndState - fun getErrorStateSubstring(context: Context, flow: Flow): String -} - -class YourEventsEndStateUtilImpl( - private val stringUtil: StringUtil -) : YourEventsEndStateUtil { - override fun getEndState(context: Context, newEvents: List, hints: List, blockedEvents: List): YourEventsEndState { - val newEventsContainBlockedEvent = newEvents.any { blockedEvents.contains(it) } - return if (newEventsContainBlockedEvent) { - YourEventsEndState.BlockedEvent - } else { - val endStateFromHints = hintsToEndState(hints) - if (endStateFromHints != YourEventsEndState.None) { - endStateFromHints - } else { - val localisedHints = - hints.map { stringUtil.getStringFromResourceName(it) }.filterNot { it.isEmpty() } - if (localisedHints.isEmpty()) { - YourEventsEndState.None - } else { - YourEventsEndState.Hints(localisedHints) - } - } - } - } - - private fun hintsToEndState(hints: List): YourEventsEndState { - val anyRecoveryCreated = - hints.contains("domestic_recovery_created") || hints.contains("international_recovery_created") - val allRecoveriesCreated = - hints.contains("domestic_recovery_created") && hints.contains("international_recovery_created") - val anyRecoveryRejected = - hints.contains("domestic_recovery_rejected") || hints.contains("international_recovery_rejected") - val anyVaccinationCreated = - hints.contains("domestic_vaccination_created") || hints.contains("international_vaccination_created") - val allVaccinationsCreated = - hints.contains("domestic_vaccination_created") && hints.contains("international_vaccination_created") - val anyVaccinationRejected = - hints.contains("domestic_vaccination_rejected") || hints.contains("international_vaccination_rejected") - val anyNegativeTestCreated = - hints.contains("domestic_negativetest_created") || hints.contains("international_negativetest_created") - val anyNegativeTestRejected = - hints.contains("domestic_negativetest_rejected") || hints.contains("international_negativetest_rejected") - - if (allRecoveriesCreated && hints.contains("vaccination_dose_correction_applied")) { - return if (allVaccinationsCreated) { - YourEventsEndStateWithCustomTitle.VaccinationsAndRecovery - } else { - YourEventsEndStateWithCustomTitle.RecoveryAndDosisCorrection - } - } - - if (!anyVaccinationCreated && !anyVaccinationRejected) { - - if (anyNegativeTestCreated) { - return YourEventsEndState.None - } else if (anyNegativeTestRejected) { - return YourEventsEndState.WeCouldntMakeACertificateError( - WeCouldntCreateCertificateException("0512") - ) - } - - return if (anyRecoveryCreated) { - YourEventsEndState.None - } else if (anyRecoveryRejected && hints.contains("vaccination_dose_correction_applied")) { - YourEventsEndStateWithCustomTitle.NoRecoveryButDosisCorrection - } else if (anyRecoveryRejected && - (hints.contains("vaccination_dose_correction_not_applied") || - hints.contains("international_recovery_too_old")) - ) { - YourEventsEndStateWithCustomTitle.RecoveryTooOld - } else if (anyRecoveryRejected) { - YourEventsEndState.WeCouldntMakeACertificateError( - WeCouldntCreateCertificateException("0511") - ) - } else { - YourEventsEndState.None - } - } - - if (!anyVaccinationRejected && !anyRecoveryCreated) { - return YourEventsEndState.None - } - - if (anyRecoveryCreated) { - return if (anyVaccinationCreated) { - if (hints.contains("domestic_vaccination_created")) { - YourEventsEndStateWithCustomTitle.VaccinationsAndRecovery - } else { - YourEventsEndStateWithCustomTitle.InternationalVaccinationAndRecovery - } - } else { - YourEventsEndStateWithCustomTitle.RecoveryOnly - } - } - - if (hints.contains("domestic_vaccination_rejected") && hints.contains("international_vaccination_rejected")) { - return YourEventsEndState.WeCouldntMakeACertificateError( - WeCouldntCreateCertificateException("059") - ) - } - - if (hints.contains("domestic_vaccination_rejected")) { - return YourEventsEndStateWithCustomTitle.InternationalQROnly - } - - if (hints.containsAll( - listOf( - "domestic_recovery_rejected", - "international_recovery_rejected", - "domestic_vaccination_rejected", - "international_vaccination_rejected", - "vaccination_dose_correction_not_applied" - ) - ) - ) { - return YourEventsEndState.WeCouldntMakeACertificateError( - WeCouldntCreateCertificateException("0510") - ) - } - - return YourEventsEndState.None - } - - override fun getErrorStateSubstring(context: Context, flow: Flow): String { - return context.getString( - when (flow) { - HolderFlow.CommercialTest -> R.string.general_negativeTest - HolderFlow.DigidTest -> R.string.general_negativeTest - HolderFlow.Recovery -> R.string.general_positiveTest - HolderFlow.Vaccination -> R.string.general_vaccination - else -> R.string.general_retrievedDetails - } - ).lowercase() - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/YourEventsFragmentUtil.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/YourEventsFragmentUtil.kt deleted file mode 100644 index fc35bedc0..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/utils/YourEventsFragmentUtil.kt +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.your_events.utils - -import androidx.core.text.HtmlCompat -import java.time.LocalDate -import java.time.format.DateTimeFormatter -import java.time.format.DateTimeParseException -import nl.rijksoverheid.ctr.appconfig.api.model.AppConfig -import nl.rijksoverheid.ctr.design.ext.formatDayMonthYear -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteProtocol -import nl.rijksoverheid.ctr.holder.models.HolderFlow -import nl.rijksoverheid.ctr.holder.your_events.YourEventsFragmentType -import nl.rijksoverheid.ctr.persistence.database.entities.OriginType -import nl.rijksoverheid.ctr.shared.models.Flow - -interface YourEventsFragmentUtil { - fun getHeaderCopy(type: YourEventsFragmentType, flow: Flow): Int - fun getNoOriginTypeCopy(type: YourEventsFragmentType, flow: Flow): Int - fun getProviderName(providers: List, providerIdentifier: String): String - fun getCancelDialogDescription(type: YourEventsFragmentType): Int - fun getFullName(holder: RemoteProtocol.Holder?): String - fun getBirthDate(holder: RemoteProtocol.Holder?): String - fun getVaccinationDate(date: LocalDate?): String -} - -class YourEventsFragmentUtilImpl( - private val remoteEventUtil: RemoteEventUtil -) : YourEventsFragmentUtil { - override fun getHeaderCopy(type: YourEventsFragmentType, flow: Flow): Int { - return when { - flow == HolderFlow.Migration -> { - R.string.holder_migrationFlow_scannedDetailsOverview_message - } - type is YourEventsFragmentType.DCC -> { - R.string.holder_listRemoteEvents_paperflow_message - } - isRecovery(type) -> { - R.string.holder_listRemoteEvents_recovery_message - } - isTest(type) -> { - R.string.holder_listRemoteEvents_negativeTest_message - } - else -> { - R.string.holder_listRemoteEvents_vaccination_message - } - } - } - - private fun isRecovery(yourEventsFragmentType: YourEventsFragmentType): Boolean { - val type = - yourEventsFragmentType as? YourEventsFragmentType.RemoteProtocol3Type ?: return false - val remoteEvent = type.remoteEvents.keys.firstOrNull()?.events?.first() ?: return false - return remoteEventUtil.getOriginType(remoteEvent) == OriginType.Recovery - } - - private fun isTest(yourEventsFragmentType: YourEventsFragmentType): Boolean { - val type = - yourEventsFragmentType as? YourEventsFragmentType.RemoteProtocol3Type ?: return false - val remoteEvent = type.remoteEvents.keys.firstOrNull()?.events?.first() ?: return false - return remoteEventUtil.getOriginType(remoteEvent) == OriginType.Test - } - - override fun getNoOriginTypeCopy(type: YourEventsFragmentType, flow: Flow): Int { - return when (type) { - is YourEventsFragmentType.DCC -> { - R.string.rule_engine_no_test_origin_description_scanned_qr_code - } - is YourEventsFragmentType.RemoteProtocol3Type -> { - return when (remoteEventUtil.getOriginType(type.remoteEvents.keys.first().events!!.first())) { - is OriginType.Test -> { - R.string.rule_engine_no_test_origin_description_negative_test - } - is OriginType.Recovery -> { - R.string.rule_engine_no_test_origin_description_positive_test - } - is OriginType.Vaccination -> { - if (flow is HolderFlow.VaccinationAndPositiveTest) { - R.string.general_retrievedDetails - } else { - R.string.rule_engine_no_test_origin_description_vaccination - } - } - } - } - } - } - - override fun getProviderName( - providers: List, - providerIdentifier: String - ): String { - return providers.firstOrNull { it.code == providerIdentifier } - ?.name - ?: providerIdentifier - } - - override fun getCancelDialogDescription(type: YourEventsFragmentType): Int { - return when (type) { - is YourEventsFragmentType.DCC -> R.string.holder_dcc_alert_message - is YourEventsFragmentType.RemoteProtocol3Type -> { - when (remoteEventUtil.getOriginType(type.remoteEvents.keys.first().events!!.first())) { - is OriginType.Test -> R.string.holder_test_alert_message - is OriginType.Recovery -> R.string.holder_recovery_alert_message - is OriginType.Vaccination -> R.string.holder_vaccination_alert_message - } - } - } - } - - override fun getFullName(holder: RemoteProtocol.Holder?): String { - return holder?.let { - return HtmlCompat.fromHtml( - if (it.infix.isNullOrEmpty()) { - "${it.lastName}, ${it.firstName}" - } else { - "${it.infix} ${it.lastName}, ${it.firstName}" - }, HtmlCompat.FROM_HTML_MODE_LEGACY - ).toString() - } ?: "" - } - - override fun getBirthDate(holder: RemoteProtocol.Holder?): String { - return holder?.birthDate?.let { - val birthDate = HtmlCompat.fromHtml(it, HtmlCompat.FROM_HTML_MODE_LEGACY).toString() - try { - LocalDate.parse(birthDate, DateTimeFormatter.ISO_DATE).formatDayMonthYear() - } catch (e: DateTimeParseException) { - // Check if date has removed content, if so return string directly - if (birthDate.contains("XX")) { - birthDate - } else "" - } catch (e: Exception) { - "" - } - } ?: "" - } - - override fun getVaccinationDate(date: LocalDate?): String { - return date?.let { vaccinationDate -> - try { - vaccinationDate.formatDayMonthYear() - } catch (e: Exception) { - "" - } - } ?: "" - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/widgets/YourEventWidget.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/widgets/YourEventWidget.kt deleted file mode 100644 index 0cce39d9b..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/widgets/YourEventWidget.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ - -package nl.rijksoverheid.ctr.holder.your_events.widgets - -import android.content.Context -import android.util.AttributeSet -import android.view.LayoutInflater -import androidx.constraintlayout.widget.ConstraintLayout -import androidx.core.content.ContextCompat -import androidx.core.view.accessibility.AccessibilityNodeInfoCompat -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.databinding.ItemYourEventBinding -import nl.rijksoverheid.ctr.shared.utils.Accessibility.addAccessibilityAction -import nl.rijksoverheid.ctr.shared.utils.Accessibility.setAccessibilityLabel -import nl.rijksoverheid.ctr.shared.utils.Accessibility.setAsAccessibilityButton - -class YourEventWidget @JvmOverloads constructor( - context: Context, - attrs: AttributeSet? = null, - defStyle: Int = 0, - defStyleRes: Int = 0 -) : ConstraintLayout(context, attrs, defStyle, defStyleRes) { - - val binding = - ItemYourEventBinding.inflate(LayoutInflater.from(context), this, true) - - fun setContent(title: String, subtitle: String, infoClickListener: () -> Unit) { - binding.rowTitle.text = title - binding.rowSubtitle.setHtmlText(subtitle, htmlTextColor = ContextCompat.getColor(context, R.color.html_secondary_text)) - binding.detailsButton.setOnClickListener { infoClickListener.invoke() } - binding.detailsButton.contentDescription = "${binding.detailsButton.text}, $title" - - with(binding.testResultsGroup) { - setOnClickListener { infoClickListener.invoke() } - - setAccessibilityLabel(String.format("%s. %s.", - binding.rowTitle.text, - binding.rowSubtitle.spannable - )) - setAsAccessibilityButton(true) - addAccessibilityAction(AccessibilityNodeInfoCompat.ACTION_CLICK, binding.detailsButton.text) - } - } - - fun setButtonsEnabled(enabled: Boolean) { - binding.detailsButton.isEnabled = enabled - binding.testResultsGroup.isClickable = enabled - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/widgets/YourEventWidgetUtil.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/widgets/YourEventWidgetUtil.kt deleted file mode 100644 index bcf719c8c..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/your_events/widgets/YourEventWidgetUtil.kt +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.holder.your_events.widgets - -import android.content.Context -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEventVaccination - -interface YourEventWidgetUtil { - fun getVaccinationEventTitle( - context: Context, - isDccEvent: Boolean, - currentEvent: RemoteEventVaccination - ): String - - fun getVaccinationEventSubtitle( - context: Context, - isDccEvent: Boolean, - providerIdentifiers: String, - vaccinationDate: String, - fullName: String, - birthDate: String - ): String -} - -class YourEventWidgetUtilImpl : YourEventWidgetUtil { - override fun getVaccinationEventTitle( - context: Context, - isDccEvent: Boolean, - currentEvent: RemoteEventVaccination - ): String { - return if (isDccEvent) { - context.getString(R.string.retrieved_vaccination_dcc_title, currentEvent.vaccination?.doseNumber ?: "", currentEvent.vaccination?.totalDoses ?: "") - } else { - context.getString( - R.string.retrieved_vaccination_title - ) - } - } - - override fun getVaccinationEventSubtitle( - context: Context, - isDccEvent: Boolean, - providerIdentifiers: String, - vaccinationDate: String, - fullName: String, - birthDate: String - ): String { - return if (isDccEvent) { - context.getString( - R.string.your_vaccination_dcc_row_subtitle, - vaccinationDate, - fullName, - birthDate) - } else { - context.getString( - R.string.your_vaccination_row_subtitle, - vaccinationDate, - fullName, - birthDate, - providerIdentifiers - ) - } - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/persistence/database/HolderDatabaseSyncer.kt b/holder/src/main/java/nl/rijksoverheid/ctr/persistence/database/HolderDatabaseSyncer.kt deleted file mode 100644 index e77dbf32e..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/persistence/database/HolderDatabaseSyncer.kt +++ /dev/null @@ -1,206 +0,0 @@ -package nl.rijksoverheid.ctr.persistence.database - -import java.time.OffsetDateTime -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.sync.Mutex -import kotlinx.coroutines.sync.withLock -import kotlinx.coroutines.withContext -import nl.rijksoverheid.ctr.holder.dashboard.util.GreenCardUtil -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEvent -import nl.rijksoverheid.ctr.holder.get_events.usecases.PersistBlockedEventsUseCase -import nl.rijksoverheid.ctr.holder.models.HolderFlow -import nl.rijksoverheid.ctr.holder.usecases.HolderFeatureFlagUseCase -import nl.rijksoverheid.ctr.holder.workers.WorkerManagerUtil -import nl.rijksoverheid.ctr.persistence.database.entities.RemovedEventReason -import nl.rijksoverheid.ctr.persistence.database.usecases.DraftEventUseCase -import nl.rijksoverheid.ctr.persistence.database.usecases.GetRemoteGreenCardsUseCase -import nl.rijksoverheid.ctr.persistence.database.usecases.RemoteGreenCardsResult -import nl.rijksoverheid.ctr.persistence.database.usecases.RemoveExpiredEventsUseCase -import nl.rijksoverheid.ctr.persistence.database.usecases.SyncRemoteGreenCardsResult -import nl.rijksoverheid.ctr.persistence.database.usecases.SyncRemoteGreenCardsUseCase -import nl.rijksoverheid.ctr.persistence.database.usecases.UpdateEventExpirationUseCase -import nl.rijksoverheid.ctr.shared.MobileCoreWrapper -import nl.rijksoverheid.ctr.shared.models.ErrorResult -import nl.rijksoverheid.ctr.shared.models.Flow -import nl.rijksoverheid.ctr.shared.models.NetworkRequestResult - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -interface HolderDatabaseSyncer { - - /** - * Synchronized the database. Does cleanup in the database based on expiration dates and can resync with remote - * @param flow the [HolderFlow] we are in - * @param syncWithRemote If true and the data call to resync succeeds, clear all green cards in the database and re-add them - * @param previousSyncResult The previous result outputted by this [sync] if known - */ - suspend fun sync( - flow: Flow = HolderFlow.Startup, - syncWithRemote: Boolean = true, - previousSyncResult: DatabaseSyncerResult? = null, - newEvents: List = listOf() - ): DatabaseSyncerResult -} - -class HolderDatabaseSyncerImpl( - private val mobileCoreWrapper: MobileCoreWrapper, - private val holderDatabase: HolderDatabase, - private val greenCardUtil: GreenCardUtil, - private val workerManagerUtil: WorkerManagerUtil, - private val getRemoteGreenCardsUseCase: GetRemoteGreenCardsUseCase, - private val syncRemoteGreenCardsUseCase: SyncRemoteGreenCardsUseCase, - private val removeExpiredEventsUseCase: RemoveExpiredEventsUseCase, - private val updateEventExpirationUseCase: UpdateEventExpirationUseCase, - private val draftEventUseCase: DraftEventUseCase, - private val featureFlagUseCase: HolderFeatureFlagUseCase, - private val persistBlockedEventsUseCase: PersistBlockedEventsUseCase -) : HolderDatabaseSyncer { - - private val mutex = Mutex() - - override suspend fun sync( - flow: Flow, - syncWithRemote: Boolean, - previousSyncResult: DatabaseSyncerResult?, - newEvents: List - ): DatabaseSyncerResult { - return withContext(Dispatchers.IO) { - mutex.withLock { - val events = holderDatabase.eventGroupDao().getAll() - - if (!featureFlagUseCase.isInArchiveMode() && syncWithRemote) { - if (events.isEmpty()) { - // Remote does not handle empty events, so we decide that empty events == no green cards - holderDatabase.greenCardDao().deleteAll() - return@withContext DatabaseSyncerResult.Success(listOf()) - } - - // Generate a new secret key - val secretKey = mobileCoreWrapper.generateHolderSk() - - // Sync with remote - val remoteGreenCardsResult = getRemoteGreenCardsUseCase.get( - events = events, - secretKey = secretKey, - flow = flow - ) - - when (remoteGreenCardsResult) { - is RemoteGreenCardsResult.Success -> { - // Update event expire dates - updateEventExpirationUseCase.update( - blobExpireDates = remoteGreenCardsResult.remoteGreenCards.blobExpireDates ?: listOf() - ) - - // Persist blocked events for communication to the user on the dashboard - persistBlockedEventsUseCase.persist( - newEvents = newEvents, - removedEvents = remoteGreenCardsResult.blockedEvents, - reason = RemovedEventReason.Blocked - ) - - val remoteGreenCards = remoteGreenCardsResult.remoteGreenCards - - // Insert green cards in database - val result = syncRemoteGreenCardsUseCase.execute( - remoteGreenCards = remoteGreenCards, - secretKey = secretKey - ) - - // Clean up expired events in the database - removeExpiredEventsUseCase.execute( - events = holderDatabase.eventGroupDao().getAll() - ) - - when (result) { - is SyncRemoteGreenCardsResult.Success -> { - draftEventUseCase.finalise() - workerManagerUtil.scheduleRefreshCredentialsJob() - return@withContext DatabaseSyncerResult.Success( - hints = remoteGreenCards.hints ?: listOf(), - blockedEvents = remoteGreenCardsResult.blockedEvents - ) - } - is SyncRemoteGreenCardsResult.Failed -> { - draftEventUseCase.remove() - return@withContext DatabaseSyncerResult.Failed.Error(result.errorResult) - } - } - } - is RemoteGreenCardsResult.FuzzyMatchingError -> { - DatabaseSyncerResult.FuzzyMatchingError( - matchingBlobIds = remoteGreenCardsResult.matchingBlobIds - ) - } - is RemoteGreenCardsResult.Error -> { - draftEventUseCase.remove() - val greenCards = holderDatabase.greenCardDao().getAll() - - when (remoteGreenCardsResult.errorResult) { - is NetworkRequestResult.Failed.ClientNetworkError, is NetworkRequestResult.Failed.ServerNetworkError -> { - DatabaseSyncerResult.Failed.NetworkError( - errorResult = remoteGreenCardsResult.errorResult, - hasGreenCardsWithoutCredentials = greenCards - .any { greenCardUtil.hasNoActiveCredentials(it) } - ) - } - is NetworkRequestResult.Failed.CoronaCheckHttpError -> { - if (previousSyncResult == null) { - DatabaseSyncerResult.Failed.ServerError.FirstTime( - errorResult = remoteGreenCardsResult.errorResult - ) - } else { - DatabaseSyncerResult.Failed.ServerError.MultipleTimes( - errorResult = remoteGreenCardsResult.errorResult - ) - } - } - else -> { - DatabaseSyncerResult.Failed.Error( - errorResult = remoteGreenCardsResult.errorResult - ) - } - } - } - } - } else { - previousSyncResult ?: DatabaseSyncerResult.Success(listOf()) - } - } - } - } -} - -sealed class DatabaseSyncerResult { - data class Success( - val hints: List = listOf(), - val blockedEvents: List = listOf() - ) : DatabaseSyncerResult() - - data class FuzzyMatchingError( - val matchingBlobIds: List> - ) : DatabaseSyncerResult() - - sealed class Failed(open val errorResult: ErrorResult, open val failedAt: OffsetDateTime) : - DatabaseSyncerResult() { - data class NetworkError( - override val errorResult: ErrorResult, - val hasGreenCardsWithoutCredentials: Boolean - ) : Failed(errorResult, OffsetDateTime.now()) - - sealed class ServerError(override val errorResult: ErrorResult) : - Failed(errorResult, OffsetDateTime.now()) { - data class FirstTime(override val errorResult: ErrorResult) : ServerError(errorResult) - data class MultipleTimes(override val errorResult: ErrorResult) : - ServerError(errorResult) - } - - data class Error(override val errorResult: ErrorResult) : - Failed(errorResult, OffsetDateTime.now()) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/persistence/database/usecases/CreateEuGreenCardsUseCase.kt b/holder/src/main/java/nl/rijksoverheid/ctr/persistence/database/usecases/CreateEuGreenCardsUseCase.kt deleted file mode 100644 index d18a87bdb..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/persistence/database/usecases/CreateEuGreenCardsUseCase.kt +++ /dev/null @@ -1,75 +0,0 @@ -package nl.rijksoverheid.ctr.persistence.database.usecases - -import java.time.Instant -import java.time.OffsetDateTime -import java.time.ZoneOffset -import nl.rijksoverheid.ctr.holder.your_events.models.RemoteGreenCards -import nl.rijksoverheid.ctr.persistence.database.HolderDatabase -import nl.rijksoverheid.ctr.persistence.database.entities.CredentialEntity -import nl.rijksoverheid.ctr.persistence.database.entities.GreenCardEntity -import nl.rijksoverheid.ctr.persistence.database.entities.GreenCardType -import nl.rijksoverheid.ctr.persistence.database.entities.OriginEntity -import nl.rijksoverheid.ctr.persistence.database.entities.OriginHintEntity -import nl.rijksoverheid.ctr.shared.MobileCoreWrapper - -interface CreateEuGreenCardUseCase { - suspend fun create(greenCard: RemoteGreenCards.EuGreenCard) -} - -class CreateEuGreenCardUseCaseImpl( - private val holderDatabase: HolderDatabase, - private val mobileCoreWrapper: MobileCoreWrapper -) : CreateEuGreenCardUseCase { - override suspend fun create(greenCard: RemoteGreenCards.EuGreenCard) { - // Create green card - val localEuropeanGreenCardId = holderDatabase.greenCardDao().insert( - GreenCardEntity( - walletId = 1, - type = GreenCardType.Eu - ) - ) - - // Create origins for european green card - greenCard.origins.map { remoteOrigin -> - val localOriginId = holderDatabase.originDao().insert( - OriginEntity( - greenCardId = localEuropeanGreenCardId, - type = remoteOrigin.type, - eventTime = remoteOrigin.eventTime, - expirationTime = remoteOrigin.expirationTime, - validFrom = remoteOrigin.validFrom - ) - ) - - remoteOrigin.hints?.forEach { hint -> - holderDatabase.originHintDao().insert( - OriginHintEntity( - originId = localOriginId, - hint = hint - ) - ) - } - } - - // Create credential - val europeanCredential = mobileCoreWrapper.readEuropeanCredential( - credential = greenCard.credential.toByteArray() - ) - - val entity = CredentialEntity( - greenCardId = localEuropeanGreenCardId, - data = greenCard.credential.toByteArray(), - credentialVersion = europeanCredential.getInt("credentialVersion"), - validFrom = OffsetDateTime.ofInstant( - Instant.ofEpochSecond(europeanCredential.getLong("issuedAt")), - ZoneOffset.UTC - ), - expirationTime = OffsetDateTime.ofInstant( - Instant.ofEpochSecond(europeanCredential.getLong("expirationTime")), - ZoneOffset.UTC - ) - ) - - holderDatabase.credentialDao().insert(entity) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/persistence/database/usecases/DraftEventUseCase.kt b/holder/src/main/java/nl/rijksoverheid/ctr/persistence/database/usecases/DraftEventUseCase.kt deleted file mode 100644 index 52c01047f..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/persistence/database/usecases/DraftEventUseCase.kt +++ /dev/null @@ -1,30 +0,0 @@ -package nl.rijksoverheid.ctr.persistence.database.usecases - -import nl.rijksoverheid.ctr.persistence.database.HolderDatabase - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -interface DraftEventUseCase { - suspend fun remove() - suspend fun finalise() -} - -class DraftEventUseCaseImpl( - private val holderDatabase: HolderDatabase -) : DraftEventUseCase { - - private val eventGroupDao = holderDatabase.eventGroupDao() - - override suspend fun remove() { - eventGroupDao.deleteDraftEvents() - } - - override suspend fun finalise() { - eventGroupDao.updateDraft(false) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/persistence/database/usecases/GetRemoteGreenCardsUseCase.kt b/holder/src/main/java/nl/rijksoverheid/ctr/persistence/database/usecases/GetRemoteGreenCardsUseCase.kt deleted file mode 100644 index eeae4c243..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/persistence/database/usecases/GetRemoteGreenCardsUseCase.kt +++ /dev/null @@ -1,124 +0,0 @@ -package nl.rijksoverheid.ctr.persistence.database.usecases - -import nl.rijksoverheid.ctr.holder.api.repositories.CoronaCheckRepository -import nl.rijksoverheid.ctr.holder.get_events.models.RemoteEvent -import nl.rijksoverheid.ctr.holder.get_events.usecases.GetRemoteProtocolFromEventGroupUseCase -import nl.rijksoverheid.ctr.holder.models.HolderStep -import nl.rijksoverheid.ctr.holder.your_events.models.RemoteGreenCards -import nl.rijksoverheid.ctr.persistence.database.entities.EventGroupEntity -import nl.rijksoverheid.ctr.shared.MobileCoreWrapper -import nl.rijksoverheid.ctr.shared.models.AppErrorResult -import nl.rijksoverheid.ctr.shared.models.ErrorResult -import nl.rijksoverheid.ctr.shared.models.Flow -import nl.rijksoverheid.ctr.shared.models.NetworkRequestResult -import org.json.JSONObject - -/** - * Get green cards from remote - */ -interface GetRemoteGreenCardsUseCase { - suspend fun get( - events: List, - secretKey: String, - flow: Flow - ): RemoteGreenCardsResult -} - -class GetRemoteGreenCardsUseCaseImpl( - private val coronaCheckRepository: CoronaCheckRepository, - private val mobileCoreWrapper: MobileCoreWrapper, - private val getRemoteProtocolFromEventGroupUseCase: GetRemoteProtocolFromEventGroupUseCase -) : GetRemoteGreenCardsUseCase { - - override suspend fun get( - events: List, - secretKey: String, - flow: Flow - ): RemoteGreenCardsResult { - return try { - val prepareIssue = - when (val prepareIssueResult = coronaCheckRepository.getPrepareIssue()) { - is NetworkRequestResult.Success -> { - prepareIssueResult.response - } - is NetworkRequestResult.Failed -> { - return RemoteGreenCardsResult.Error(prepareIssueResult) - } - } - - val commitmentMessage = try { - mobileCoreWrapper.createCommitmentMessage( - secretKey = secretKey.toByteArray(), - prepareIssueMessage = prepareIssue.prepareIssueMessage - ) - } catch (e: Exception) { - return RemoteGreenCardsResult.Error( - AppErrorResult( - step = HolderStep.PrepareIssueNetworkRequest, - e = e - ) - ) - } - - val remoteGreenCardsResult = coronaCheckRepository.getGreenCards( - stoken = prepareIssue.stoken, - events = events.map { - val jsonObject = JSONObject(it.jsonData.decodeToString()) - jsonObject.put("id", it.id.toString()) - jsonObject.toString() - }, - issueCommitmentMessage = commitmentMessage, - flow = flow - ) - - when (remoteGreenCardsResult) { - is NetworkRequestResult.Success -> { - val matchingBlobIds = remoteGreenCardsResult.response.context?.matchingBlobIds - if (matchingBlobIds?.isNotEmpty() == true) { - val fuzzyMatchedEvents = matchingBlobIds.flatten().toSet().mapNotNull { fuzzyMatchedEventId -> - val eventGroup = events.firstOrNull() { event -> event.id == fuzzyMatchedEventId } - val remoteProtocol = - eventGroup?.let { getRemoteProtocolFromEventGroupUseCase.get(it) } - remoteProtocol?.events?.mapNotNull { remoteEvent -> - remoteEvent - } - }.flatten() - return RemoteGreenCardsResult.FuzzyMatchingError(matchingBlobIds, fuzzyMatchedEvents) - } - - val blockedEventIds = - remoteGreenCardsResult.response.blobExpireDates?.filter { it.reason == "event_blocked" } - ?: listOf() - val blockedEvents = blockedEventIds.mapNotNull { blobExpiry -> - val eventGroup = events.firstOrNull { event -> event.id == blobExpiry.id } - val remoteProtocol = - eventGroup?.let { getRemoteProtocolFromEventGroupUseCase.get(it) } - remoteProtocol?.events?.mapNotNull { remoteEvent -> - remoteEvent - } - }.flatten() - RemoteGreenCardsResult.Success(remoteGreenCardsResult.response, blockedEvents) - } - is NetworkRequestResult.Failed -> { - RemoteGreenCardsResult.Error(remoteGreenCardsResult) - } - } - } catch (e: Exception) { - RemoteGreenCardsResult.Error(AppErrorResult(HolderStep.GetCredentialsNetworkRequest, e)) - } - } -} - -sealed class RemoteGreenCardsResult { - data class Success( - val remoteGreenCards: RemoteGreenCards, - val blockedEvents: List = listOf() - ) : RemoteGreenCardsResult() - - data class FuzzyMatchingError( - val matchingBlobIds: List>, - val fuzzyMatchedEvents: List - ) : RemoteGreenCardsResult() - - data class Error(val errorResult: ErrorResult) : RemoteGreenCardsResult() -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/persistence/database/usecases/RemoveCTBUseCase.kt b/holder/src/main/java/nl/rijksoverheid/ctr/persistence/database/usecases/RemoveCTBUseCase.kt deleted file mode 100644 index 7705af2dc..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/persistence/database/usecases/RemoveCTBUseCase.kt +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.persistence.database.usecases - -import android.util.Base64 -import com.squareup.moshi.Moshi -import nl.rijksoverheid.ctr.holder.your_events.utils.SignedResponse -import nl.rijksoverheid.ctr.persistence.database.HolderDatabase -import nl.rijksoverheid.ctr.persistence.database.entities.GreenCardType -import nl.rijksoverheid.ctr.persistence.database.entities.OriginType - -interface RemoveCTBUseCase { - suspend fun execute() -} - -class RemoveCTBUseCaseImpl( - private val moshi: Moshi, - private val holderDatabase: HolderDatabase -) : RemoveCTBUseCase { - override suspend fun execute() { - holderDatabase.eventGroupDao().deleteAllOfNotTypes( - listOf( - OriginType.Vaccination, - OriginType.Recovery, - OriginType.Test - ) - ) - val remainingEventGroups = holderDatabase.eventGroupDao().getAll() - val eventGroupsWithVaccinationAssessmentEvents = remainingEventGroups.filter { - try { - val payload = moshi.adapter(SignedResponse::class.java) - .fromJson(String(it.jsonData))?.payload - String(Base64.decode(payload, Base64.DEFAULT)).contains("vaccinationassessment") - } catch (exception: Exception) { - false - } - } - if (eventGroupsWithVaccinationAssessmentEvents.isNotEmpty()) { - holderDatabase.eventGroupDao().deleteAllOfIds(eventGroupsWithVaccinationAssessmentEvents.map { it.id }) - } - holderDatabase.greenCardDao().deleteAllOfNotTypes( - listOf( - GreenCardType.Eu - ) - ) - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/persistence/database/usecases/RemoveExpiredEventsUseCase.kt b/holder/src/main/java/nl/rijksoverheid/ctr/persistence/database/usecases/RemoveExpiredEventsUseCase.kt deleted file mode 100644 index bf20e9209..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/persistence/database/usecases/RemoveExpiredEventsUseCase.kt +++ /dev/null @@ -1,30 +0,0 @@ -package nl.rijksoverheid.ctr.persistence.database.usecases - -import java.time.Clock -import java.time.OffsetDateTime -import nl.rijksoverheid.ctr.holder.usecases.HolderFeatureFlagUseCase -import nl.rijksoverheid.ctr.persistence.database.HolderDatabase -import nl.rijksoverheid.ctr.persistence.database.entities.EventGroupEntity - -interface RemoveExpiredEventsUseCase { - suspend fun execute(events: List) -} - -class RemoveExpiredEventsUseCaseImpl( - private val clock: Clock, - private val featureFlagUseCase: HolderFeatureFlagUseCase, - private val holderDatabase: HolderDatabase -) : RemoveExpiredEventsUseCase { - - override suspend fun execute(events: List) { - if (featureFlagUseCase.isInArchiveMode()) { - return - } - - events.forEach { - if (it.expiryDate != null && it.expiryDate <= OffsetDateTime.now(clock)) { - holderDatabase.eventGroupDao().delete(it) - } - } - } -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/persistence/database/usecases/SyncRemoteGreenCardsUseCase.kt b/holder/src/main/java/nl/rijksoverheid/ctr/persistence/database/usecases/SyncRemoteGreenCardsUseCase.kt deleted file mode 100644 index 9509ba18a..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/persistence/database/usecases/SyncRemoteGreenCardsUseCase.kt +++ /dev/null @@ -1,53 +0,0 @@ -package nl.rijksoverheid.ctr.persistence.database.usecases - -import nl.rijksoverheid.ctr.holder.models.HolderStep -import nl.rijksoverheid.ctr.holder.your_events.models.RemoteGreenCards -import nl.rijksoverheid.ctr.persistence.database.HolderDatabase -import nl.rijksoverheid.ctr.shared.MobileCoreWrapper -import nl.rijksoverheid.ctr.shared.models.AppErrorResult -import nl.rijksoverheid.ctr.shared.models.ErrorResult - -/** - * Inserts the green cards fetched from remote into the database - */ -interface SyncRemoteGreenCardsUseCase { - suspend fun execute(remoteGreenCards: RemoteGreenCards, secretKey: String): SyncRemoteGreenCardsResult -} - -class SyncRemoteGreenCardsUseCaseImpl( - private val holderDatabase: HolderDatabase, - private val createEuGreenCardsUseCase: CreateEuGreenCardUseCase, - private val mobileCoreWrapper: MobileCoreWrapper -) : SyncRemoteGreenCardsUseCase { - - override suspend fun execute(remoteGreenCards: RemoteGreenCards, secretKey: String): SyncRemoteGreenCardsResult { - try { - // Clear everything from the database - holderDatabase.greenCardDao().deleteAll() - holderDatabase.originDao().deleteAll() - holderDatabase.credentialDao().deleteAll() - holderDatabase.originHintDao().deleteAll() - - remoteGreenCards.euGreencards?.let { - it.forEach { greenCard -> - createEuGreenCardsUseCase.create( - greenCard = greenCard - ) - } - } - return SyncRemoteGreenCardsResult.Success - } catch (e: Exception) { - return SyncRemoteGreenCardsResult.Failed( - AppErrorResult( - step = HolderStep.StoringCredentials, - e = e - ) - ) - } - } -} - -sealed class SyncRemoteGreenCardsResult { - object Success : SyncRemoteGreenCardsResult() - data class Failed(val errorResult: ErrorResult) : SyncRemoteGreenCardsResult() -} diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/persistence/database/usecases/UpdateEventExpirationUseCase.kt b/holder/src/main/java/nl/rijksoverheid/ctr/persistence/database/usecases/UpdateEventExpirationUseCase.kt deleted file mode 100644 index 6c9e55ac5..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/persistence/database/usecases/UpdateEventExpirationUseCase.kt +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - */ - -package nl.rijksoverheid.ctr.persistence.database.usecases - -import nl.rijksoverheid.ctr.holder.your_events.models.RemoteGreenCards -import nl.rijksoverheid.ctr.persistence.database.HolderDatabase - -interface UpdateEventExpirationUseCase { - suspend fun update(blobExpireDates: List) -} - -class UpdateEventExpirationUseCaseImpl( - private val holderDatabase: HolderDatabase -) : UpdateEventExpirationUseCase { - - override suspend fun update(blobExpireDates: List) { - blobExpireDates.forEach { - holderDatabase.eventGroupDao().updateExpiryDate( - eventGroupId = it.id, - expiryDate = it.expiry - ) - } - } -} diff --git a/holder/src/main/res/layout/fragment_main.xml b/holder/src/main/res/layout/fragment_main.xml deleted file mode 100644 index 174c9d66c..000000000 --- a/holder/src/main/res/layout/fragment_main.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - diff --git a/holder/src/main/res/navigation/holder_fuzzy_matching.xml b/holder/src/main/res/navigation/holder_fuzzy_matching.xml deleted file mode 100644 index a2bdff8ba..000000000 --- a/holder/src/main/res/navigation/holder_fuzzy_matching.xml +++ /dev/null @@ -1,86 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/holder/src/main/res/navigation/holder_nav_graph_main.xml b/holder/src/main/res/navigation/holder_nav_graph_main.xml deleted file mode 100644 index e70cbcb8f..000000000 --- a/holder/src/main/res/navigation/holder_nav_graph_main.xml +++ /dev/null @@ -1,857 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/holder/src/main/res/navigation/holder_nav_graph_root.xml b/holder/src/main/res/navigation/holder_nav_graph_root.xml index 637cfa8bf..ea636d63a 100644 --- a/holder/src/main/res/navigation/holder_nav_graph_root.xml +++ b/holder/src/main/res/navigation/holder_nav_graph_root.xml @@ -5,50 +5,6 @@ android:id="@+id/root_nav" app:startDestination="@+id/nav_status"> - - - - - - - - - - - - - - - From 4cd7261407c88b539e6f7ecc026d30d5a531b182 Mon Sep 17 00:00:00 2001 From: Giorgos Papadopoulos Date: Fri, 1 Dec 2023 15:38:20 +0100 Subject: [PATCH 08/21] delete part 2 --- .../nl/rijksoverheid/ctr/holder/Bindings.kt | 62 --- .../layout/adapter_item_dashboard_add_qr.xml | 27 - .../adapter_item_dashboard_green_card.xml | 202 ------- ..._item_dashboard_green_card_placeholder.xml | 58 -- .../layout/adapter_item_dashboard_header.xml | 39 -- .../adapter_item_dashboard_info_card.xml | 72 --- .../res/layout/adapter_item_saved_event.xml | 58 -- .../adapter_item_saved_events_clear_data.xml | 42 -- .../adapter_item_saved_events_header.xml | 45 -- ...pter_item_saved_events_no_saved_events.xml | 55 -- .../adapter_item_saved_events_section.xml | 41 -- .../layout/fragment_certificate_created.xml | 56 -- .../res/layout/fragment_choose_proof_type.xml | 76 --- .../res/layout/fragment_choose_provider.xml | 75 --- .../layout/fragment_could_not_create_qr.xml | 69 --- .../main/res/layout/fragment_dashboard.xml | 72 --- .../res/layout/fragment_dashboard_page.xml | 14 - .../fragment_data_migration_scan_qr.xml | 8 - .../fragment_data_migration_show_qr.xml | 74 --- ...ment_data_migration_start_transferring.xml | 74 --- ...agment_data_migration_transfer_options.xml | 60 --- .../layout/fragment_export_introduction.xml | 73 --- .../main/res/layout/fragment_get_events.xml | 97 ---- .../layout/fragment_holder_name_selection.xml | 40 -- .../main/res/layout/fragment_input_token.xml | 151 ------ .../src/main/res/layout/fragment_no_digid.xml | 71 --- ...agment_paper_proof_domestic_input_code.xml | 93 ---- .../fragment_paper_proof_start_scanning.xml | 90 ---- .../main/res/layout/fragment_pdf_exported.xml | 125 ----- .../main/res/layout/fragment_pdf_preview.xml | 12 - .../main/res/layout/fragment_pdf_webview.xml | 23 - .../src/main/res/layout/fragment_qr_codes.xml | 144 ----- .../main/res/layout/fragment_saved_events.xml | 20 - ...fragment_saved_events_sync_green_cards.xml | 19 - .../fragment_your_event_explanation.xml | 27 - .../main/res/layout/fragment_your_events.xml | 103 ---- .../res/layout/include_content_button.xml | 64 --- .../res/layout/include_loading_indicator.xml | 41 -- .../include_transfer_options_button.xml | 44 -- .../item_holder_name_selection_footer.xml | 19 - .../item_holder_name_selection_header.xml | 41 -- .../item_holder_name_selection_view.xml | 88 --- .../layout/item_paper_proof_explanation.xml | 51 -- .../src/main/res/layout/item_your_event.xml | 82 --- holder/src/main/res/layout/view_qr_code.xml | 99 ---- .../res/layout/widget_qr_code_animation.xml | 29 - .../layout/your_event_explanation_item.xml | 38 -- verifier/.gitignore | 1 - verifier/build.gradle | 160 ------ verifier/consumer-rules.pro | 0 verifier/google-services.json | 298 ---------- verifier/proguard-rules.pro | 21 - .../1.json | 46 -- .../drawable-v24/ic_launcher_background.xml | 28 - .../src/acc/res/mipmap-hdpi/ic_launcher.png | Bin 2800 -> 0 bytes .../acc/res/mipmap-hdpi/ic_launcher_round.png | Bin 4307 -> 0 bytes .../src/acc/res/mipmap-mdpi/ic_launcher.png | Bin 2065 -> 0 bytes .../acc/res/mipmap-mdpi/ic_launcher_round.png | Bin 2812 -> 0 bytes .../src/acc/res/mipmap-xhdpi/ic_launcher.png | Bin 3756 -> 0 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 6048 -> 0 bytes .../src/acc/res/mipmap-xxhdpi/ic_launcher.png | Bin 5418 -> 0 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 9298 -> 0 bytes .../acc/res/mipmap-xxxhdpi/ic_launcher.png | Bin 6977 -> 0 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 13365 -> 0 bytes verifier/src/debug/AndroidManifest.xml | 8 - verifier/src/debug/res/xml/network_config.xml | 15 - verifier/src/main/AndroidManifest.xml | 40 -- .../ctr/verifier/VerifierApplication.kt | 75 --- .../ctr/verifier/VerifierMainActivity.kt | 169 ------ .../verifier/VerifierMainActivityViewModel.kt | 47 -- .../ctr/verifier/VerifierMainFragment.kt | 40 -- .../InstructionsExplanationData.kt | 55 -- .../ScanInstructionsButtonUtil.kt | 40 -- .../instructions/ScanInstructionsFragment.kt | 228 -------- .../ScanInstructionsWithToolbarFragment.kt | 30 -- .../ctr/verifier/managers/DeeplinkManager.kt | 58 -- .../ctr/verifier/menu/MenuViewModel.kt | 203 ------- .../ctr/verifier/models/ScannerState.kt | 26 - .../ctr/verifier/models/VerifierStep.kt | 15 - .../ctr/verifier/modules/ErrorsModule.kt | 16 - .../ctr/verifier/modules/StorageModule.kt | 23 - .../modules/VerifierAppStatusModule.kt | 43 -- .../modules/VerifierClmobileModule.kt | 18 - .../modules/VerifierIntroductionModule.kt | 45 -- .../modules/VerifierMobileCoreModule.kt | 18 - .../ctr/verifier/modules/VerifierModule.kt | 154 ------ .../modules/VerifierPreferenceModule.kt | 27 - .../persistance/PersistenceManager.kt | 138 ----- .../persistance/database/VerifierDatabase.kt | 47 -- .../converters/VerifierDatabaseConverters.kt | 34 -- .../persistance/database/dao/ScanLogDao.kt | 31 -- .../database/entities/ScanLogEntity.kt | 22 - .../persistance/usecase/RandomKeyUseCase.kt | 40 -- .../usecase/VerifierCachedConfigUseCase.kt | 24 - .../policy/ConfigVerificationPolicyUseCase.kt | 68 --- .../ctr/verifier/policy/NewPolicyItem.kt | 18 - .../verifier/policy/NewPolicyRulesFragment.kt | 94 ---- .../policy/NewPolicyRulesItemUseCase.kt | 37 -- .../policy/NewPolicyRulesViewModel.kt | 46 -- .../policy/ScannerUsedRecentlyUseCase.kt | 27 - .../policy/VerificationPolicyInfoFragment.kt | 101 ---- .../VerificationPolicySelectionFragment.kt | 238 -------- .../VerificationPolicySelectionState.kt | 32 -- ...VerificationPolicySelectionStateUseCase.kt | 46 -- .../policy/VerificationPolicySelectionType.kt | 19 - .../VerificationPolicySelectionUseCase.kt | 42 -- .../VerificationPolicySelectionViewModel.kt | 73 --- .../ctr/verifier/scanlog/ScanLogFragment.kt | 72 --- .../ctr/verifier/scanlog/ScanLogViewModel.kt | 33 -- .../scanlog/datamapper/ScanLogDataMapper.kt | 68 --- .../items/ScanLogEmptyListAdapterItem.kt | 30 -- .../ScanLogFirstInstallTimeAdapterItem.kt | 39 -- .../scanlog/items/ScanLogHeaderAdapterItem.kt | 28 - .../ctr/verifier/scanlog/items/ScanLogItem.kt | 19 - .../scanlog/items/ScanLogListAdapterItem.kt | 51 -- .../items/ScanLogListHeaderAdapterItem.kt | 29 - .../ScanLogFirstInstallTimeAdapterItemUtil.kt | 24 - .../items/util/ScanLogListAdapterItemUtil.kt | 39 -- .../ctr/verifier/scanlog/models/ScanLog.kt | 19 - .../verifier/scanlog/models/ScanLogBuilder.kt | 35 -- .../scanlog/repositories/ScanLogRepository.kt | 33 -- .../scanlog/usecase/GetScanLogItemsUseCase.kt | 48 -- .../scanlog/usecase/LogScanUseCase.kt | 34 -- .../scanlog/usecase/ScanLogsCleanupUseCase.kt | 35 -- .../scanner/ScanResultInvalidFragment.kt | 120 ----- .../ScanResultPersonalDetailsFragment.kt | 114 ---- .../ScanResultPersonalDetailsWrongFragment.kt | 53 -- .../scanner/ScanResultValidFragment.kt | 108 ---- .../ctr/verifier/scanner/ScannerViewModel.kt | 57 -- .../scanner/VerifierQrScannerFragment.kt | 125 ----- .../scanner/models/ScanResultInvalidData.kt | 14 - .../scanner/models/ScanResultValidData.kt | 23 - .../scanner/models/VerifiedQrResultState.kt | 30 -- .../usecases/TestResultValidUseCase.kt | 48 -- .../scanner/usecases/VerifyQrUseCase.kt | 43 -- .../ctr/verifier/scanner/utils/ScannerUtil.kt | 25 - .../ctr/verifier/scanqr/ScanQrFragment.kt | 315 ----------- .../ctr/verifier/scanqr/ScanQrViewModel.kt | 61 --- .../verifier/scanqr/ScannerNavigationState.kt | 15 - .../scanqr/ScannerNavigationStateUseCase.kt | 35 -- .../scanqr/ScannerStateCountDownTimer.kt | 37 -- .../scanqr/util/ScannerStateCountdownUtil.kt | 32 -- .../usecases/BuildConfigUseCaseImpl.kt | 18 - .../verifier/usecases/ScannerStateUseCase.kt | 52 -- .../usecases/VerifierAppStatusUseCaseImpl.kt | 111 ---- .../usecases/VerifierFeatureFlagUseCase.kt | 27 - .../VerifierIntroductionStatusUseCase.kt | 18 - .../widgets/PersonalDetailItemWidget.kt | 59 -- .../widgets/ScrollViewPolicyButtonWidget.kt | 124 ----- .../play/listings/en-US/full-description.txt | 21 - .../listings/en-US/graphics/icon/icon.png | Bin 11777 -> 0 bytes .../play/listings/en-US/short-description.txt | 1 - .../src/main/play/listings/en-US/title.txt | 1 - .../play/listings/nl-NL/full-description.txt | 22 - .../play/listings/nl-NL/short-description.txt | 1 - .../src/main/play/listings/nl-NL/title.txt | 1 - .../res/drawable-hdpi/logo_ministerie.png | Bin 5087 -> 0 bytes .../src/main/res/drawable-hdpi/shield.png | Bin 1237 -> 0 bytes .../res/drawable-mdpi/logo_ministerie.png | Bin 2765 -> 0 bytes .../src/main/res/drawable-mdpi/shield.png | Bin 843 -> 0 bytes .../drawable-v24/ic_launcher_background.xml | 28 - .../res/drawable-xhdpi/logo_ministerie.png | Bin 7212 -> 0 bytes .../src/main/res/drawable-xhdpi/shield.png | Bin 1582 -> 0 bytes .../main/res/drawable-xxhdpi/ic_question.xml | 10 - .../res/drawable-xxhdpi/logo_ministerie.png | Bin 12175 -> 0 bytes .../src/main/res/drawable-xxhdpi/shield.png | Bin 2343 -> 0 bytes .../res/drawable-xxxhdpi/logo_ministerie.png | Bin 17921 -> 0 bytes .../src/main/res/drawable-xxxhdpi/shield.png | Bin 3228 -> 0 bytes verifier/src/main/res/drawable/ic_back.xml | 5 - verifier/src/main/res/drawable/ic_close.xml | 5 - .../src/main/res/drawable/ic_deeplink.xml | 10 - .../ic_illustration_launch_screen.xml | 42 -- verifier/src/main/res/drawable/ic_info.xml | 17 - .../res/drawable/ic_launcher_foreground.xml | 36 -- verifier/src/main/res/drawable/ic_menu.xml | 5 - .../src/main/res/drawable/ic_text_info.xml | 17 - .../drawable/illustration_launch_screen.xml | 18 - .../drawable/illustration_onboarding_1.xml | 510 ------------------ .../drawable/illustration_onboarding_2.xml | 254 --------- .../drawable/illustration_onboarding_3.xml | 418 -------------- .../drawable/illustration_onboarding_4.xml | 338 ------------ .../illustration_scan_result_invalid.xml | 10 - .../illustration_scan_result_valid.xml | 9 - .../illustration_scanner_get_started_1g.xml | 230 -------- .../illustration_scanner_get_started_3g.xml | 229 -------- .../drawable/personal_detail_background.xml | 12 - .../shape_personal_detail_background.xml | 6 - ...pe_personal_detail_disabled_background.xml | 5 - .../src/main/res/font/montserrat_bold.ttf | Bin 244468 -> 0 bytes .../src/main/res/font/montserrat_semibold.ttf | Bin 243816 -> 0 bytes .../src/main/res/layout/activity_main.xml | 19 - .../res/layout/fragment_about_this_app.xml | 20 - .../src/main/res/layout/fragment_main.xml | 43 -- .../res/layout/fragment_new_policy_rules.xml | 88 --- .../res/layout/fragment_scan_instructions.xml | 68 --- ...ragment_scan_instructions_with_toolbar.xml | 43 -- .../src/main/res/layout/fragment_scan_log.xml | 12 - .../src/main/res/layout/fragment_scan_qr.xml | 128 ----- .../layout/fragment_scan_result_invalid.xml | 92 ---- ...ent_scan_result_personal_details_wrong.xml | 64 --- .../res/layout/fragment_scan_result_valid.xml | 70 --- ...ent_scan_result_valid_personal_details.xml | 123 ----- .../fragment_verification_policy_info.xml | 126 ----- ...fragment_verification_policy_selection.xml | 203 ------- .../res/layout/item_scan_log_empty_list.xml | 38 -- .../item_scan_log_first_install_time.xml | 12 - .../main/res/layout/item_scan_log_header.xml | 13 - .../res/layout/item_scan_log_list_header.xml | 33 -- .../res/layout/item_scan_log_list_item.xml | 85 --- .../layout/personal_details_item_widget.xml | 41 -- .../layout/view_clock_deviation_warning.xml | 57 -- .../widget_scroll_view_policy_button.xml | 65 --- .../res/menu/scan_instructions_toolbar.xml | 15 - .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 - .../mipmap-anydpi-v26/ic_launcher_round.xml | 5 - .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 2708 -> 0 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 4231 -> 0 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 1964 -> 0 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 2785 -> 0 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 3624 -> 0 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 6015 -> 0 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 5538 -> 0 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 9363 -> 0 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 6943 -> 0 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 13436 -> 0 bytes .../navigation/verifier_nav_graph_main.xml | 255 --------- .../navigation/verifier_nav_graph_root.xml | 74 --- .../navigation/verifier_nav_graph_scanner.xml | 156 ------ verifier/src/main/res/raw/lock_1g_to_3g.json | 1 - verifier/src/main/res/raw/lock_3g_to_1g.json | 1 - .../src/main/res/raw/scaninstructions_1.json | 1 - .../src/main/res/raw/scaninstructions_2.json | 1 - .../src/main/res/raw/scaninstructions_3.json | 1 - .../src/main/res/raw/scaninstructions_4.json | 1 - .../src/main/res/raw/scaninstructions_5.json | 1 - verifier/src/main/res/values-en/strings.xml | 218 -------- .../src/main/res/values-sw600dp/dimens.xml | 4 - verifier/src/main/res/values-v31/themes.xml | 10 - verifier/src/main/res/values/arrays.xml | 17 - verifier/src/main/res/values/attrs.xml | 17 - verifier/src/main/res/values/dimens.xml | 7 - verifier/src/main/res/values/strings.xml | 218 -------- verifier/src/main/res/values/themes.xml | 25 - .../nl/rijksoverheid/ctr/verifier/Fakes.kt | 208 ------- .../ctr/verifier/TestVerifierApplication.kt | 22 - .../ctr/verifier/VerifierMainActivityTest.kt | 164 ------ .../VerifierMainActivityViewModelImplTest.kt | 56 -- .../InstructionsExplanationDataTest.kt | 52 -- .../ScanInstructionsButtonUtilImplTest.kt | 64 --- .../managers/DeeplinkManagerImplTest.kt | 80 --- .../database/VerifierDatabaseTest.kt | 104 ---- .../usecase/RandomKeyUseCaseImplTest.kt | 100 ---- ...ConfigVerificationPolicyUseCaseImplTest.kt | 166 ------ .../NewPolicyRulesItemUseCaseImplTest.kt | 44 -- .../policy/NewPolicyRulesViewModelImplTest.kt | 67 --- .../VerificationPolicyInfoFragmentTest.kt | 113 ---- ...VerificationPolicySelectionFragmentTest.kt | 242 --------- ...tionPolicySelectionStateUseCaseImplTest.kt | 67 --- ...icationPolicySelectionViewModelImplTest.kt | 42 -- .../VerificationPolicyUseCaseImplTest.kt | 62 --- .../scanlog/ScanLogViewModelImplTest.kt | 47 -- .../datamapper/ScanLogDataMapperImplTest.kt | 102 ---- ...FirstInstallTimeAdapterItemUtilImplTest.kt | 59 -- .../ScanLogListAdapterItemUtilImplTest.kt | 93 ---- .../repositories/ScanLogRepositoryImplTest.kt | 62 --- .../usecase/GetScanLogItemsUseCaseImplTest.kt | 132 ----- .../scanlog/usecase/LogScanUseCaseImplTest.kt | 43 -- .../usecase/ScanLogsCleanupUseCaseImplTest.kt | 60 --- .../scanner/ScanResultInvalidFragmentTest.kt | 100 ---- .../scanner/ScanResultValidFragmentTest.kt | 108 ---- .../scanner/ScannerViewModelImplTest.kt | 84 --- .../TestResultValidUseCaseImplTest.kt | 67 --- .../ctr/verifier/scanqr/ScanQrFragmentTest.kt | 256 --------- .../ScannerNavigationStateUseCaseImplTest.kt | 79 --- .../VerifierAppStatusUseCaseImplTest.kt | 424 --------------- .../VerifierFeatureFlagUseCaseImplTest.kt | 67 --- ...rifierIntroductionStatusUseCaseImplTest.kt | 40 -- .../src/test/resources/robolectric.properties | 5 - .../drawable-v24/ic_launcher_background.xml | 28 - .../src/tst/res/mipmap-hdpi/ic_launcher.png | Bin 4842 -> 0 bytes .../mipmap-hdpi/ic_launcher_background.png | Bin 3956 -> 0 bytes .../mipmap-hdpi/ic_launcher_foreground.png | Bin 6151 -> 0 bytes .../src/tst/res/mipmap-mdpi/ic_launcher.png | Bin 2765 -> 0 bytes .../mipmap-mdpi/ic_launcher_background.png | Bin 1955 -> 0 bytes .../mipmap-mdpi/ic_launcher_foreground.png | Bin 3610 -> 0 bytes .../src/tst/res/mipmap-xhdpi/ic_launcher.png | Bin 7230 -> 0 bytes .../mipmap-xhdpi/ic_launcher_background.png | Bin 6255 -> 0 bytes .../mipmap-xhdpi/ic_launcher_foreground.png | Bin 8868 -> 0 bytes .../src/tst/res/mipmap-xxhdpi/ic_launcher.png | Bin 12103 -> 0 bytes .../mipmap-xxhdpi/ic_launcher_background.png | Bin 15861 -> 0 bytes .../mipmap-xxhdpi/ic_launcher_foreground.png | Bin 18098 -> 0 bytes .../tst/res/mipmap-xxxhdpi/ic_launcher.png | Bin 18756 -> 0 bytes .../mipmap-xxxhdpi/ic_launcher_background.png | Bin 28338 -> 0 bytes .../mipmap-xxxhdpi/ic_launcher_foreground.png | Bin 28235 -> 0 bytes 294 files changed, 16633 deletions(-) delete mode 100644 holder/src/main/java/nl/rijksoverheid/ctr/holder/Bindings.kt delete mode 100644 holder/src/main/res/layout/adapter_item_dashboard_add_qr.xml delete mode 100644 holder/src/main/res/layout/adapter_item_dashboard_green_card.xml delete mode 100644 holder/src/main/res/layout/adapter_item_dashboard_green_card_placeholder.xml delete mode 100644 holder/src/main/res/layout/adapter_item_dashboard_header.xml delete mode 100644 holder/src/main/res/layout/adapter_item_dashboard_info_card.xml delete mode 100644 holder/src/main/res/layout/adapter_item_saved_event.xml delete mode 100644 holder/src/main/res/layout/adapter_item_saved_events_clear_data.xml delete mode 100644 holder/src/main/res/layout/adapter_item_saved_events_header.xml delete mode 100644 holder/src/main/res/layout/adapter_item_saved_events_no_saved_events.xml delete mode 100644 holder/src/main/res/layout/adapter_item_saved_events_section.xml delete mode 100644 holder/src/main/res/layout/fragment_certificate_created.xml delete mode 100644 holder/src/main/res/layout/fragment_choose_proof_type.xml delete mode 100644 holder/src/main/res/layout/fragment_choose_provider.xml delete mode 100644 holder/src/main/res/layout/fragment_could_not_create_qr.xml delete mode 100644 holder/src/main/res/layout/fragment_dashboard.xml delete mode 100644 holder/src/main/res/layout/fragment_dashboard_page.xml delete mode 100644 holder/src/main/res/layout/fragment_data_migration_scan_qr.xml delete mode 100644 holder/src/main/res/layout/fragment_data_migration_show_qr.xml delete mode 100644 holder/src/main/res/layout/fragment_data_migration_start_transferring.xml delete mode 100644 holder/src/main/res/layout/fragment_data_migration_transfer_options.xml delete mode 100644 holder/src/main/res/layout/fragment_export_introduction.xml delete mode 100644 holder/src/main/res/layout/fragment_get_events.xml delete mode 100644 holder/src/main/res/layout/fragment_holder_name_selection.xml delete mode 100644 holder/src/main/res/layout/fragment_input_token.xml delete mode 100644 holder/src/main/res/layout/fragment_no_digid.xml delete mode 100644 holder/src/main/res/layout/fragment_paper_proof_domestic_input_code.xml delete mode 100644 holder/src/main/res/layout/fragment_paper_proof_start_scanning.xml delete mode 100644 holder/src/main/res/layout/fragment_pdf_exported.xml delete mode 100644 holder/src/main/res/layout/fragment_pdf_preview.xml delete mode 100644 holder/src/main/res/layout/fragment_pdf_webview.xml delete mode 100644 holder/src/main/res/layout/fragment_qr_codes.xml delete mode 100644 holder/src/main/res/layout/fragment_saved_events.xml delete mode 100644 holder/src/main/res/layout/fragment_saved_events_sync_green_cards.xml delete mode 100644 holder/src/main/res/layout/fragment_your_event_explanation.xml delete mode 100644 holder/src/main/res/layout/fragment_your_events.xml delete mode 100644 holder/src/main/res/layout/include_content_button.xml delete mode 100644 holder/src/main/res/layout/include_loading_indicator.xml delete mode 100644 holder/src/main/res/layout/include_transfer_options_button.xml delete mode 100644 holder/src/main/res/layout/item_holder_name_selection_footer.xml delete mode 100644 holder/src/main/res/layout/item_holder_name_selection_header.xml delete mode 100644 holder/src/main/res/layout/item_holder_name_selection_view.xml delete mode 100644 holder/src/main/res/layout/item_paper_proof_explanation.xml delete mode 100644 holder/src/main/res/layout/item_your_event.xml delete mode 100644 holder/src/main/res/layout/view_qr_code.xml delete mode 100644 holder/src/main/res/layout/widget_qr_code_animation.xml delete mode 100644 holder/src/main/res/layout/your_event_explanation_item.xml delete mode 100644 verifier/.gitignore delete mode 100644 verifier/build.gradle delete mode 100644 verifier/consumer-rules.pro delete mode 100644 verifier/google-services.json delete mode 100644 verifier/proguard-rules.pro delete mode 100644 verifier/schemas/nl.rijksoverheid.ctr.verifier.persistance.database.VerifierDatabase/1.json delete mode 100644 verifier/src/acc/res/drawable-v24/ic_launcher_background.xml delete mode 100644 verifier/src/acc/res/mipmap-hdpi/ic_launcher.png delete mode 100644 verifier/src/acc/res/mipmap-hdpi/ic_launcher_round.png delete mode 100644 verifier/src/acc/res/mipmap-mdpi/ic_launcher.png delete mode 100644 verifier/src/acc/res/mipmap-mdpi/ic_launcher_round.png delete mode 100644 verifier/src/acc/res/mipmap-xhdpi/ic_launcher.png delete mode 100644 verifier/src/acc/res/mipmap-xhdpi/ic_launcher_round.png delete mode 100644 verifier/src/acc/res/mipmap-xxhdpi/ic_launcher.png delete mode 100644 verifier/src/acc/res/mipmap-xxhdpi/ic_launcher_round.png delete mode 100644 verifier/src/acc/res/mipmap-xxxhdpi/ic_launcher.png delete mode 100644 verifier/src/acc/res/mipmap-xxxhdpi/ic_launcher_round.png delete mode 100644 verifier/src/debug/AndroidManifest.xml delete mode 100644 verifier/src/debug/res/xml/network_config.xml delete mode 100644 verifier/src/main/AndroidManifest.xml delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/VerifierApplication.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/VerifierMainActivity.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/VerifierMainActivityViewModel.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/VerifierMainFragment.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/instructions/InstructionsExplanationData.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/instructions/ScanInstructionsButtonUtil.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/instructions/ScanInstructionsFragment.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/instructions/ScanInstructionsWithToolbarFragment.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/managers/DeeplinkManager.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/menu/MenuViewModel.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/models/ScannerState.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/models/VerifierStep.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/modules/ErrorsModule.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/modules/StorageModule.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/modules/VerifierAppStatusModule.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/modules/VerifierClmobileModule.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/modules/VerifierIntroductionModule.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/modules/VerifierMobileCoreModule.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/modules/VerifierModule.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/modules/VerifierPreferenceModule.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/persistance/PersistenceManager.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/persistance/database/VerifierDatabase.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/persistance/database/converters/VerifierDatabaseConverters.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/persistance/database/dao/ScanLogDao.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/persistance/database/entities/ScanLogEntity.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/persistance/usecase/RandomKeyUseCase.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/persistance/usecase/VerifierCachedConfigUseCase.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/policy/ConfigVerificationPolicyUseCase.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/policy/NewPolicyItem.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/policy/NewPolicyRulesFragment.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/policy/NewPolicyRulesItemUseCase.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/policy/NewPolicyRulesViewModel.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/policy/ScannerUsedRecentlyUseCase.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/policy/VerificationPolicyInfoFragment.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/policy/VerificationPolicySelectionFragment.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/policy/VerificationPolicySelectionState.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/policy/VerificationPolicySelectionStateUseCase.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/policy/VerificationPolicySelectionType.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/policy/VerificationPolicySelectionUseCase.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/policy/VerificationPolicySelectionViewModel.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/scanlog/ScanLogFragment.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/scanlog/ScanLogViewModel.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/scanlog/datamapper/ScanLogDataMapper.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/scanlog/items/ScanLogEmptyListAdapterItem.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/scanlog/items/ScanLogFirstInstallTimeAdapterItem.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/scanlog/items/ScanLogHeaderAdapterItem.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/scanlog/items/ScanLogItem.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/scanlog/items/ScanLogListAdapterItem.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/scanlog/items/ScanLogListHeaderAdapterItem.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/scanlog/items/util/ScanLogFirstInstallTimeAdapterItemUtil.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/scanlog/items/util/ScanLogListAdapterItemUtil.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/scanlog/models/ScanLog.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/scanlog/models/ScanLogBuilder.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/scanlog/repositories/ScanLogRepository.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/scanlog/usecase/GetScanLogItemsUseCase.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/scanlog/usecase/LogScanUseCase.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/scanlog/usecase/ScanLogsCleanupUseCase.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/scanner/ScanResultInvalidFragment.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/scanner/ScanResultPersonalDetailsFragment.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/scanner/ScanResultPersonalDetailsWrongFragment.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/scanner/ScanResultValidFragment.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/scanner/ScannerViewModel.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/scanner/VerifierQrScannerFragment.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/scanner/models/ScanResultInvalidData.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/scanner/models/ScanResultValidData.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/scanner/models/VerifiedQrResultState.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/scanner/usecases/TestResultValidUseCase.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/scanner/usecases/VerifyQrUseCase.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/scanner/utils/ScannerUtil.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/scanqr/ScanQrFragment.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/scanqr/ScanQrViewModel.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/scanqr/ScannerNavigationState.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/scanqr/ScannerNavigationStateUseCase.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/scanqr/ScannerStateCountDownTimer.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/scanqr/util/ScannerStateCountdownUtil.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/usecases/BuildConfigUseCaseImpl.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/usecases/ScannerStateUseCase.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/usecases/VerifierAppStatusUseCaseImpl.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/usecases/VerifierFeatureFlagUseCase.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/usecases/VerifierIntroductionStatusUseCase.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/widgets/PersonalDetailItemWidget.kt delete mode 100644 verifier/src/main/java/nl/rijksoverheid/ctr/verifier/widgets/ScrollViewPolicyButtonWidget.kt delete mode 100644 verifier/src/main/play/listings/en-US/full-description.txt delete mode 100644 verifier/src/main/play/listings/en-US/graphics/icon/icon.png delete mode 100644 verifier/src/main/play/listings/en-US/short-description.txt delete mode 100644 verifier/src/main/play/listings/en-US/title.txt delete mode 100644 verifier/src/main/play/listings/nl-NL/full-description.txt delete mode 100644 verifier/src/main/play/listings/nl-NL/short-description.txt delete mode 100644 verifier/src/main/play/listings/nl-NL/title.txt delete mode 100644 verifier/src/main/res/drawable-hdpi/logo_ministerie.png delete mode 100644 verifier/src/main/res/drawable-hdpi/shield.png delete mode 100644 verifier/src/main/res/drawable-mdpi/logo_ministerie.png delete mode 100644 verifier/src/main/res/drawable-mdpi/shield.png delete mode 100644 verifier/src/main/res/drawable-v24/ic_launcher_background.xml delete mode 100644 verifier/src/main/res/drawable-xhdpi/logo_ministerie.png delete mode 100644 verifier/src/main/res/drawable-xhdpi/shield.png delete mode 100644 verifier/src/main/res/drawable-xxhdpi/ic_question.xml delete mode 100644 verifier/src/main/res/drawable-xxhdpi/logo_ministerie.png delete mode 100644 verifier/src/main/res/drawable-xxhdpi/shield.png delete mode 100644 verifier/src/main/res/drawable-xxxhdpi/logo_ministerie.png delete mode 100644 verifier/src/main/res/drawable-xxxhdpi/shield.png delete mode 100644 verifier/src/main/res/drawable/ic_back.xml delete mode 100644 verifier/src/main/res/drawable/ic_close.xml delete mode 100644 verifier/src/main/res/drawable/ic_deeplink.xml delete mode 100644 verifier/src/main/res/drawable/ic_illustration_launch_screen.xml delete mode 100644 verifier/src/main/res/drawable/ic_info.xml delete mode 100644 verifier/src/main/res/drawable/ic_launcher_foreground.xml delete mode 100644 verifier/src/main/res/drawable/ic_menu.xml delete mode 100644 verifier/src/main/res/drawable/ic_text_info.xml delete mode 100644 verifier/src/main/res/drawable/illustration_launch_screen.xml delete mode 100644 verifier/src/main/res/drawable/illustration_onboarding_1.xml delete mode 100644 verifier/src/main/res/drawable/illustration_onboarding_2.xml delete mode 100644 verifier/src/main/res/drawable/illustration_onboarding_3.xml delete mode 100644 verifier/src/main/res/drawable/illustration_onboarding_4.xml delete mode 100644 verifier/src/main/res/drawable/illustration_scan_result_invalid.xml delete mode 100644 verifier/src/main/res/drawable/illustration_scan_result_valid.xml delete mode 100644 verifier/src/main/res/drawable/illustration_scanner_get_started_1g.xml delete mode 100644 verifier/src/main/res/drawable/illustration_scanner_get_started_3g.xml delete mode 100644 verifier/src/main/res/drawable/personal_detail_background.xml delete mode 100644 verifier/src/main/res/drawable/shape_personal_detail_background.xml delete mode 100644 verifier/src/main/res/drawable/shape_personal_detail_disabled_background.xml delete mode 100644 verifier/src/main/res/font/montserrat_bold.ttf delete mode 100644 verifier/src/main/res/font/montserrat_semibold.ttf delete mode 100644 verifier/src/main/res/layout/activity_main.xml delete mode 100644 verifier/src/main/res/layout/fragment_about_this_app.xml delete mode 100644 verifier/src/main/res/layout/fragment_main.xml delete mode 100644 verifier/src/main/res/layout/fragment_new_policy_rules.xml delete mode 100644 verifier/src/main/res/layout/fragment_scan_instructions.xml delete mode 100644 verifier/src/main/res/layout/fragment_scan_instructions_with_toolbar.xml delete mode 100644 verifier/src/main/res/layout/fragment_scan_log.xml delete mode 100644 verifier/src/main/res/layout/fragment_scan_qr.xml delete mode 100644 verifier/src/main/res/layout/fragment_scan_result_invalid.xml delete mode 100644 verifier/src/main/res/layout/fragment_scan_result_personal_details_wrong.xml delete mode 100644 verifier/src/main/res/layout/fragment_scan_result_valid.xml delete mode 100644 verifier/src/main/res/layout/fragment_scan_result_valid_personal_details.xml delete mode 100644 verifier/src/main/res/layout/fragment_verification_policy_info.xml delete mode 100644 verifier/src/main/res/layout/fragment_verification_policy_selection.xml delete mode 100644 verifier/src/main/res/layout/item_scan_log_empty_list.xml delete mode 100644 verifier/src/main/res/layout/item_scan_log_first_install_time.xml delete mode 100644 verifier/src/main/res/layout/item_scan_log_header.xml delete mode 100644 verifier/src/main/res/layout/item_scan_log_list_header.xml delete mode 100644 verifier/src/main/res/layout/item_scan_log_list_item.xml delete mode 100644 verifier/src/main/res/layout/personal_details_item_widget.xml delete mode 100644 verifier/src/main/res/layout/view_clock_deviation_warning.xml delete mode 100644 verifier/src/main/res/layout/widget_scroll_view_policy_button.xml delete mode 100644 verifier/src/main/res/menu/scan_instructions_toolbar.xml delete mode 100644 verifier/src/main/res/mipmap-anydpi-v26/ic_launcher.xml delete mode 100644 verifier/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml delete mode 100644 verifier/src/main/res/mipmap-hdpi/ic_launcher.png delete mode 100644 verifier/src/main/res/mipmap-hdpi/ic_launcher_round.png delete mode 100644 verifier/src/main/res/mipmap-mdpi/ic_launcher.png delete mode 100644 verifier/src/main/res/mipmap-mdpi/ic_launcher_round.png delete mode 100644 verifier/src/main/res/mipmap-xhdpi/ic_launcher.png delete mode 100644 verifier/src/main/res/mipmap-xhdpi/ic_launcher_round.png delete mode 100644 verifier/src/main/res/mipmap-xxhdpi/ic_launcher.png delete mode 100644 verifier/src/main/res/mipmap-xxhdpi/ic_launcher_round.png delete mode 100644 verifier/src/main/res/mipmap-xxxhdpi/ic_launcher.png delete mode 100644 verifier/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png delete mode 100644 verifier/src/main/res/navigation/verifier_nav_graph_main.xml delete mode 100644 verifier/src/main/res/navigation/verifier_nav_graph_root.xml delete mode 100644 verifier/src/main/res/navigation/verifier_nav_graph_scanner.xml delete mode 100644 verifier/src/main/res/raw/lock_1g_to_3g.json delete mode 100644 verifier/src/main/res/raw/lock_3g_to_1g.json delete mode 100644 verifier/src/main/res/raw/scaninstructions_1.json delete mode 100644 verifier/src/main/res/raw/scaninstructions_2.json delete mode 100644 verifier/src/main/res/raw/scaninstructions_3.json delete mode 100644 verifier/src/main/res/raw/scaninstructions_4.json delete mode 100644 verifier/src/main/res/raw/scaninstructions_5.json delete mode 100644 verifier/src/main/res/values-en/strings.xml delete mode 100644 verifier/src/main/res/values-sw600dp/dimens.xml delete mode 100644 verifier/src/main/res/values-v31/themes.xml delete mode 100644 verifier/src/main/res/values/arrays.xml delete mode 100644 verifier/src/main/res/values/attrs.xml delete mode 100644 verifier/src/main/res/values/dimens.xml delete mode 100644 verifier/src/main/res/values/strings.xml delete mode 100644 verifier/src/main/res/values/themes.xml delete mode 100644 verifier/src/test/java/nl/rijksoverheid/ctr/verifier/Fakes.kt delete mode 100644 verifier/src/test/java/nl/rijksoverheid/ctr/verifier/TestVerifierApplication.kt delete mode 100644 verifier/src/test/java/nl/rijksoverheid/ctr/verifier/VerifierMainActivityTest.kt delete mode 100644 verifier/src/test/java/nl/rijksoverheid/ctr/verifier/VerifierMainActivityViewModelImplTest.kt delete mode 100644 verifier/src/test/java/nl/rijksoverheid/ctr/verifier/instructions/InstructionsExplanationDataTest.kt delete mode 100644 verifier/src/test/java/nl/rijksoverheid/ctr/verifier/instructions/ScanInstructionsButtonUtilImplTest.kt delete mode 100644 verifier/src/test/java/nl/rijksoverheid/ctr/verifier/managers/DeeplinkManagerImplTest.kt delete mode 100644 verifier/src/test/java/nl/rijksoverheid/ctr/verifier/persistence/database/VerifierDatabaseTest.kt delete mode 100644 verifier/src/test/java/nl/rijksoverheid/ctr/verifier/persistence/usecase/RandomKeyUseCaseImplTest.kt delete mode 100644 verifier/src/test/java/nl/rijksoverheid/ctr/verifier/policy/ConfigVerificationPolicyUseCaseImplTest.kt delete mode 100644 verifier/src/test/java/nl/rijksoverheid/ctr/verifier/policy/NewPolicyRulesItemUseCaseImplTest.kt delete mode 100644 verifier/src/test/java/nl/rijksoverheid/ctr/verifier/policy/NewPolicyRulesViewModelImplTest.kt delete mode 100644 verifier/src/test/java/nl/rijksoverheid/ctr/verifier/policy/VerificationPolicyInfoFragmentTest.kt delete mode 100644 verifier/src/test/java/nl/rijksoverheid/ctr/verifier/policy/VerificationPolicySelectionFragmentTest.kt delete mode 100644 verifier/src/test/java/nl/rijksoverheid/ctr/verifier/policy/VerificationPolicySelectionStateUseCaseImplTest.kt delete mode 100644 verifier/src/test/java/nl/rijksoverheid/ctr/verifier/policy/VerificationPolicySelectionViewModelImplTest.kt delete mode 100644 verifier/src/test/java/nl/rijksoverheid/ctr/verifier/policy/VerificationPolicyUseCaseImplTest.kt delete mode 100644 verifier/src/test/java/nl/rijksoverheid/ctr/verifier/scanlog/ScanLogViewModelImplTest.kt delete mode 100644 verifier/src/test/java/nl/rijksoverheid/ctr/verifier/scanlog/datamapper/ScanLogDataMapperImplTest.kt delete mode 100644 verifier/src/test/java/nl/rijksoverheid/ctr/verifier/scanlog/items/util/ScanLogFirstInstallTimeAdapterItemUtilImplTest.kt delete mode 100644 verifier/src/test/java/nl/rijksoverheid/ctr/verifier/scanlog/items/util/ScanLogListAdapterItemUtilImplTest.kt delete mode 100644 verifier/src/test/java/nl/rijksoverheid/ctr/verifier/scanlog/repositories/ScanLogRepositoryImplTest.kt delete mode 100644 verifier/src/test/java/nl/rijksoverheid/ctr/verifier/scanlog/usecase/GetScanLogItemsUseCaseImplTest.kt delete mode 100644 verifier/src/test/java/nl/rijksoverheid/ctr/verifier/scanlog/usecase/LogScanUseCaseImplTest.kt delete mode 100644 verifier/src/test/java/nl/rijksoverheid/ctr/verifier/scanlog/usecase/ScanLogsCleanupUseCaseImplTest.kt delete mode 100644 verifier/src/test/java/nl/rijksoverheid/ctr/verifier/scanner/ScanResultInvalidFragmentTest.kt delete mode 100644 verifier/src/test/java/nl/rijksoverheid/ctr/verifier/scanner/ScanResultValidFragmentTest.kt delete mode 100644 verifier/src/test/java/nl/rijksoverheid/ctr/verifier/scanner/ScannerViewModelImplTest.kt delete mode 100644 verifier/src/test/java/nl/rijksoverheid/ctr/verifier/scanner/usecases/TestResultValidUseCaseImplTest.kt delete mode 100644 verifier/src/test/java/nl/rijksoverheid/ctr/verifier/scanqr/ScanQrFragmentTest.kt delete mode 100644 verifier/src/test/java/nl/rijksoverheid/ctr/verifier/scanqr/ScannerNavigationStateUseCaseImplTest.kt delete mode 100644 verifier/src/test/java/nl/rijksoverheid/ctr/verifier/usecases/VerifierAppStatusUseCaseImplTest.kt delete mode 100644 verifier/src/test/java/nl/rijksoverheid/ctr/verifier/usecases/VerifierFeatureFlagUseCaseImplTest.kt delete mode 100644 verifier/src/test/java/nl/rijksoverheid/ctr/verifier/usecases/VerifierIntroductionStatusUseCaseImplTest.kt delete mode 100644 verifier/src/test/resources/robolectric.properties delete mode 100644 verifier/src/tst/res/drawable-v24/ic_launcher_background.xml delete mode 100644 verifier/src/tst/res/mipmap-hdpi/ic_launcher.png delete mode 100644 verifier/src/tst/res/mipmap-hdpi/ic_launcher_background.png delete mode 100644 verifier/src/tst/res/mipmap-hdpi/ic_launcher_foreground.png delete mode 100644 verifier/src/tst/res/mipmap-mdpi/ic_launcher.png delete mode 100644 verifier/src/tst/res/mipmap-mdpi/ic_launcher_background.png delete mode 100644 verifier/src/tst/res/mipmap-mdpi/ic_launcher_foreground.png delete mode 100644 verifier/src/tst/res/mipmap-xhdpi/ic_launcher.png delete mode 100644 verifier/src/tst/res/mipmap-xhdpi/ic_launcher_background.png delete mode 100644 verifier/src/tst/res/mipmap-xhdpi/ic_launcher_foreground.png delete mode 100644 verifier/src/tst/res/mipmap-xxhdpi/ic_launcher.png delete mode 100644 verifier/src/tst/res/mipmap-xxhdpi/ic_launcher_background.png delete mode 100644 verifier/src/tst/res/mipmap-xxhdpi/ic_launcher_foreground.png delete mode 100644 verifier/src/tst/res/mipmap-xxxhdpi/ic_launcher.png delete mode 100644 verifier/src/tst/res/mipmap-xxxhdpi/ic_launcher_background.png delete mode 100644 verifier/src/tst/res/mipmap-xxxhdpi/ic_launcher_foreground.png diff --git a/holder/src/main/java/nl/rijksoverheid/ctr/holder/Bindings.kt b/holder/src/main/java/nl/rijksoverheid/ctr/holder/Bindings.kt deleted file mode 100644 index 7acb385d5..000000000 --- a/holder/src/main/java/nl/rijksoverheid/ctr/holder/Bindings.kt +++ /dev/null @@ -1,62 +0,0 @@ -package nl.rijksoverheid.ctr.holder.ui.create_qr - -import android.view.View -import androidx.annotation.DrawableRes -import androidx.annotation.StringRes -import nl.rijksoverheid.ctr.holder.R -import nl.rijksoverheid.ctr.holder.databinding.IncludeContentButtonBinding -import nl.rijksoverheid.ctr.holder.databinding.ItemPaperProofExplanationBinding -import nl.rijksoverheid.ctr.shared.utils.Accessibility - -/* - * Copyright (c) 2021 De Staat der Nederlanden, Ministerie van Volksgezondheid, Welzijn en Sport. - * Licensed under the EUROPEAN UNION PUBLIC LICENCE v. 1.2 - * - * SPDX-License-Identifier: EUPL-1.2 - * - */ -fun IncludeContentButtonBinding.bind( - @StringRes title: Int, - subtitle: String?, - @DrawableRes logo: Int? = null, - onClick: () -> Unit -) { - providerTitle.setText(title) - providerSubtitle.text = subtitle - - if (subtitle.isNullOrEmpty()) { - providerSubtitle.visibility = View.GONE - providerTitle.setPadding( - providerTitle.paddingLeft, - providerTitle.context.resources.getDimensionPixelSize(R.dimen.test_provider_title_without_subtitle_padding), - providerTitle.paddingRight, - providerTitle.context.resources.getDimensionPixelSize(R.dimen.test_provider_title_without_subtitle_padding) - ) - root.contentDescription = providerTitle.text - logo?.let { providerTitle.setCompoundDrawablesWithIntrinsicBounds(0, 0, it, 0) } - } else { - root.contentDescription = String.format("%s. %s", providerTitle.text, providerSubtitle.text) - logo?.let { providerSubtitle.setCompoundDrawablesWithIntrinsicBounds(0, 0, it, 0) } - } - - Accessibility.button(root) - - root.setOnClickListener { - onClick() - } -} - -fun IncludeContentButtonBinding.setEnabled(enabled: Boolean) { - root.isClickable = enabled - root.isEnabled = enabled -} - -fun ItemPaperProofExplanationBinding.bind( - @DrawableRes icon: Int, - @StringRes title: Int, - @StringRes subtitle: Int -) { - iconView.setImageResource(icon) - titleView.setText(title) - subtitleView.setText(subtitle) -} diff --git a/holder/src/main/res/layout/adapter_item_dashboard_add_qr.xml b/holder/src/main/res/layout/adapter_item_dashboard_add_qr.xml deleted file mode 100644 index a4049ad48..000000000 --- a/holder/src/main/res/layout/adapter_item_dashboard_add_qr.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - diff --git a/holder/src/main/res/layout/adapter_item_dashboard_green_card.xml b/holder/src/main/res/layout/adapter_item_dashboard_green_card.xml deleted file mode 100644 index f50b6d6f0..000000000 --- a/holder/src/main/res/layout/adapter_item_dashboard_green_card.xml +++ /dev/null @@ -1,202 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/holder/src/main/res/layout/adapter_item_dashboard_green_card_placeholder.xml b/holder/src/main/res/layout/adapter_item_dashboard_green_card_placeholder.xml deleted file mode 100644 index b0c189671..000000000 --- a/holder/src/main/res/layout/adapter_item_dashboard_green_card_placeholder.xml +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - - - diff --git a/holder/src/main/res/layout/adapter_item_dashboard_header.xml b/holder/src/main/res/layout/adapter_item_dashboard_header.xml deleted file mode 100644 index ad9400156..000000000 --- a/holder/src/main/res/layout/adapter_item_dashboard_header.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/holder/src/main/res/layout/adapter_item_dashboard_info_card.xml b/holder/src/main/res/layout/adapter_item_dashboard_info_card.xml deleted file mode 100644 index 8e347194c..000000000 --- a/holder/src/main/res/layout/adapter_item_dashboard_info_card.xml +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - -