Skip to content
This repository has been archived by the owner on Jun 20, 2023. It is now read-only.

Interoperability Onboarding and Information (EXPOSUREAPP-2730, EXPOSUREAPP-2733) #1202

Merged
merged 47 commits into from
Sep 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
5539b60
Import flag assets. Create init CountrySelectionList and Fragment
mertsafter Sep 4, 2020
402247e
Implement missing components. Create ViewModel and Repository for Int…
mertsafter Sep 8, 2020
93d35df
fix wrong property usage
mertsafter Sep 8, 2020
246a43a
Implement storage of selected countries
mertsafter Sep 8, 2020
e1fcbb5
Implement warn dialog
mertsafter Sep 9, 2020
0d4187a
Added navigation from country selection to tracing fragment
Sep 9, 2020
2752409
Fixed lint errors
Sep 9, 2020
c2ec023
Fix typo and build error
mertsafter Sep 10, 2020
464e46f
Merge branch 'feature/interoperability-eu' into feature/interoperabil…
mertsafter Sep 10, 2020
9df2c1d
Move navigation out of onResume
mertsafter Sep 10, 2020
9fc13fe
Implement Warning dialog and do some code cleanup
mertsafter Sep 10, 2020
29acf9d
Begin of onboarding for Interoperability. Fix linting issues
mertsafter Sep 10, 2020
e95d0ba
Implement onboarding for Interoperability (#1976)
mertsafter Sep 11, 2020
97b53d9
Implement skip path of interop screen in onboarding (#1976)
mertsafter Sep 11, 2020
f607aae
Implement navigation logic for onBoarding (#1976)
mertsafter Sep 14, 2020
7a27f45
Fix linting issues
mertsafter Sep 14, 2020
2d86cb7
Adjust country list and view to new UI (#2667)
mertsafter Sep 17, 2020
693c61d
Merge OnboardingTracingFragment with country list (#2665)
mertsafter Sep 17, 2020
bae450d
UI adjustments (#2665)
mertsafter Sep 17, 2020
8ae9fc3
Fix linting issues
mertsafter Sep 17, 2020
d24f6f4
Implement Delta Onboarding logic (#2665)
mertsafter Sep 21, 2020
7142853
Adjust interoperability screens to new UI (#2730, #2733)
mertsafter Sep 21, 2020
b48abf5
Added navigation from country selection to tracing fragment
Sep 9, 2020
4772b74
Fix merge issues with interoperability branch
mertsafter Sep 21, 2020
317c495
Fix merge issues with interoperability branch
mertsafter Sep 21, 2020
7bfca87
Merge remote-tracking branch 'origin/release/1.5.x' into feature/2667…
mertsafter Sep 21, 2020
2c95d47
Fix merge changes with 1.5.x branch
mertsafter Sep 21, 2020
0b43657
Remove unused Formatter
mertsafter Sep 21, 2020
c9371f3
Remove import of unused Formatter
mertsafter Sep 21, 2020
f84857f
Remove import of unused Formatter
mertsafter Sep 21, 2020
d35598d
Fix linting issue
mertsafter Sep 22, 2020
164a562
Adjust UI to mock changes (#2730)
mertsafter Sep 22, 2020
6b6dcc4
Adjust fragment binding to new solution and code cleanup
mertsafter Sep 22, 2020
a46242e
Adjust layout ids to guidelines. Comment strings.xml
mertsafter Sep 22, 2020
f9570bc
Moved back navigation event to ViewModel
mertsafter Sep 22, 2020
459b25c
Move to DI and ViewModel navigation
mertsafter Sep 23, 2020
a5d94e8
Improve accessibility
mertsafter Sep 23, 2020
ea8b08a
Improve accessibility
mertsafter Sep 23, 2020
89d49c7
Merge branch 'release/1.5.x' into feature/2667-2665-interoperability
mertsafter Sep 23, 2020
9b875ff
Adjusted UI to updated mockups. Clean-Up of InteroperabilityRepositor…
mertsafter Sep 23, 2020
ec2038b
Refactoring and ViewModel use.
d4rken Sep 23, 2020
305e5a3
Make detekt happy.
d4rken Sep 23, 2020
97c5d8c
Fix PR comments, typos, inline getString.
d4rken Sep 23, 2020
ec26193
Merge branch 'release/1.5.x' into feature/2667-2665-interoperability
d4rken Sep 23, 2020
31cf631
Fix refactoring typo
d4rken Sep 23, 2020
c0217d4
Merge remote-tracking branch 'origin/feature/2667-2665-interoperabili…
d4rken Sep 23, 2020
0703544
Merge branch 'release/1.5.x' into feature/2667-2665-interoperability
d4rken Sep 23, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import kotlinx.coroutines.withContext
* @see PopupMenu
*/
class MainFragment : Fragment(R.layout.fragment_main) {

private val tracingViewModel: TracingViewModel by activityViewModels()
private val settingsViewModel: SettingsViewModel by activityViewModels()
private val submissionViewModel: SubmissionViewModel by activityViewModels()
Expand All @@ -45,11 +46,10 @@ class MainFragment : Fragment(R.layout.fragment_main) {
binding.tracingViewModel = tracingViewModel
binding.settingsViewModel = settingsViewModel
binding.submissionViewModel = submissionViewModel
binding.lifecycleOwner = this

setButtonOnClickListener()
setContentDescription()

checkShouldInteroperabilityBeOpened()
showOneTimeTracingExplanationDialog()
}

Expand Down Expand Up @@ -159,6 +159,18 @@ class MainFragment : Fragment(R.layout.fragment_main) {
popup.show()
}

private fun checkShouldInteroperabilityBeOpened() {
if (!LocalData.isInteroperabilityShownAtLeastOnce) {
navigateToInteroperabilityFeature()
}
}

private fun navigateToInteroperabilityFeature() {
findNavController().doNavigate(
MainFragmentDirections.actionMainFragmentToOnboardingDeltaInteroperabilityFragment()
)
}

private fun showOneTimeTracingExplanationDialog() {

// check if the dialog explaining the tracing time was already shown
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ class MainFragment : Fragment(R.layout.fragment_main) {
binding.submissionViewModel = submissionViewModel

setButtonOnClickListener()

setContentDescription()
checkShouldInteroperabilityBeOpened()
showOneTimeTracingExplanationDialog()
}

Expand All @@ -66,9 +67,10 @@ class MainFragment : Fragment(R.layout.fragment_main) {
binding.mainScrollview.sendAccessibilityEvent(AccessibilityEvent.TYPE_ANNOUNCEMENT)
}

override fun onStart() {
super.onStart()
binding.mainScrollview.sendAccessibilityEvent(AccessibilityEvent.TYPE_ANNOUNCEMENT)
private fun setContentDescription() {
binding.mainHeaderShare.buttonIcon.contentDescription = getString(R.string.button_share)
binding.mainHeaderOptionsMenu.buttonIcon.contentDescription = getString(R.string.button_menu)
binding.mainAbout.mainCard.contentDescription = getString(R.string.hint_external_webpage)
}

private fun setButtonOnClickListener() {
Expand Down Expand Up @@ -168,6 +170,18 @@ class MainFragment : Fragment(R.layout.fragment_main) {
popup.show()
}

private fun checkShouldInteroperabilityBeOpened() {
if (!LocalData.isInteroperabilityShownAtLeastOnce) {
navigateToInteroperabilityFeature()
}
}

private fun navigateToInteroperabilityFeature() {
findNavController().doNavigate(
MainFragmentDirections.actionMainFragmentToOnboardingDeltaInteroperabilityFragment()
)
}

private fun showOneTimeTracingExplanationDialog() {

// check if the dialog explaining the tracing time was already shown
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@
<action
android:id="@+id/action_mainFragment_to_testRiskLevelCalculation"
app:destination="@id/testRiskLevelCalculation" />
<action
android:id="@+id/action_mainFragment_to_onboardingDeltaInteroperabilityFragment"
app:destination="@id/onboardingDeltaInteroperabilityFragment" />
</fragment>

<fragment
Expand Down Expand Up @@ -85,7 +88,26 @@
android:id="@+id/settingsTracingFragment"
android:name="de.rki.coronawarnapp.ui.settings.SettingsTracingFragment"
android:label="@layout/fragment_settings_tracing"
tools:layout="@layout/fragment_settings_tracing" />
tools:layout="@layout/fragment_settings_tracing">
<action
android:id="@+id/action_settingsTracingFragment_to_interopCountryConfigurationFragment"
app:destination="@id/interopCountryConfigurationFragment" />
</fragment>

<fragment
android:id="@+id/onboardingDeltaInteroperabilityFragment"
android:name="de.rki.coronawarnapp.ui.onboarding.OnboardingDeltaInteroperabilityFragment"
android:label="OnboardingDeltaInteroperabilityFragment" />

<fragment
android:id="@+id/interopCountryConfigurationFragment"
android:name="de.rki.coronawarnapp.ui.interoperability.InteroperabilityConfigurationFragment"
android:label="InteropCountryConfigurationFragment"
tools:layout="@layout/fragment_interoperability_configuration">
<action
android:id="@+id/action_interopCountryConfigurationFragment_to_settingTracingFragment"
app:destination="@id/settingsTracingFragment" />
</fragment>

<fragment
android:id="@+id/settingsNotificationFragment"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ object ApplicationConfigurationService {
.clearSupportedCountries()
.addAllSupportedCountries(
listOf(
"DE", "UK", "FR", "IT", "SP", "PL", "RO", "NL",
"BE", "CZ", "EL", "SE", "PT", "HU", "AT", "CH", "BG", "DK", "FI", "SK",
"DE", "UK", "FR", "IT", "ES", "PL", "RO", "NL",
"BE", "CZ", "SE", "PT", "HU", "AT", "CH", "BG", "DK", "FI", "SK",
"NO", "IE", "HR", "SI", "LT", "LV", "EE", "CY", "LU", "MT", "IS"
)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ object LocalData {
private const val PREFERENCE_GOOGLE_API_PROVIDE_DIAGNOSIS_KEYS_CALL_COUNT =
"preference_google_api_provide_diagnosis_keys_call_count"

private const val PREFERENCE_INTEROPERABILITY_IS_USED_AT_LEAST_ONCE =
"preference_interoperability_is_used_at_least_once"

/****************************************************
* ONBOARDING DATA
****************************************************/
Expand Down Expand Up @@ -750,4 +753,21 @@ object LocalData {
****************************************************/

fun getSharedPreferenceInstance(): SharedPreferences = globalEncryptedSharedPreferencesInstance

/****************************************************
* INTEROPERABILITY
****************************************************/

var isInteroperabilityShownAtLeastOnce: Boolean
get() {
return getSharedPreferenceInstance().getBoolean(
PREFERENCE_INTEROPERABILITY_IS_USED_AT_LEAST_ONCE,
false
)
}
set(value) {
getSharedPreferenceInstance().edit {
putBoolean(PREFERENCE_INTEROPERABILITY_IS_USED_AT_LEAST_ONCE, value)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package de.rki.coronawarnapp.storage.interoperability

import de.rki.coronawarnapp.service.applicationconfiguration.ApplicationConfigurationService
import de.rki.coronawarnapp.storage.LocalData
import kotlinx.coroutines.runBlocking
import java.util.Locale
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class InteroperabilityRepository @Inject constructor() {

fun saveInteroperabilityUsed() {
LocalData.isInteroperabilityShownAtLeastOnce = true
}

/**
* Gets all countries from @see ApplicationConfigurationService.asyncRetrieveApplicationConfiguration
* Also changes every country code to lower case
*/
fun getAllCountries(): List<String> {
return runBlocking {
ApplicationConfigurationService.asyncRetrieveApplicationConfiguration()
.supportedCountriesList
?.map { it.toLowerCase(Locale.ROOT) } ?: listOf()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package de.rki.coronawarnapp.ui.interoperability

import android.os.Bundle
import android.view.View
import androidx.fragment.app.Fragment
import de.rki.coronawarnapp.R
import de.rki.coronawarnapp.databinding.FragmentInteroperabilityConfigurationBinding
import de.rki.coronawarnapp.ui.main.MainActivity
import de.rki.coronawarnapp.util.di.AutoInject
import de.rki.coronawarnapp.util.ui.observe2
import de.rki.coronawarnapp.util.ui.viewBindingLazy
import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider
import de.rki.coronawarnapp.util.viewmodel.cwaViewModels
import javax.inject.Inject

class InteroperabilityConfigurationFragment :
Fragment(R.layout.fragment_interoperability_configuration), AutoInject {

@Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory
private val vm: InteroperabilityConfigurationFragmentViewModel by cwaViewModels { viewModelFactory }

private val binding: FragmentInteroperabilityConfigurationBinding by viewBindingLazy()

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

vm.countryList.observe2(this) {
binding.countryData = it
}

vm.saveInteroperabilityUsed()

binding.interoperabilityConfigurationHeader.headerButtonBack.buttonIcon.setOnClickListener {
vm.onBackPressed()
}

vm.navigateBack.observe2(this) {
if (it) {
(requireActivity() as MainActivity).goBack()
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package de.rki.coronawarnapp.ui.interoperability

import dagger.Binds
import dagger.Module
import dagger.multibindings.IntoMap
import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory
import de.rki.coronawarnapp.util.viewmodel.CWAViewModelKey

@Module
abstract class InteroperabilityConfigurationFragmentModule {
@Binds
@IntoMap
@CWAViewModelKey(InteroperabilityConfigurationFragmentViewModel::class)
abstract fun testRiskLevelFragment(
factory: InteroperabilityConfigurationFragmentViewModel.Factory
): CWAViewModelFactory<out CWAViewModel>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package de.rki.coronawarnapp.ui.interoperability

import androidx.lifecycle.MutableLiveData
import com.squareup.inject.assisted.AssistedInject
import de.rki.coronawarnapp.storage.interoperability.InteroperabilityRepository
import de.rki.coronawarnapp.util.ui.SingleLiveEvent
import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory

class InteroperabilityConfigurationFragmentViewModel @AssistedInject constructor(
private val interoperabilityRepository: InteroperabilityRepository
) : CWAViewModel() {

val countryList = MutableLiveData(interoperabilityRepository.getAllCountries())
val navigateBack = SingleLiveEvent<Boolean>()

fun onBackPressed() {
navigateBack.postValue(true)
}

fun saveInteroperabilityUsed() {
interoperabilityRepository.saveInteroperabilityUsed()
}

@AssistedInject.Factory
interface Factory : SimpleCWAViewModelFactory<InteroperabilityConfigurationFragmentViewModel>
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
package de.rki.coronawarnapp.ui.main

import dagger.Module
import dagger.android.ContributesAndroidInjector
import de.rki.coronawarnapp.ui.interoperability.InteroperabilityConfigurationFragment
import de.rki.coronawarnapp.ui.interoperability.InteroperabilityConfigurationFragmentModule
import de.rki.coronawarnapp.ui.onboarding.OnboardingDeltaInteroperabilityModule

@Module
@Module(includes = [OnboardingDeltaInteroperabilityModule::class])
abstract class MainActivityModule {

// activity specific injection module for future dependencies

// example:
// @ContributesAndroidInjector
// abstract fun mainFragment(): MainFragment

@ContributesAndroidInjector(modules = [InteroperabilityConfigurationFragmentModule::class])
abstract fun intertopConfigScreen(): InteroperabilityConfigurationFragment
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,21 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.LifecycleObserver
import dagger.android.AndroidInjector
import dagger.android.DispatchingAndroidInjector
import dagger.android.HasAndroidInjector
import de.rki.coronawarnapp.R
import de.rki.coronawarnapp.storage.LocalData
import de.rki.coronawarnapp.ui.main.MainActivity
import de.rki.coronawarnapp.util.di.AppInjector
import javax.inject.Inject

/**
* This activity holds all the onboarding fragments and isn't used after a successful onboarding flow.
*
* @see LocalData
*/
class OnboardingActivity : AppCompatActivity(), LifecycleObserver {
class OnboardingActivity : AppCompatActivity(), LifecycleObserver, HasAndroidInjector {
companion object {
private val TAG: String? = OnboardingActivity::class.simpleName

Expand All @@ -27,6 +31,9 @@ class OnboardingActivity : AppCompatActivity(), LifecycleObserver {
}
}

@Inject lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Any>
override fun androidInjector(): AndroidInjector<Any> = dispatchingAndroidInjector

private val FragmentManager.currentNavigationFragment: Fragment?
get() = primaryNavigationFragment?.childFragmentManager?.fragments?.first()

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package de.rki.coronawarnapp.ui.onboarding

import dagger.Module
import dagger.android.ContributesAndroidInjector

@Module
internal abstract class OnboardingActivityModule {
Expand All @@ -10,4 +11,7 @@ internal abstract class OnboardingActivityModule {
// example:
// @ContributesAndroidInjector
// abstract fun onboardingFragment(): OnboardingFragment

@ContributesAndroidInjector(modules = [OnboardingTracingModule::class])
abstract fun onboardingScreen(): OnboardingTracingFragment
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package de.rki.coronawarnapp.ui.onboarding

import android.os.Bundle
import android.view.View
import androidx.fragment.app.Fragment
import de.rki.coronawarnapp.R
import de.rki.coronawarnapp.databinding.FragmentOnboardingDeltaInteroperabilityBinding
import de.rki.coronawarnapp.ui.main.MainActivity
import de.rki.coronawarnapp.util.di.AutoInject
import de.rki.coronawarnapp.util.ui.observe2
import de.rki.coronawarnapp.util.ui.viewBindingLazy
import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider
import de.rki.coronawarnapp.util.viewmodel.cwaViewModels
import javax.inject.Inject

class OnboardingDeltaInteroperabilityFragment :
Fragment(R.layout.fragment_onboarding_delta_interoperability), AutoInject {

@Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory
private val vm: OnboardingDeltaInteroperabilityFragmentViewModel by cwaViewModels { viewModelFactory }

private val binding: FragmentOnboardingDeltaInteroperabilityBinding by viewBindingLazy()

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
vm.countryList.observe2(this) {
binding.countryData = it
}
vm.saveInteroperabilityUsed()

binding.onboardingButtonBack.buttonIcon.setOnClickListener {
vm.onBackPressed()
}
binding.onboardingButtonNext.setOnClickListener {
vm.onBackPressed()
}

vm.navigateBack.observe2(this) {
if (it) {
(requireActivity() as MainActivity).goBack()
}
}
}
}
Loading