From bbe460079b6d2315577e675d15fa18107d3541d8 Mon Sep 17 00:00:00 2001 From: Mohamed Metwalli <mohamed.metwalli@sap.com> Date: Wed, 3 Feb 2021 12:54:05 +0100 Subject: [PATCH] Add Tab bar (EXPOSUREAPP-4639) (#2235) * Add bottom bar * Fix di * Adjust theme * Align content on top of bottom bar * Enhance findNavController * Adjust Bottom Bar * Remove diary card * Remove up button * lint * Adapt MD theme * Fix ui tests * Delete contact diary , handle onboarding * Remove x button * Show bottom nav only for Home and contact diary destinations * Only contact diary overview screen * Adjust alert dialog theme * update docs * Fix close button issue * Revert close button changes * Rename text resources * Make visibility logic flexible for future additions * Fix typo * Contact diary onboarding's bottom bar behaviour * Update ContactDiaryOnboardingFragmentTest.kt * Update Corona-Warn-App/src/main/res/values/strings.xml Co-authored-by: Sabine Loss <44154356+SabineLoss@users.noreply.github.com> * Update contact_diary_overview_fragment.xml * Small refactoring * Remove un required gravity * Use accent colour * Move diary settings into vm * Update MainActivityViewModelTest.kt * Fix styling in bottom sheet dialog Co-authored-by: Sabine Loss <44154356+SabineLoss@users.noreply.github.com> Co-authored-by: harambasicluka <64483219+harambasicluka@users.noreply.github.com> --- .../ContactDiaryDayFragmentTest.kt | 4 +- .../ContactDiaryOnboardingFragmentTest.kt | 9 ++- .../ui/main/home/HomeFragmentTest.kt | 2 - .../ui/statistics/StatisticsCardsTest.kt | 2 - Corona-Warn-App/src/main/AndroidManifest.xml | 19 ++---- .../contactdiary/ContactDiaryRootModule.kt | 19 ------ .../contactdiary/ui/ContactDiaryActivity.kt | 63 ------------------- .../contactdiary/ui/ContactDiarySettings.kt | 2 + .../ContactDiaryOnboardingFragment.kt | 12 +++- .../overview/ContactDiaryOverviewFragment.kt | 2 +- .../de/rki/coronawarnapp/ui/ActivityBinder.kt | 18 +++++- .../de/rki/coronawarnapp/ui/UIExtensions.kt | 52 +++++++++++++++ .../rki/coronawarnapp/ui/main/MainActivity.kt | 28 ++++++++- .../ui/main/MainActivityViewModel.kt | 9 ++- .../coronawarnapp/ui/main/home/HomeAdapter.kt | 2 - .../ui/main/home/HomeFragment.kt | 23 +++---- .../ui/main/home/HomeFragmentEvents.kt | 2 - .../ui/main/home/HomeFragmentViewModel.kt | 3 - .../ui/main/home/items/DiaryCard.kt | 38 ----------- .../util/di/ApplicationComponent.kt | 2 - .../util/ui/FragmentExtensions.kt | 18 ++++++ .../src/main/res/color/nav_item_color.xml | 5 ++ .../src/main/res/drawable/ic_nav_diary.xml | 9 +++ .../src/main/res/drawable/ic_nav_home.xml | 10 +++ .../src/main/res/layout/activity_main.xml | 33 ++++++++-- .../res/layout/contact_diary_activity.xml | 16 ----- .../contact_diary_onboarding_fragment.xml | 1 - .../contact_diary_overview_fragment.xml | 18 +----- .../src/main/res/menu/menu_bottom_nav.xml | 13 ++++ .../navigation/contact_diary_nav_graph.xml | 4 ++ .../src/main/res/navigation/nav_graph.xml | 9 ++- .../src/main/res/values-de/strings.xml | 5 +- .../src/main/res/values/colors.xml | 4 ++ .../src/main/res/values/strings.xml | 4 ++ .../src/main/res/values/styles.xml | 46 ++++++-------- .../main/MainActivityViewModelTest.kt | 26 +++++++- 36 files changed, 286 insertions(+), 246 deletions(-) delete mode 100644 Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ContactDiaryRootModule.kt delete mode 100644 Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/ContactDiaryActivity.kt delete mode 100644 Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/items/DiaryCard.kt create mode 100644 Corona-Warn-App/src/main/res/color/nav_item_color.xml create mode 100644 Corona-Warn-App/src/main/res/drawable/ic_nav_diary.xml create mode 100644 Corona-Warn-App/src/main/res/drawable/ic_nav_home.xml delete mode 100644 Corona-Warn-App/src/main/res/layout/contact_diary_activity.xml create mode 100644 Corona-Warn-App/src/main/res/menu/menu_bottom_nav.xml diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/contactdiary/ContactDiaryDayFragmentTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/contactdiary/ContactDiaryDayFragmentTest.kt index 584cdf3f7..9f87c005e 100644 --- a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/contactdiary/ContactDiaryDayFragmentTest.kt +++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/contactdiary/ContactDiaryDayFragmentTest.kt @@ -87,7 +87,7 @@ class ContactDiaryDayFragmentTest : BaseUITest() { fun launch_fragment() { launchFragment2<ContactDiaryDayFragment>( fragmentArgs = fragmentArgs, - themeResId = R.style.AppTheme_ContactDiary + themeResId = R.style.AppTheme_Main ) } @@ -113,7 +113,7 @@ class ContactDiaryDayFragmentTest : BaseUITest() { launchFragmentInContainer2<ContactDiaryDayFragment>( fragmentArgs = fragmentArgs, - themeResId = R.style.AppTheme_ContactDiary + themeResId = R.style.AppTheme_Main ) Thread.sleep(SCREENSHOT_DELAY_TIME) Screengrab.screenshot(ContactDiaryDayFragment::class.simpleName.plus("_$suffix")) diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/contactdiary/ContactDiaryOnboardingFragmentTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/contactdiary/ContactDiaryOnboardingFragmentTest.kt index 62bd3621a..8f39f59ba 100644 --- a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/contactdiary/ContactDiaryOnboardingFragmentTest.kt +++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/contactdiary/ContactDiaryOnboardingFragmentTest.kt @@ -4,6 +4,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import dagger.Module import dagger.android.ContributesAndroidInjector import de.rki.coronawarnapp.contactdiary.ui.onboarding.ContactDiaryOnboardingFragment +import de.rki.coronawarnapp.contactdiary.ui.onboarding.ContactDiaryOnboardingFragmentArgs import de.rki.coronawarnapp.contactdiary.ui.onboarding.ContactDiaryOnboardingFragmentViewModel import io.mockk.MockKAnnotations import io.mockk.unmockkAll @@ -30,6 +31,10 @@ class ContactDiaryOnboardingFragmentTest : BaseUITest() { @get:Rule val systemUIDemoModeRule = SystemUIDemoModeRule() + private val fragmentArgs = ContactDiaryOnboardingFragmentArgs( + showBottomNav = false + ).toBundle() + @Before fun setup() { MockKAnnotations.init(this, relaxed = true) @@ -50,13 +55,13 @@ class ContactDiaryOnboardingFragmentTest : BaseUITest() { @Test fun launch_fragment() { - launchFragment2<ContactDiaryOnboardingFragment>() + launchFragment2<ContactDiaryOnboardingFragment>(fragmentArgs) } @Screenshot @Test fun capture_screenshot() { - launchFragmentInContainer2<ContactDiaryOnboardingFragment>() + launchFragmentInContainer2<ContactDiaryOnboardingFragment>(fragmentArgs) Thread.sleep(SCREENSHOT_DELAY_TIME) Screengrab.screenshot(ContactDiaryOnboardingFragment::class.simpleName) } diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentTest.kt index a16a8dbe7..0ac8a2958 100644 --- a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentTest.kt +++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentTest.kt @@ -22,7 +22,6 @@ import de.rki.coronawarnapp.tracing.GeneralTracingStatus import de.rki.coronawarnapp.tracing.states.TracingStateProvider import de.rki.coronawarnapp.tracing.ui.homecards.TracingStateItem import de.rki.coronawarnapp.tracing.ui.statusbar.TracingHeaderState -import de.rki.coronawarnapp.ui.main.home.items.DiaryCard import de.rki.coronawarnapp.ui.main.home.items.FAQCard import de.rki.coronawarnapp.ui.main.home.items.HomeItem import de.rki.coronawarnapp.util.security.EncryptionErrorResetTool @@ -242,7 +241,6 @@ class HomeFragmentTest : BaseUITest() { } add(submissionTestResultItem) - add(DiaryCard.Item {}) add(FAQCard.Item {}) } ) diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/statistics/StatisticsCardsTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/statistics/StatisticsCardsTest.kt index 5d9afd0ba..d32145019 100644 --- a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/statistics/StatisticsCardsTest.kt +++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/statistics/StatisticsCardsTest.kt @@ -33,7 +33,6 @@ import de.rki.coronawarnapp.tracing.ui.statusbar.TracingHeaderState import de.rki.coronawarnapp.ui.main.home.HomeData import de.rki.coronawarnapp.ui.main.home.HomeFragment import de.rki.coronawarnapp.ui.main.home.HomeFragmentViewModel -import de.rki.coronawarnapp.ui.main.home.items.DiaryCard import de.rki.coronawarnapp.ui.main.home.items.FAQCard import de.rki.coronawarnapp.ui.main.home.items.HomeItem import de.rki.coronawarnapp.util.security.EncryptionErrorResetTool @@ -156,7 +155,6 @@ class StatisticsCardsTest : BaseUITest() { add(StatisticsHomeCard.Item(data = statsData, onHelpAction = { })) } - add(DiaryCard.Item {}) add(FAQCard.Item {}) } ) diff --git a/Corona-Warn-App/src/main/AndroidManifest.xml b/Corona-Warn-App/src/main/AndroidManifest.xml index f7f4cc3ee..ce4c559b2 100644 --- a/Corona-Warn-App/src/main/AndroidManifest.xml +++ b/Corona-Warn-App/src/main/AndroidManifest.xml @@ -1,8 +1,8 @@ <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" - tools:ignore="LockedOrientationActivity" - package="de.rki.coronawarnapp"> + package="de.rki.coronawarnapp" + tools:ignore="LockedOrientationActivity"> <uses-sdk tools:overrideLibrary="com.google.zxing.client.android" /> @@ -26,9 +26,9 @@ <application android:name="de.rki.coronawarnapp.CoronaWarnApplication" android:allowBackup="false" + android:extractNativeLibs="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" - android:extractNativeLibs="true" android:networkSecurityConfig="@xml/network_security_config" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" @@ -50,7 +50,7 @@ <receiver android:name=".notification.NotificationReceiver" - android:enabled="true"/> + android:enabled="true" /> <activity android:name=".ui.launcher.LauncherActivity" @@ -65,7 +65,8 @@ android:name=".ui.main.MainActivity" android:exported="false" android:screenOrientation="portrait" - android:theme="@style/AppTheme.Main" /> + android:theme="@style/AppTheme.Main" + android:windowSoftInputMode="adjustResize" /> <activity android:name=".ui.onboarding.OnboardingActivity" android:exported="false" @@ -76,14 +77,6 @@ android:exported="false" android:screenOrientation="fullSensor" tools:replace="screenOrientation" /> - <activity - android:name=".contactdiary.ui.ContactDiaryActivity" - android:exported="false" - android:screenOrientation="portrait" - android:launchMode="singleTop" - android:label="@string/empty_string_to_avoid_toolbar_announcement" - android:theme="@style/AppTheme.ContactDiary" - android:windowSoftInputMode="adjustResize" /> <provider android:name="androidx.core.content.FileProvider" diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ContactDiaryRootModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ContactDiaryRootModule.kt deleted file mode 100644 index 4215c795d..000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ContactDiaryRootModule.kt +++ /dev/null @@ -1,19 +0,0 @@ -package de.rki.coronawarnapp.contactdiary - -import dagger.Module -import dagger.android.ContributesAndroidInjector -import de.rki.coronawarnapp.contactdiary.retention.ContactDiaryRetentionModule -import de.rki.coronawarnapp.contactdiary.storage.ContactDiaryStorageModule -import de.rki.coronawarnapp.contactdiary.ui.ContactDiaryActivity -import de.rki.coronawarnapp.contactdiary.ui.ContactDiaryUIModule - -@Module( - includes = [ - ContactDiaryStorageModule::class, - ContactDiaryRetentionModule::class - ] -) -abstract class ContactDiaryRootModule { - @ContributesAndroidInjector(modules = [ContactDiaryUIModule::class]) - abstract fun contactDiaryActivity(): ContactDiaryActivity -} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/ContactDiaryActivity.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/ContactDiaryActivity.kt deleted file mode 100644 index 3aeaba9b7..000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/ContactDiaryActivity.kt +++ /dev/null @@ -1,63 +0,0 @@ -package de.rki.coronawarnapp.contactdiary.ui - -import android.content.Context -import android.content.Intent -import android.os.Bundle -import androidx.appcompat.app.AppCompatActivity -import androidx.fragment.app.Fragment -import androidx.fragment.app.FragmentManager -import androidx.navigation.fragment.NavHostFragment -import dagger.android.AndroidInjector -import dagger.android.DispatchingAndroidInjector -import dagger.android.HasAndroidInjector -import de.rki.coronawarnapp.R -import de.rki.coronawarnapp.util.di.AppInjector -import javax.inject.Inject - -/** - * This activity holds all the contact diary fragments - */ -class ContactDiaryActivity : AppCompatActivity(), HasAndroidInjector { - - @Inject lateinit var settings: ContactDiarySettings - @Inject lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Any> - override fun androidInjector(): AndroidInjector<Any> = dispatchingAndroidInjector - - private val FragmentManager.currentNavigationFragment: Fragment? - get() = primaryNavigationFragment?.childFragmentManager?.fragments?.first() - - override fun onCreate(savedInstanceState: Bundle?) { - AppInjector.setup(this) - super.onCreate(savedInstanceState) - setContentView(R.layout.contact_diary_activity) - - val navHost = supportFragmentManager.findFragmentById(R.id.contact_diary_fragment_container) as NavHostFragment? - val navController = navHost!!.navController - - val navInflater = navController.navInflater - val graph = navInflater.inflate(R.navigation.contact_diary_nav_graph) - - if (settings.onboardingStatus == ContactDiarySettings.OnboardingStatus.RISK_STATUS_1_12) { - graph.startDestination = R.id.contactDiaryOverviewFragment - } else { - graph.startDestination = R.id.contactDiaryOnboardingFragment - } - - navController.graph = graph - } - - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) - supportFragmentManager.currentNavigationFragment?.onActivityResult( - requestCode, - resultCode, - data - ) - } - - companion object { - fun start(context: Context) { - context.startActivity(Intent(context, ContactDiaryActivity::class.java)) - } - } -} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/ContactDiarySettings.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/ContactDiarySettings.kt index 060f31727..c44a3355a 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/ContactDiarySettings.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/ContactDiarySettings.kt @@ -14,6 +14,8 @@ class ContactDiarySettings @Inject constructor(val preferences: ContactDiaryPref } set(value) = preferences.onboardingStatusOrder.update { value.order } + inline val isOnboardingDone get() = onboardingStatus == OnboardingStatus.RISK_STATUS_1_12 + enum class OnboardingStatus(val order: Int) { NOT_ONBOARDED(0), RISK_STATUS_1_12(1) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/onboarding/ContactDiaryOnboardingFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/onboarding/ContactDiaryOnboardingFragment.kt index 2d7674dff..e01721dc3 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/onboarding/ContactDiaryOnboardingFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/onboarding/ContactDiaryOnboardingFragment.kt @@ -4,9 +4,11 @@ import android.os.Bundle import android.view.View import android.view.accessibility.AccessibilityEvent import androidx.fragment.app.Fragment +import androidx.navigation.fragment.navArgs import de.rki.coronawarnapp.R import de.rki.coronawarnapp.contactdiary.ui.ContactDiarySettings import de.rki.coronawarnapp.databinding.ContactDiaryOnboardingFragmentBinding +import de.rki.coronawarnapp.util.ContextExtensions.getDrawableCompat import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 @@ -23,6 +25,7 @@ class ContactDiaryOnboardingFragment : Fragment(R.layout.contact_diary_onboardin private val vm: ContactDiaryOnboardingFragmentViewModel by cwaViewModels { viewModelFactory } private val binding: ContactDiaryOnboardingFragmentBinding by viewBindingLazy() + private val args by navArgs<ContactDiaryOnboardingFragmentArgs>() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -31,9 +34,12 @@ class ContactDiaryOnboardingFragment : Fragment(R.layout.contact_diary_onboardin vm.onNextButtonClick() } - - toolbar.setNavigationOnClickListener { - vm.onBackButtonPress() + if (!args.showBottomNav) { + toolbar.apply { + navigationIcon = context.getDrawableCompat(R.drawable.ic_close) + navigationContentDescription = getString(R.string.accessibility_close) + setNavigationOnClickListener { vm.onBackButtonPress() } + } } contactDiaryOnboardingPrivacyInformation.setOnClickListener { diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/overview/ContactDiaryOverviewFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/overview/ContactDiaryOverviewFragment.kt index 4cef4c67c..166a25340 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/overview/ContactDiaryOverviewFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/overview/ContactDiaryOverviewFragment.kt @@ -96,7 +96,7 @@ class ContactDiaryOverviewFragment : Fragment(R.layout.contact_diary_overview_fr R.id.menu_contact_diary_information -> { doNavigate( ContactDiaryOverviewFragmentDirections - .actionContactDiaryOverviewFragmentToContactDiaryOnboardingFragment() + .actionContactDiaryOverviewFragmentToContactDiaryOnboardingFragment(showBottomNav = false) ) true } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/ActivityBinder.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/ActivityBinder.kt index be99bd064..4f190973a 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/ActivityBinder.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/ActivityBinder.kt @@ -2,6 +2,9 @@ package de.rki.coronawarnapp.ui import dagger.Module import dagger.android.ContributesAndroidInjector +import de.rki.coronawarnapp.contactdiary.retention.ContactDiaryRetentionModule +import de.rki.coronawarnapp.contactdiary.storage.ContactDiaryStorageModule +import de.rki.coronawarnapp.contactdiary.ui.ContactDiaryUIModule import de.rki.coronawarnapp.ui.launcher.LauncherActivity import de.rki.coronawarnapp.ui.launcher.LauncherActivityModule import de.rki.coronawarnapp.ui.main.MainActivity @@ -10,9 +13,20 @@ import de.rki.coronawarnapp.ui.main.MainActivityTestModule import de.rki.coronawarnapp.ui.onboarding.OnboardingActivity import de.rki.coronawarnapp.ui.onboarding.OnboardingActivityModule -@Module +@Module( + includes = [ + ContactDiaryStorageModule::class, + ContactDiaryRetentionModule::class + ] +) abstract class ActivityBinder { - @ContributesAndroidInjector(modules = [MainActivityModule::class, MainActivityTestModule::class]) + @ContributesAndroidInjector( + modules = [ + MainActivityModule::class, + MainActivityTestModule::class, + ContactDiaryUIModule::class + ] + ) abstract fun mainActivity(): MainActivity @ContributesAndroidInjector(modules = [LauncherActivityModule::class]) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/UIExtensions.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/UIExtensions.kt index ed1f696f7..3863ee801 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/UIExtensions.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/UIExtensions.kt @@ -1,7 +1,17 @@ package de.rki.coronawarnapp.ui +import android.os.Bundle +import androidx.core.view.isVisible import androidx.navigation.NavController +import androidx.navigation.NavDestination import androidx.navigation.NavDirections +import androidx.navigation.ui.NavigationUI +import androidx.navigation.ui.setupWithNavController +import com.google.android.material.bottomnavigation.BottomNavigationView +import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.contactdiary.ui.overview.ContactDiaryOverviewFragment +import de.rki.coronawarnapp.ui.main.home.HomeFragment +import java.lang.ref.WeakReference /** * Extends NavController to prevent navigation error when the user clicks on two buttons at almost @@ -13,3 +23,45 @@ fun NavController.doNavigate(direction: NavDirections) { currentDestination?.getAction(direction.actionId) ?.let { navigate(direction) } } + +/** + * Similar to [setupWithNavController],but it executes the passed action on item selection + * and shows [BottomNavigationView] on [HomeFragment], [ContactDiaryOverviewFragment] only + */ +fun BottomNavigationView.setupWithNavController2( + navController: NavController, + onItemSelected: () -> Unit +) { + setupWithNavController(navController) + setOnNavigationItemSelectedListener { item -> + onItemSelected() + NavigationUI.onNavDestinationSelected(item, navController) + } + val weakBottomNavView = WeakReference(this) + navController.addOnDestinationChangedListener( + object : NavController.OnDestinationChangedListener { + override fun onDestinationChanged( + controller: NavController, + destination: NavDestination, + arguments: Bundle? + ) { + val bottomView = weakBottomNavView.get() + // Remove listener if View does not exit + if (bottomView == null) { + navController.removeOnDestinationChangedListener(this) + return + } + // For destinations that always show the bottom bar + val inShowList = destination.id in listOf( + R.id.mainFragment, + R.id.contactDiaryOverviewFragment + ) + // For destinations that can show or hide the bottom bar in different cases + // for example [ContactDiaryOnboardingFragment] + val hasShowArgument = arguments?.getBoolean("showBottomNav") ?: false + + bottomView.isVisible = inShowList || hasShowArgument + } + } + ) +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivity.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivity.kt index 053520fcd..1d6e670ec 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivity.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivity.kt @@ -9,18 +9,23 @@ import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager +import androidx.navigation.NavController +import androidx.navigation.NavGraph import dagger.android.AndroidInjector import dagger.android.DispatchingAndroidInjector import dagger.android.HasAndroidInjector import de.rki.coronawarnapp.R import de.rki.coronawarnapp.contactdiary.retention.ContactDiaryWorkScheduler +import de.rki.coronawarnapp.databinding.ActivityMainBinding import de.rki.coronawarnapp.deadman.DeadmanNotificationScheduler import de.rki.coronawarnapp.ui.base.startActivitySafely +import de.rki.coronawarnapp.ui.setupWithNavController2 import de.rki.coronawarnapp.util.CWADebug import de.rki.coronawarnapp.util.ConnectivityHelper import de.rki.coronawarnapp.util.DialogHelper import de.rki.coronawarnapp.util.device.PowerManagement import de.rki.coronawarnapp.util.di.AppInjector +import de.rki.coronawarnapp.util.ui.findNavController import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import de.rki.coronawarnapp.worker.BackgroundWorkScheduler @@ -35,8 +40,6 @@ import javax.inject.Inject */ class MainActivity : AppCompatActivity(), HasAndroidInjector { companion object { - private val TAG: String? = MainActivity::class.simpleName - fun start(context: Context) { context.startActivity(Intent(context, MainActivity::class.java)) } @@ -62,7 +65,9 @@ class MainActivity : AppCompatActivity(), HasAndroidInjector { override fun onCreate(savedInstanceState: Bundle?) { AppInjector.setup(this) super.onCreate(savedInstanceState) - setContentView(R.layout.activity_main) + + val binding = ActivityMainBinding.inflate(layoutInflater) + setContentView(binding.root) if (CWADebug.isDeviceForTestersBuild) { vm.showEnvironmentHint.observe(this) { @@ -76,6 +81,23 @@ class MainActivity : AppCompatActivity(), HasAndroidInjector { vm.showEnergyOptimizedEnabledForBackground.observe(this) { showEnergyOptimizedEnabledForBackground() } + + val navController = supportFragmentManager.findNavController(R.id.nav_host_fragment) + binding.mainBottomNavigation.setupWithNavController2(navController) { + vm.onBottomNavSelected() + } + vm.isOnboardingDone.observe(this) { isOnboardingDone -> + startNestedGraphDestination(navController, isOnboardingDone) + } + } + + private fun startNestedGraphDestination(navController: NavController, isOnboardingDone: Boolean) { + val nestedGraph = navController.graph.findNode(R.id.contact_diary_nav_graph) as NavGraph + nestedGraph.startDestination = if (isOnboardingDone) { + R.id.contactDiaryOverviewFragment + } else { + R.id.contactDiaryOnboardingFragment + } } /** diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivityViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivityViewModel.kt index 37e600e85..f4c94877b 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivityViewModel.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivityViewModel.kt @@ -2,6 +2,7 @@ package de.rki.coronawarnapp.ui.main import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject +import de.rki.coronawarnapp.contactdiary.ui.ContactDiarySettings import de.rki.coronawarnapp.environment.EnvironmentSetup import de.rki.coronawarnapp.playbook.BackgroundNoise import de.rki.coronawarnapp.storage.LocalData @@ -16,7 +17,8 @@ import kotlinx.coroutines.flow.first class MainActivityViewModel @AssistedInject constructor( dispatcherProvider: DispatcherProvider, private val environmentSetup: EnvironmentSetup, - private val backgroundModeStatus: BackgroundModeStatus + private val backgroundModeStatus: BackgroundModeStatus, + private val contactDiarySettings: ContactDiarySettings ) : CWAViewModel( dispatcherProvider = dispatcherProvider ) { @@ -25,6 +27,7 @@ class MainActivityViewModel @AssistedInject constructor( val showBackgroundJobDisabledNotification = SingleLiveEvent<Unit>() val showEnergyOptimizedEnabledForBackground = SingleLiveEvent<Unit>() + val isOnboardingDone = SingleLiveEvent<Boolean>() init { if (CWADebug.isDeviceForTestersBuild) { @@ -60,6 +63,10 @@ class MainActivityViewModel @AssistedInject constructor( } } + fun onBottomNavSelected() { + isOnboardingDone.value = contactDiarySettings.isOnboardingDone + } + private suspend fun checkForEnergyOptimizedEnabled() { if (!backgroundModeStatus.isIgnoringBatteryOptimizations.first()) { showEnergyOptimizedEnabledForBackground.postValue(Unit) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeAdapter.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeAdapter.kt index 5e7565d58..72653654c 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeAdapter.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeAdapter.kt @@ -18,7 +18,6 @@ import de.rki.coronawarnapp.tracing.ui.homecards.LowRiskCard import de.rki.coronawarnapp.tracing.ui.homecards.TracingDisabledCard import de.rki.coronawarnapp.tracing.ui.homecards.TracingFailedCard import de.rki.coronawarnapp.tracing.ui.homecards.TracingProgressCard -import de.rki.coronawarnapp.ui.main.home.items.DiaryCard import de.rki.coronawarnapp.ui.main.home.items.FAQCard import de.rki.coronawarnapp.ui.main.home.items.HomeItem import de.rki.coronawarnapp.util.lists.BindableVH @@ -53,7 +52,6 @@ class HomeAdapter : ModularAdapter<HomeAdapter.HomeItemVH<HomeItem, ViewBinding> TypedVHCreatorMod({ data[it] is TestReadyCard.Item }) { TestReadyCard(it) }, TypedVHCreatorMod({ data[it] is TestPendingCard.Item }) { TestPendingCard(it) }, TypedVHCreatorMod({ data[it] is TestUnregisteredCard.Item }) { TestUnregisteredCard(it) }, - TypedVHCreatorMod({ data[it] is DiaryCard.Item }) { DiaryCard(it) }, TypedVHCreatorMod({ data[it] is StatisticsHomeCard.Item }) { StatisticsHomeCard(it) } )) } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragment.kt index f5236041c..f9d818fa1 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragment.kt @@ -8,7 +8,6 @@ import androidx.fragment.app.Fragment import androidx.recyclerview.widget.DefaultItemAnimator import androidx.recyclerview.widget.LinearLayoutManager import de.rki.coronawarnapp.R -import de.rki.coronawarnapp.contactdiary.ui.ContactDiaryActivity import de.rki.coronawarnapp.databinding.HomeFragmentLayoutBinding import de.rki.coronawarnapp.tracing.ui.TracingExplanationDialog import de.rki.coronawarnapp.ui.main.home.popups.DeviceTimeIncorrectDialog @@ -97,21 +96,15 @@ class HomeFragment : Fragment(R.layout.home_fragment_layout), AutoInject { onPositive = { vm.errorResetDialogDismissed() } ) } - HomeFragmentEvents.ShowDeleteTestDialog -> { - showRemoveTestDialog() - } - HomeFragmentEvents.GoToContactDiary -> { - context?.let { ContactDiaryActivity.start(it) } - } + HomeFragmentEvents.ShowDeleteTestDialog -> showRemoveTestDialog() - HomeFragmentEvents.ShowNewReleaseFragment -> { - doNavigate(HomeFragmentDirections.actionMainFragmentToNewReleaseInfoFragment(false)) - } - HomeFragmentEvents.GoToStatisticsExplanation -> { - doNavigate( - HomeFragmentDirections.actionMainFragmentToStatisticsExplanationFragment() - ) - } + HomeFragmentEvents.ShowNewReleaseFragment -> doNavigate( + HomeFragmentDirections.actionMainFragmentToNewReleaseInfoFragment(false) + ) + + HomeFragmentEvents.GoToStatisticsExplanation -> doNavigate( + HomeFragmentDirections.actionMainFragmentToStatisticsExplanationFragment() + ) } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentEvents.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentEvents.kt index 9e54306e5..5069ba21f 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentEvents.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentEvents.kt @@ -11,8 +11,6 @@ sealed class HomeFragmentEvents { object ShowDeleteTestDialog : HomeFragmentEvents() - object GoToContactDiary : HomeFragmentEvents() - object ShowNewReleaseFragment : HomeFragmentEvents() object GoToStatisticsExplanation : HomeFragmentEvents() diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentViewModel.kt index 559d1ef7e..77a35a177 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentViewModel.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentViewModel.kt @@ -51,7 +51,6 @@ import de.rki.coronawarnapp.tracing.ui.statusbar.toHeaderState import de.rki.coronawarnapp.ui.main.home.HomeFragmentEvents.ShowErrorResetDialog import de.rki.coronawarnapp.ui.main.home.HomeFragmentEvents.ShowInteropDeltaOnboarding import de.rki.coronawarnapp.ui.main.home.HomeFragmentEvents.ShowTracingExplanation -import de.rki.coronawarnapp.ui.main.home.items.DiaryCard import de.rki.coronawarnapp.ui.main.home.items.FAQCard import de.rki.coronawarnapp.ui.main.home.items.HomeItem import de.rki.coronawarnapp.util.DeviceUIState @@ -236,8 +235,6 @@ class HomeFragmentViewModel @AssistedInject constructor( })) } - add(DiaryCard.Item(onClickAction = { popupEvents.postValue(HomeFragmentEvents.GoToContactDiary) })) - add(FAQCard.Item(onClickAction = { openFAQUrlEvent.postValue(Unit) })) } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/items/DiaryCard.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/items/DiaryCard.kt deleted file mode 100644 index 3cf7983ce..000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/items/DiaryCard.kt +++ /dev/null @@ -1,38 +0,0 @@ -package de.rki.coronawarnapp.ui.main.home.items - -import android.view.ViewGroup -import de.rki.coronawarnapp.R -import de.rki.coronawarnapp.databinding.ContactDiaryHomescreenCardIncludeBinding -import de.rki.coronawarnapp.ui.main.home.HomeAdapter -import de.rki.coronawarnapp.ui.main.home.items.DiaryCard.Item -import de.rki.coronawarnapp.util.lists.diffutil.HasPayloadDiffer - -class DiaryCard(parent: ViewGroup) : HomeAdapter.HomeItemVH<Item, ContactDiaryHomescreenCardIncludeBinding>( - R.layout.home_card_container_layout, parent -) { - - override val viewBinding = lazy { - ContactDiaryHomescreenCardIncludeBinding.inflate( - layoutInflater, - itemView.findViewById(R.id.card_container), - true - ) - } - - override val onBindData: ContactDiaryHomescreenCardIncludeBinding.( - item: Item, - payloads: List<Any> - ) -> Unit = { item, payloads -> - itemView.setOnClickListener { - val curItem = payloads.filterIsInstance<Item>().singleOrNull() ?: item - curItem.onClickAction(item) - } - contactDiaryCardHomescreenButton.setOnClickListener { itemView.performClick() } - } - - data class Item(val onClickAction: (Item) -> Unit) : HomeItem, HasPayloadDiffer { - override val stableId: Long = Item::class.java.name.hashCode().toLong() - - override fun diffPayload(old: Any, new: Any): Any? = if (old::class == new::class) new else null - } -} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/di/ApplicationComponent.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/di/ApplicationComponent.kt index 9c5d073ce..25854c3c9 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/di/ApplicationComponent.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/di/ApplicationComponent.kt @@ -11,7 +11,6 @@ import de.rki.coronawarnapp.bugreporting.BugReporter import de.rki.coronawarnapp.bugreporting.BugReportingModule import de.rki.coronawarnapp.bugreporting.BugReportingSharedModule import de.rki.coronawarnapp.bugreporting.debuglog.DebugLogger -import de.rki.coronawarnapp.contactdiary.ContactDiaryRootModule import de.rki.coronawarnapp.datadonation.DataDonationModule import de.rki.coronawarnapp.diagnosiskeys.DiagnosisKeysModule import de.rki.coronawarnapp.diagnosiskeys.DownloadDiagnosisKeysTaskModule @@ -70,7 +69,6 @@ import javax.inject.Singleton BugReportingSharedModule::class, SerializationModule::class, WorkerBinder::class, - ContactDiaryRootModule::class, StatisticsModule::class, DataDonationModule::class ] diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ui/FragmentExtensions.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ui/FragmentExtensions.kt index 493fd21f6..4cdc9ec41 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ui/FragmentExtensions.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ui/FragmentExtensions.kt @@ -1,7 +1,13 @@ package de.rki.coronawarnapp.util.ui +import android.app.Activity +import androidx.annotation.IdRes import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentContainerView +import androidx.fragment.app.FragmentManager +import androidx.navigation.NavController import androidx.navigation.NavDirections +import androidx.navigation.fragment.NavHostFragment import androidx.navigation.fragment.findNavController import de.rki.coronawarnapp.ui.doNavigate import timber.log.Timber @@ -17,3 +23,15 @@ fun Fragment.popBackStack(): Boolean { } return findNavController().popBackStack() } + +/** + * [FragmentContainerView] does not access [NavController] in [Activity.onCreate] + * as workaround [FragmentManager] is used to get the [NavController] + * @param id [Int] NavFragment id + * @see <a href="https://issuetracker.google.com/issues/142847973">issue-142847973</a> + */ +@Throws(IllegalStateException::class) +fun FragmentManager.findNavController(@IdRes id: Int): NavController { + val fragment = findFragmentById(id) ?: throw IllegalStateException("Fragment is not found for id:$id") + return NavHostFragment.findNavController(fragment) +} diff --git a/Corona-Warn-App/src/main/res/color/nav_item_color.xml b/Corona-Warn-App/src/main/res/color/nav_item_color.xml new file mode 100644 index 000000000..943ce8e79 --- /dev/null +++ b/Corona-Warn-App/src/main/res/color/nav_item_color.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:color="@color/navItemColorSelected" android:state_selected="true" /> + <item android:color="@color/navItemColorNormal" /> +</selector> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/drawable/ic_nav_diary.xml b/Corona-Warn-App/src/main/res/drawable/ic_nav_diary.xml new file mode 100644 index 000000000..38266eeda --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_nav_diary.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="18dp" + android:height="22dp" + android:viewportWidth="18" + android:viewportHeight="22"> + <path + android:pathData="M17.0753,19.7501V2.5C17.0753,1 16,0 14.5,0H2.3493C1.088,0 -0.0081,1.2401 0,2.5C0,8.0716 0,13.9291 0,19.5C0,21 1.0002,22 2.5582,22H16.5C16.5,22 17,22 17,21.5C17,21 17,20.5 17,20.5C17,20.5 17,20.0056 16.5,20C16,19.9944 3.5002,20 3.5002,20C3.5002,20 2.0001,20 2.0001,18.5C2.0001,17.8138 2.0001,17.5 2.0001,17.5C2.0001,16 3.5002,16 3.5002,16C2.1767,16 13.2552,16 16,16C16,16 15.5,17 15.5,18C15.5,18.5728 16,19.7501 16,19.7501C16.5,19.7501 17.0753,19.7501 17.0753,19.7501Z" + android:fillColor="#999999"/> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_nav_home.xml b/Corona-Warn-App/src/main/res/drawable/ic_nav_home.xml new file mode 100644 index 000000000..61da02f81 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_nav_home.xml @@ -0,0 +1,10 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="22dp" + android:height="20dp" + android:viewportWidth="22" + android:viewportHeight="20"> + <path + android:pathData="M11,0.5C10.73,0.5 10.48,0.61 10.29,0.8L0.2,9.6C0.07,9.69 0,9.84 0,10C0,10.28 0.22,10.5 0.5,10.5H3V18.5C3,19.05 3.45,19.5 4,19.5H8C8.55,19.5 9,19.05 9,18.5V12.5H13V18.5C13,19.05 13.45,19.5 14,19.5H18C18.55,19.5 19,19.05 19,18.5V10.5H21.5C21.78,10.5 22,10.28 22,10C22,9.84 21.92,9.69 21.8,9.6L11.72,0.8C11.72,0.8 11.72,0.8 11.71,0.79C11.52,0.61 11.27,0.5 11,0.5Z" + android:fillColor="#017FAD" + android:fillType="evenOdd"/> +</vector> diff --git a/Corona-Warn-App/src/main/res/layout/activity_main.xml b/Corona-Warn-App/src/main/res/layout/activity_main.xml index 117a40334..80cb4564b 100644 --- a/Corona-Warn-App/src/main/res/layout/activity_main.xml +++ b/Corona-Warn-App/src/main/res/layout/activity_main.xml @@ -6,12 +6,33 @@ android:layout_height="match_parent" tools:context="de.rki.coronawarnapp.ui.main.MainActivity"> - <androidx.fragment.app.FragmentContainerView - android:id="@+id/nav_host_fragment" - android:name="androidx.navigation.fragment.NavHostFragment" + <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" - android:layout_height="match_parent" - app:defaultNavHost="true" - app:navGraph="@navigation/nav_graph" /> + android:layout_height="match_parent"> + + <androidx.fragment.app.FragmentContainerView + android:id="@+id/nav_host_fragment" + android:name="androidx.navigation.fragment.NavHostFragment" + android:layout_width="0dp" + android:layout_height="0dp" + app:defaultNavHost="true" + app:layout_constraintBottom_toTopOf="@id/main_bottom_navigation" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:navGraph="@navigation/nav_graph" /> + + <com.google.android.material.bottomnavigation.BottomNavigationView + android:id="@+id/main_bottom_navigation" + style="@style/Widget.MaterialComponents.BottomNavigationView" + android:layout_width="0dp" + android:layout_height="wrap_content" + app:itemIconTint="@color/nav_item_color" + app:itemTextColor="@color/nav_item_color" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:menu="@menu/menu_bottom_nav" /> + </androidx.constraintlayout.widget.ConstraintLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/layout/contact_diary_activity.xml b/Corona-Warn-App/src/main/res/layout/contact_diary_activity.xml deleted file mode 100644 index 7d2465983..000000000 --- a/Corona-Warn-App/src/main/res/layout/contact_diary_activity.xml +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto" - xmlns:tools="http://schemas.android.com/tools" - android:layout_width="match_parent" - android:layout_height="match_parent" - tools:context="de.rki.coronawarnapp.contactdiary.ui.ContactDiaryActivity"> - - <androidx.fragment.app.FragmentContainerView - android:id="@+id/contact_diary_fragment_container" - android:name="androidx.navigation.fragment.NavHostFragment" - android:layout_width="match_parent" - android:layout_height="match_parent" - app:defaultNavHost="true" /> - -</androidx.coordinatorlayout.widget.CoordinatorLayout> diff --git a/Corona-Warn-App/src/main/res/layout/contact_diary_onboarding_fragment.xml b/Corona-Warn-App/src/main/res/layout/contact_diary_onboarding_fragment.xml index 17ede5ce2..fffbd9bce 100644 --- a/Corona-Warn-App/src/main/res/layout/contact_diary_onboarding_fragment.xml +++ b/Corona-Warn-App/src/main/res/layout/contact_diary_onboarding_fragment.xml @@ -15,7 +15,6 @@ android:id="@+id/toolbar" android:layout_width="0dp" android:layout_height="wrap_content" - style="@style/CWAToolbar.Close" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" diff --git a/Corona-Warn-App/src/main/res/layout/contact_diary_overview_fragment.xml b/Corona-Warn-App/src/main/res/layout/contact_diary_overview_fragment.xml index d3182899c..e4daa3c93 100644 --- a/Corona-Warn-App/src/main/res/layout/contact_diary_overview_fragment.xml +++ b/Corona-Warn-App/src/main/res/layout/contact_diary_overview_fragment.xml @@ -13,26 +13,12 @@ android:id="@+id/toolbar" android:layout_width="0dp" android:layout_height="wrap_content" - style="@style/CWAToolbar.BackArrow" android:background="@color/colorBackground" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:popupTheme="@style/CWAToolbar.Menu" - app:title="@string/contact_diary_overview_header" /> - - <TextView - android:id="@+id/onboarding_headline" - style="@style/headline5Bold" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_tiny" - android:focusable="true" - android:text="@string/contact_diary_overview_title" - app:layout_constraintEnd_toStartOf="@+id/guideline_end" - app:layout_constraintStart_toStartOf="@+id/guideline_start" - app:layout_constraintTop_toBottomOf="@+id/toolbar" - tools:text="Kontakt-Tagebuch" /> + app:title="@string/contact_diary_overview_title" /> <TextView android:id="@+id/contact_diary_overview_subtitle" @@ -44,7 +30,7 @@ android:text="@string/contact_diary_overview_subtitle" app:layout_constraintEnd_toEndOf="@id/guideline_end" app:layout_constraintStart_toStartOf="@id/guideline_start" - app:layout_constraintTop_toBottomOf="@+id/onboarding_headline" + app:layout_constraintTop_toBottomOf="@id/toolbar" tools:text="Tragen Sie ein, mit wem Sie sich getroffen haben und wo Sie gewesen sind." /> <androidx.recyclerview.widget.RecyclerView diff --git a/Corona-Warn-App/src/main/res/menu/menu_bottom_nav.xml b/Corona-Warn-App/src/main/res/menu/menu_bottom_nav.xml new file mode 100644 index 000000000..3c5985250 --- /dev/null +++ b/Corona-Warn-App/src/main/res/menu/menu_bottom_nav.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + + <item + android:id="@+id/mainFragment" + android:icon="@drawable/ic_nav_home" + android:title="@string/bottom_nav_home_title" /> + + <item + android:id="@+id/contact_diary_nav_graph" + android:icon="@drawable/ic_nav_diary" + android:title="@string/bottom_nav_diary_title" /> +</menu> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/navigation/contact_diary_nav_graph.xml b/Corona-Warn-App/src/main/res/navigation/contact_diary_nav_graph.xml index 06e81152e..a11f6a236 100644 --- a/Corona-Warn-App/src/main/res/navigation/contact_diary_nav_graph.xml +++ b/Corona-Warn-App/src/main/res/navigation/contact_diary_nav_graph.xml @@ -83,6 +83,10 @@ app:destination="@id/contactDiaryOverviewFragment" app:popUpTo="@id/contact_diary_nav_graph" app:popUpToInclusive="true" /> + <argument + android:name="showBottomNav" + android:defaultValue="true" + app:argType="boolean" /> </fragment> <fragment android:id="@+id/contactDiaryInformationPrivacyFragment" diff --git a/Corona-Warn-App/src/main/res/navigation/nav_graph.xml b/Corona-Warn-App/src/main/res/navigation/nav_graph.xml index 0c7ba28ea..ce2311bb0 100644 --- a/Corona-Warn-App/src/main/res/navigation/nav_graph.xml +++ b/Corona-Warn-App/src/main/res/navigation/nav_graph.xml @@ -5,7 +5,10 @@ android:id="@+id/nav_graph" app:startDestination="@id/mainFragment"> + <!-- Corona Test graph--> <include app:graph="@navigation/test_nav_graph" /> + <!-- Contact Diary graph--> + <include app:graph="@navigation/contact_diary_nav_graph" /> <!-- Main --> <fragment @@ -504,10 +507,10 @@ <fragment android:id="@+id/newReleaseInfoFragment" android:name="de.rki.coronawarnapp.release.NewReleaseInfoFragment" - android:label="NewReleaseInfoFragment" > + android:label="NewReleaseInfoFragment"> <argument android:name="comesFromInfoScreen" - app:argType="boolean" - android:defaultValue="false" /> + android:defaultValue="false" + app:argType="boolean" /> </fragment> </navigation> diff --git a/Corona-Warn-App/src/main/res/values-de/strings.xml b/Corona-Warn-App/src/main/res/values-de/strings.xml index 39cf5f056..571bdf081 100644 --- a/Corona-Warn-App/src/main/res/values-de/strings.xml +++ b/Corona-Warn-App/src/main/res/values-de/strings.xml @@ -1643,5 +1643,8 @@ <string name="statistics_trend_decreasing">Trend fallend</string> <!-- XTXT: Statistics trend stable (Accessibilty) --> <string name="statistics_trend_stable">Trend stabil</string> - + <!-- XHED: Title for BottomNav main screen title --> + <string name="bottom_nav_home_title">Startseite</string> + <!-- XHED: Title for BottomNav diary screen title --> + <string name="bottom_nav_diary_title">Tagebuch</string> </resources> diff --git a/Corona-Warn-App/src/main/res/values/colors.xml b/Corona-Warn-App/src/main/res/values/colors.xml index 959ba9df9..8bcf58220 100644 --- a/Corona-Warn-App/src/main/res/values/colors.xml +++ b/Corona-Warn-App/src/main/res/values/colors.xml @@ -84,4 +84,8 @@ <color name="colorStatisticsTrendPositive">#2E854B</color> <color name="colorStatisticsTrendNegative">#C11633</color> <color name="colorStatisticsTrendNeutral">#5D6F80</color> + + <!-- Bottom Nav bar--> + <color name="navItemColorSelected">@color/colorAccent</color> + <color name="navItemColorNormal">#999999</color> </resources> diff --git a/Corona-Warn-App/src/main/res/values/strings.xml b/Corona-Warn-App/src/main/res/values/strings.xml index 18854057f..142d5d709 100644 --- a/Corona-Warn-App/src/main/res/values/strings.xml +++ b/Corona-Warn-App/src/main/res/values/strings.xml @@ -1665,5 +1665,9 @@ <string name="statistics_trend_decreasing">"Trend: Downwards"</string> <!-- XTXT: Statistics trend stable (Accessibilty) --> <string name="statistics_trend_stable">"Trend: Steady"</string> + <!-- XHED: Title for BottomNav main screen title --> + <string name="bottom_nav_home_title">Home</string> + <!-- XHED: Title for BottomNav diary screen title --> + <string name="bottom_nav_diary_title">Journal</string> </resources> diff --git a/Corona-Warn-App/src/main/res/values/styles.xml b/Corona-Warn-App/src/main/res/values/styles.xml index 0fa57df7b..1a62baa5e 100644 --- a/Corona-Warn-App/src/main/res/values/styles.xml +++ b/Corona-Warn-App/src/main/res/values/styles.xml @@ -1,37 +1,24 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android"> - <style name="AppTheme" parent="Theme.AppCompat.DayNight"> + <style name="AppTheme" parent="Theme.MaterialComponents.DayNight.Bridge"> <item name="colorPrimary">@color/colorBrandSecondary</item> <item name="colorPrimaryDark">@color/colorStableDark</item> <item name="android:windowBackground">@color/colorBackground</item> - <item name="alertDialogTheme">@style/dialog</item> + <item name="alertDialogTheme">@style/DialogAlertTheme</item> <item name="android:actionOverflowButtonStyle">@style/CWAToolbar.Overflow</item> </style> <style name="AppTheme.NoActionBar" parent="AppTheme"> <item name="windowActionBar">false</item> <item name="windowNoTitle">true</item> - </style> - - <style name="MaterialAppTheme" parent="Theme.MaterialComponents.DayNight"> - <item name="colorPrimary">@color/colorBrandSecondary</item> - <item name="colorPrimaryDark">@color/colorStableDark</item> - <item name="android:windowBackground">@color/colorBackground</item> - <item name="alertDialogTheme">@style/diaryDialog</item> - </style> - - <style name="MaterialAppTheme.NoActionBar" parent="MaterialAppTheme"> - <item name="windowActionBar">false</item> - <item name="windowNoTitle">true</item> - <item name="dialogTheme">@style/diaryDialog</item> + <item name="dialogTheme">@style/DialogTheme</item> + <item name="bottomSheetDialogTheme">@style/BottomSheetDialogTheme</item> </style> <style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" /> <style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" /> - <style name="AppTheme.ContactDiary" parent="MaterialAppTheme.NoActionBar" /> - <style name="ThemeOverlay.App.ExtendedFloatingActionButton" parent=""> <item name="colorSecondary">@color/colorAccentTintButton</item> <item name="colorOnSecondary">@color/colorTextEmphasizedButton</item> @@ -76,21 +63,25 @@ <item name="navigationContentDescription">@string/accessibility_close</item> </style> - <!-- Default dialog --> - <style name="dialog" parent="ThemeOverlay.AppCompat.Dialog.Alert"> - <item name="buttonBarPositiveButtonStyle">@style/dialogPositiveButtonStyle</item> - <item name="buttonBarNegativeButtonStyle">@style/dialogNegativeButtonStyle</item> + <!-- Dialog Theme--> + <style name="DialogTheme" parent="Theme.MaterialComponents.DayNight.Dialog.Alert"> + <item name="buttonBarPositiveButtonStyle">@style/DialogButtonTheme</item> + <item name="buttonBarNegativeButtonStyle">@style/DialogButtonTheme</item> </style> - <style name="diaryDialogButton" parent="Widget.MaterialComponents.Button.TextButton"> + <style name="BottomSheetDialogTheme" parent="Theme.MaterialComponents.DayNight.BottomSheetDialog"> + <item name="colorPrimary">@color/colorBrandSecondary</item> + <item name="colorPrimaryDark">@color/colorStableDark</item> + </style> + + <style name="DialogButtonTheme" parent="Widget.MaterialComponents.Button.TextButton"> <item name="android:textColor">@color/colorAccentTintButton</item> </style> - <style name="diaryButtonNegative" parent="Widget.MaterialComponents.Button.TextButton" /> - <!-- Contact Diary Dialog--> - <style name="diaryDialog" parent="Theme.MaterialComponents.DayNight.Dialog.Alert"> - <item name="buttonBarPositiveButtonStyle">@style/diaryDialogButton</item> - <item name="buttonBarNegativeButtonStyle">@style/diaryDialogButton</item> + <!-- Alert Dialog Theme--> + <style name="DialogAlertTheme" parent="ThemeOverlay.AppCompat.Dialog.Alert"> + <item name="buttonBarPositiveButtonStyle">@style/dialogPositiveButtonStyle</item> + <item name="buttonBarNegativeButtonStyle">@style/dialogNegativeButtonStyle</item> </style> <style name="dialogPositiveButtonStyle" parent="Widget.AppCompat.Button.ButtonBar.AlertDialog"> @@ -245,6 +236,7 @@ <style name="headline5Tint" parent="@style/headline5"> <item name="android:textColor">@color/colorTextTint</item> </style> + <style name="headline5Bold" parent="@style/TextAppearance.MaterialComponents.Headline5"> <item name="android:textStyle">bold</item> </style> diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/main/MainActivityViewModelTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/main/MainActivityViewModelTest.kt index 10efd2034..6fb7cf973 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/main/MainActivityViewModelTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/main/MainActivityViewModelTest.kt @@ -1,6 +1,8 @@ package de.rki.coronawarnapp.main +import de.rki.coronawarnapp.contactdiary.ui.ContactDiarySettings import de.rki.coronawarnapp.environment.EnvironmentSetup +import de.rki.coronawarnapp.storage.LocalData import de.rki.coronawarnapp.ui.main.MainActivityViewModel import de.rki.coronawarnapp.util.CWADebug import de.rki.coronawarnapp.util.device.BackgroundModeStatus @@ -24,12 +26,17 @@ class MainActivityViewModelTest : BaseTest() { @MockK lateinit var environmentSetup: EnvironmentSetup @MockK lateinit var backgroundModeStatus: BackgroundModeStatus + @MockK lateinit var diarySettings: ContactDiarySettings @BeforeEach fun setup() { MockKAnnotations.init(this) + mockkObject(LocalData) mockkObject(CWADebug) + + every { LocalData.isBackgroundCheckDone() } returns true + every { environmentSetup.currentEnvironment } returns EnvironmentSetup.Type.WRU } @AfterEach @@ -40,7 +47,8 @@ class MainActivityViewModelTest : BaseTest() { private fun createInstance(): MainActivityViewModel = MainActivityViewModel( dispatcherProvider = TestDispatcherProvider(), environmentSetup = environmentSetup, - backgroundModeStatus = backgroundModeStatus + backgroundModeStatus = backgroundModeStatus, + contactDiarySettings = diarySettings ) @Test @@ -69,4 +77,20 @@ class MainActivityViewModelTest : BaseTest() { val vm = createInstance() vm.showEnvironmentHint.value shouldBe null } + + @Test + fun `User is not onboarded when settings returns NOT_ONBOARDED `() { + every { diarySettings.onboardingStatus } returns ContactDiarySettings.OnboardingStatus.NOT_ONBOARDED + val vm = createInstance() + vm.onBottomNavSelected() + vm.isOnboardingDone.value shouldBe false + } + + @Test + fun `User is onboarded when settings returns RISK_STATUS_1_12 `() { + every { diarySettings.onboardingStatus } returns ContactDiarySettings.OnboardingStatus.RISK_STATUS_1_12 + val vm = createInstance() + vm.onBottomNavSelected() + vm.isOnboardingDone.value shouldBe true + } } -- GitLab