diff --git a/Corona-Warn-App/src/main/AndroidManifest.xml b/Corona-Warn-App/src/main/AndroidManifest.xml index 1d0b39de87f9dc950e04f3eff376f752c3276c24..e450de6d4a8c1a927ee95003d34358dfb642cdb6 100644 --- a/Corona-Warn-App/src/main/AndroidManifest.xml +++ b/Corona-Warn-App/src/main/AndroidManifest.xml @@ -80,7 +80,7 @@ android:name=".contactdiary.ui.ContactDiaryActivity" android:exported="false" android:screenOrientation="portrait" - android:theme="@style/AppTheme.NoActionBar" /> + android:theme="@style/AppTheme.ContactDiary" /> </application> diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ContactDiaryModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ContactDiaryModule.kt deleted file mode 100644 index e2529d15f11863b49d991bf82ac6b5cdafb71e39..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ContactDiaryModule.kt +++ /dev/null @@ -1,9 +0,0 @@ -package de.rki.coronawarnapp.contactdiary - -import dagger.Module -import de.rki.coronawarnapp.contactdiary.storage.ContactDiaryStorageModule - -@Module( - includes = [ContactDiaryStorageModule::class] -) -class ContactDiaryModule 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 new file mode 100644 index 0000000000000000000000000000000000000000..4db7d6fde159cac51ef4e19a7c47005533b0a947 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ContactDiaryRootModule.kt @@ -0,0 +1,17 @@ +package de.rki.coronawarnapp.contactdiary + +import dagger.Module +import dagger.android.ContributesAndroidInjector +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 + ] +) +abstract class ContactDiaryRootModule { + @ContributesAndroidInjector(modules = [ContactDiaryUIModule::class]) + abstract fun contactDiaryActivity(): ContactDiaryActivity +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/ContactDiaryLocation.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/ContactDiaryLocation.kt index 4618a0b9da3230445c696dde7aae7834289dbc13..c5315a98646599c1a8773a3f99fe58e9cdb11a90 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/ContactDiaryLocation.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/ContactDiaryLocation.kt @@ -1,6 +1,8 @@ package de.rki.coronawarnapp.contactdiary.model -interface ContactDiaryLocation { +import de.rki.coronawarnapp.util.lists.HasStableId + +interface ContactDiaryLocation : HasStableId { val locationId: Long var locationName: String } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/ContactDiaryPerson.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/ContactDiaryPerson.kt index 5657484a05b1e2c808c21c69808a8d456f5ab4a0..95badab5576060f02a888551d0c416be8ad9ba9b 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/ContactDiaryPerson.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/ContactDiaryPerson.kt @@ -1,6 +1,8 @@ package de.rki.coronawarnapp.contactdiary.model -interface ContactDiaryPerson { +import de.rki.coronawarnapp.util.lists.HasStableId + +interface ContactDiaryPerson : HasStableId { val personId: Long var fullName: String } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/DefaultContactDiaryLocation.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/DefaultContactDiaryLocation.kt deleted file mode 100644 index 65bf6c6e5be5df3b6215d18c2bc2e371bec46e29..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/DefaultContactDiaryLocation.kt +++ /dev/null @@ -1,6 +0,0 @@ -package de.rki.coronawarnapp.contactdiary.model - -data class DefaultContactDiaryLocation( - override val locationId: Long = 0L, - override var locationName: String -) : ContactDiaryLocation diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/DefaultContactDiaryPerson.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/DefaultContactDiaryPerson.kt deleted file mode 100644 index fdf73bd6e014940d71c58ea54726050df3519c20..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/DefaultContactDiaryPerson.kt +++ /dev/null @@ -1,6 +0,0 @@ -package de.rki.coronawarnapp.contactdiary.model - -data class DefaultContactDiaryPerson( - override val personId: Long = 0L, - override var fullName: String -) : ContactDiaryPerson diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/entity/ContactDiaryLocationEntity.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/entity/ContactDiaryLocationEntity.kt index ffd350e419111ae73d764ef4f5aae5564e244d9d..c424bfdee70c3cf08f0907334681e3e4567ecc2e 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/entity/ContactDiaryLocationEntity.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/entity/ContactDiaryLocationEntity.kt @@ -9,7 +9,10 @@ import de.rki.coronawarnapp.contactdiary.model.ContactDiaryLocation data class ContactDiaryLocationEntity( @PrimaryKey(autoGenerate = true) @ColumnInfo(name = "locationId") override val locationId: Long = 0L, @ColumnInfo(name = "locationName") override var locationName: String -) : ContactDiaryLocation +) : ContactDiaryLocation { + override val stableId: Long + get() = locationId +} fun ContactDiaryLocation.toContactDiaryLocationEntity(): ContactDiaryLocationEntity = ContactDiaryLocationEntity(this.locationId, this.locationName) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/entity/ContactDiaryPersonEntity.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/entity/ContactDiaryPersonEntity.kt index be31909b96e9b1e8141fb9048cd4316f649a510d..0ea761f2c70a9f5a6560c6ef7bcbdd487725b7f6 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/entity/ContactDiaryPersonEntity.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/entity/ContactDiaryPersonEntity.kt @@ -9,7 +9,10 @@ import de.rki.coronawarnapp.contactdiary.model.ContactDiaryPerson data class ContactDiaryPersonEntity( @PrimaryKey(autoGenerate = true) @ColumnInfo(name = "personId") override val personId: Long = 0L, @ColumnInfo(name = "fullName") override var fullName: String -) : ContactDiaryPerson +) : ContactDiaryPerson { + override val stableId: Long + get() = personId +} fun ContactDiaryPerson.toContactDiaryPersonEntity(): ContactDiaryPersonEntity = ContactDiaryPersonEntity(this.personId, this.fullName) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/repo/DefaultContactDiaryRepository.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/repo/DefaultContactDiaryRepository.kt index 91a482917bc8649c569c0e8e6d827b4eab4487e4..6e2edbb9f5d0e2da601da730237d322b54012d21 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/repo/DefaultContactDiaryRepository.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/repo/DefaultContactDiaryRepository.kt @@ -85,10 +85,8 @@ class DefaultContactDiaryRepository @Inject constructor( override suspend fun addLocationVisit(contactDiaryLocationVisit: ContactDiaryLocationVisit) { Timber.d("Adding location visit $contactDiaryLocationVisit") - executeWhenIdNotDefault(contactDiaryLocationVisit.id) { - val contactDiaryLocationVisitEntity = contactDiaryLocationVisit.toContactDiaryLocationVisitEntity() - contactDiaryLocationVisitDao.insert(contactDiaryLocationVisitEntity) - } + val contactDiaryLocationVisitEntity = contactDiaryLocationVisit.toContactDiaryLocationVisitEntity() + contactDiaryLocationVisitDao.insert(contactDiaryLocationVisitEntity) } override suspend fun deleteLocationVisit(contactDiaryLocationVisit: ContactDiaryLocationVisit) { diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/ContactDiaryModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/ContactDiaryModule.kt deleted file mode 100644 index 8aca513cd4ecd8758aab1c317d7af2c6a8102542..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/ContactDiaryModule.kt +++ /dev/null @@ -1,17 +0,0 @@ -package de.rki.coronawarnapp.contactdiary.ui - -import dagger.Module -import dagger.android.ContributesAndroidInjector -import de.rki.coronawarnapp.contactdiary.ui.onboarding.ContactDiaryOnboardingFragment -import de.rki.coronawarnapp.contactdiary.ui.onboarding.ContactDiaryOnboardingFragmentModule -import de.rki.coronawarnapp.contactdiary.ui.overview.ContactDiaryOverviewFragment -import de.rki.coronawarnapp.contactdiary.ui.overview.ContactDiaryOverviewFragmentModule - -@Module -abstract class ContactDiaryModule { - @ContributesAndroidInjector(modules = [ContactDiaryOnboardingFragmentModule::class]) - abstract fun contactDiaryOnboardingFragment(): ContactDiaryOnboardingFragment - - @ContributesAndroidInjector(modules = [ContactDiaryOverviewFragmentModule::class]) - abstract fun contactDiaryOverviewFragment(): ContactDiaryOverviewFragment -} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/ContactDiaryUIModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/ContactDiaryUIModule.kt new file mode 100644 index 0000000000000000000000000000000000000000..0ddeb1ca0398ee8ed848fa789bd86c5b032ea6cf --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/ContactDiaryUIModule.kt @@ -0,0 +1,42 @@ +package de.rki.coronawarnapp.contactdiary.ui + +import dagger.Module +import dagger.android.ContributesAndroidInjector +import de.rki.coronawarnapp.contactdiary.ui.day.ContactDiaryDayFragment +import de.rki.coronawarnapp.contactdiary.ui.day.ContactDiaryDayModule +import de.rki.coronawarnapp.contactdiary.ui.day.sheets.location.ContactDiaryLocationBottomSheetDialogFragment +import de.rki.coronawarnapp.contactdiary.ui.day.sheets.location.ContactDiaryLocationBottomSheetDialogModule +import de.rki.coronawarnapp.contactdiary.ui.day.sheets.person.ContactDiaryPersonBottomSheetDialogFragment +import de.rki.coronawarnapp.contactdiary.ui.day.sheets.person.ContactDiaryPersonBottomSheetDialogModule +import de.rki.coronawarnapp.contactdiary.ui.day.tabs.location.ContactDiaryLocationListFragment +import de.rki.coronawarnapp.contactdiary.ui.day.tabs.location.ContactDiaryLocationListModule +import de.rki.coronawarnapp.contactdiary.ui.day.tabs.person.ContactDiaryPersonListFragment +import de.rki.coronawarnapp.contactdiary.ui.day.tabs.person.ContactDiaryPersonListModule +import de.rki.coronawarnapp.contactdiary.ui.onboarding.ContactDiaryOnboardingFragment +import de.rki.coronawarnapp.contactdiary.ui.onboarding.ContactDiaryOnboardingFragmentModule +import de.rki.coronawarnapp.contactdiary.ui.overview.ContactDiaryOverviewFragment +import de.rki.coronawarnapp.contactdiary.ui.overview.ContactDiaryOverviewFragmentModule + +@Module +abstract class ContactDiaryUIModule { + @ContributesAndroidInjector(modules = [ContactDiaryDayModule::class]) + abstract fun contactDiaryDayFragment(): ContactDiaryDayFragment + + @ContributesAndroidInjector(modules = [ContactDiaryPersonListModule::class]) + abstract fun contactDiaryPersonListFragment(): ContactDiaryPersonListFragment + + @ContributesAndroidInjector(modules = [ContactDiaryLocationListModule::class]) + abstract fun contactDiaryLocationListFragment(): ContactDiaryLocationListFragment + + @ContributesAndroidInjector(modules = [ContactDiaryPersonBottomSheetDialogModule::class]) + abstract fun contactDiaryPersonBottomSheetDialogFragment(): ContactDiaryPersonBottomSheetDialogFragment + + @ContributesAndroidInjector(modules = [ContactDiaryLocationBottomSheetDialogModule::class]) + abstract fun contactDiaryLocationBottomSheetDialogFragment(): ContactDiaryLocationBottomSheetDialogFragment + + @ContributesAndroidInjector(modules = [ContactDiaryOnboardingFragmentModule::class]) + abstract fun contactDiaryOnboardingFragment(): ContactDiaryOnboardingFragment + + @ContributesAndroidInjector(modules = [ContactDiaryOverviewFragmentModule::class]) + abstract fun contactDiaryOverviewFragment(): ContactDiaryOverviewFragment +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/ContactDiaryDayFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/ContactDiaryDayFragment.kt new file mode 100644 index 0000000000000000000000000000000000000000..b43c3bfb12def723eb8835aa33108eed153ef51e --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/ContactDiaryDayFragment.kt @@ -0,0 +1,82 @@ +package de.rki.coronawarnapp.contactdiary.ui.day + +import android.os.Bundle +import android.view.View +import androidx.fragment.app.Fragment +import androidx.navigation.fragment.navArgs +import com.google.android.material.tabs.TabLayoutMediator +import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.contactdiary.ui.day.tabs.ContactDiaryDayFragmentsAdapter +import de.rki.coronawarnapp.contactdiary.ui.day.tabs.ContactDiaryDayTab +import de.rki.coronawarnapp.contactdiary.util.registerOnPageChangeCallback +import de.rki.coronawarnapp.databinding.ContactDiaryDayFragmentBinding +import de.rki.coronawarnapp.util.di.AutoInject +import de.rki.coronawarnapp.util.ui.doNavigate +import de.rki.coronawarnapp.util.ui.observe2 +import de.rki.coronawarnapp.util.ui.popBackStack +import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider +import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted +import javax.inject.Inject + +class ContactDiaryDayFragment : Fragment(R.layout.contact_diary_day_fragment), AutoInject { + private val binding: ContactDiaryDayFragmentBinding by viewBindingLazy() + + private val navArgs by navArgs<ContactDiaryDayFragmentArgs>() + + @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory + private val viewModel: ContactDiaryDayViewModel by cwaViewModelsAssisted( + factoryProducer = { viewModelFactory }, + constructorCall = { factory, _ -> + factory as ContactDiaryDayViewModel.Factory + factory.create(navArgs.selectedDay) + } + ) + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + val contactDiaryTabs = listOf(ContactDiaryDayTab.PersonTab, ContactDiaryDayTab.LocationTab) + + val adapter = ContactDiaryDayFragmentsAdapter(this, contactDiaryTabs, navArgs.selectedDay) + + binding.contactDiaryDayViewPager.adapter = adapter + + TabLayoutMediator(binding.contactDiaryDayTabLayout, binding.contactDiaryDayViewPager) { tab, position -> + val tabSource = adapter.tabs[position] + tab.setText(tabSource.tabNameResource) + }.attach() + + binding.apply { + contactDiaryDayViewPager.registerOnPageChangeCallback { + binding.contactDiaryDayFab.setText(adapter.tabs[it].fabTextResource) + } + + contactDiaryDayFab.setOnClickListener { + viewModel.onCreateButtonClicked(adapter.tabs[contactDiaryDayTabLayout.selectedTabPosition]) + } + + contactDiaryDayHeader.headerButtonBack.buttonIcon.setOnClickListener { + viewModel.onBackPressed() + } + } + + viewModel.uiState.observe2(this) { + binding.contactDiaryDayHeader.title = it.dayText + } + + viewModel.routeToScreen.observe2(this) { + when (it) { + ContactDiaryDayNavigationEvents.NavigateToOverviewFragment -> popBackStack() + ContactDiaryDayNavigationEvents.NavigateToAddPersonBottomSheet -> doNavigate( + ContactDiaryDayFragmentDirections + .actionContactDiaryDayFragmentToContactDiaryPersonBottomSheetDialogFragment() + ) + ContactDiaryDayNavigationEvents.NavigateToAddLocationBottomSheet -> doNavigate( + ContactDiaryDayFragmentDirections + .actionContactDiaryDayFragmentToContactDiaryLocationBottomSheetDialogFragment() + ) + } + } + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/ContactDiaryDayModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/ContactDiaryDayModule.kt new file mode 100644 index 0000000000000000000000000000000000000000..a0fe530c9017956772438db18b6254ce0214f6e2 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/ContactDiaryDayModule.kt @@ -0,0 +1,18 @@ +package de.rki.coronawarnapp.contactdiary.ui.day + +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 ContactDiaryDayModule { + @Binds + @IntoMap + @CWAViewModelKey(ContactDiaryDayViewModel::class) + abstract fun contactDiaryDayFragment( + factory: ContactDiaryDayViewModel.Factory + ): CWAViewModelFactory<out CWAViewModel> +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/ContactDiaryDayNavigationEvents.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/ContactDiaryDayNavigationEvents.kt new file mode 100644 index 0000000000000000000000000000000000000000..8524c31442a6e990256712d41f3fb09e764f69ce --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/ContactDiaryDayNavigationEvents.kt @@ -0,0 +1,7 @@ +package de.rki.coronawarnapp.contactdiary.ui.day + +sealed class ContactDiaryDayNavigationEvents { + object NavigateToOverviewFragment : ContactDiaryDayNavigationEvents() + object NavigateToAddPersonBottomSheet : ContactDiaryDayNavigationEvents() + object NavigateToAddLocationBottomSheet : ContactDiaryDayNavigationEvents() +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/ContactDiaryDayViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/ContactDiaryDayViewModel.kt new file mode 100644 index 0000000000000000000000000000000000000000..dfe45bf08c0fddc5f5f6338359938ca96fa94926 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/ContactDiaryDayViewModel.kt @@ -0,0 +1,53 @@ +package de.rki.coronawarnapp.contactdiary.ui.day + +import androidx.lifecycle.asLiveData +import com.squareup.inject.assisted.Assisted +import com.squareup.inject.assisted.AssistedInject +import de.rki.coronawarnapp.contactdiary.ui.day.tabs.ContactDiaryDayTab +import de.rki.coronawarnapp.ui.SingleLiveEvent +import de.rki.coronawarnapp.util.coroutine.DispatcherProvider +import de.rki.coronawarnapp.util.viewmodel.CWAViewModel +import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.map +import org.joda.time.LocalDate +import org.joda.time.format.DateTimeFormat + +class ContactDiaryDayViewModel @AssistedInject constructor( + dispatcherProvider: DispatcherProvider, + @Assisted selectedDay: String +) : CWAViewModel(dispatcherProvider = dispatcherProvider) { + private val dateFormat by lazy { + DateTimeFormat.forPattern("EEEE, dd.MM.yy") + } + + private val displayedDay = MutableStateFlow(LocalDate.parse(selectedDay)) + + val routeToScreen: SingleLiveEvent<ContactDiaryDayNavigationEvents> = SingleLiveEvent() + + val uiState = displayedDay.map { day -> + UIState(dayText = day.toString(dateFormat)) + }.asLiveData() + + fun onCreateButtonClicked(activeTab: ContactDiaryDayTab) { + when (activeTab) { + ContactDiaryDayTab.LocationTab -> routeToScreen + .postValue(ContactDiaryDayNavigationEvents.NavigateToAddLocationBottomSheet) + ContactDiaryDayTab.PersonTab -> routeToScreen + .postValue(ContactDiaryDayNavigationEvents.NavigateToAddPersonBottomSheet) + } + } + + fun onBackPressed() { + routeToScreen.postValue(ContactDiaryDayNavigationEvents.NavigateToOverviewFragment) + } + + data class UIState( + val dayText: String + ) + + @AssistedInject.Factory + interface Factory : CWAViewModelFactory<ContactDiaryDayViewModel> { + fun create(selectedDay: String): ContactDiaryDayViewModel + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/sheets/location/ContactDiaryLocationBottomSheetDialogFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/sheets/location/ContactDiaryLocationBottomSheetDialogFragment.kt new file mode 100644 index 0000000000000000000000000000000000000000..f480e75dd09eb250fa33cb2cfd61d4ebcc826a76 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/sheets/location/ContactDiaryLocationBottomSheetDialogFragment.kt @@ -0,0 +1,57 @@ +package de.rki.coronawarnapp.contactdiary.ui.day.sheets.location + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.core.widget.doAfterTextChanged +import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import de.rki.coronawarnapp.databinding.ContactDiaryLocationBottomSheetFragmentBinding +import de.rki.coronawarnapp.util.di.AutoInject +import de.rki.coronawarnapp.util.ui.observe2 +import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider +import de.rki.coronawarnapp.util.viewmodel.cwaViewModels +import javax.inject.Inject + +class ContactDiaryLocationBottomSheetDialogFragment : BottomSheetDialogFragment(), AutoInject { + private var _binding: ContactDiaryLocationBottomSheetFragmentBinding? = null + private val binding get() = _binding!! + + @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory + private val viewModel: ContactDiaryLocationBottomSheetDialogViewModel by cwaViewModels { viewModelFactory } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + _binding = ContactDiaryLocationBottomSheetFragmentBinding.inflate(inflater) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + binding.contactDiaryLocationBottomSheetCloseButton.buttonIcon.setOnClickListener { + viewModel.closePressed() + } + + binding.contactDiaryLocationBottomSheetSaveButton.setOnClickListener { + viewModel.saveLocation() + } + + binding.contactDiaryLocationBottomSheetTextInputEditText.doAfterTextChanged { + viewModel.textChanged(it.toString()) + } + + viewModel.shouldClose.observe2(this) { + dismiss() + } + + viewModel.isValid.observe2(this) { + binding.contactDiaryLocationBottomSheetTextInputLayout.isErrorEnabled = it + binding.contactDiaryLocationBottomSheetSaveButton.isEnabled = it + } + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/sheets/location/ContactDiaryLocationBottomSheetDialogModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/sheets/location/ContactDiaryLocationBottomSheetDialogModule.kt new file mode 100644 index 0000000000000000000000000000000000000000..4acd5dd2fdf1ebaabe7047e5febd23f7cc7d3fb7 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/sheets/location/ContactDiaryLocationBottomSheetDialogModule.kt @@ -0,0 +1,18 @@ +package de.rki.coronawarnapp.contactdiary.ui.day.sheets.location + +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 ContactDiaryLocationBottomSheetDialogModule { + @Binds + @IntoMap + @CWAViewModelKey(ContactDiaryLocationBottomSheetDialogViewModel::class) + abstract fun contactDiaryLocationBottomSheetDialogFragment( + factory: ContactDiaryLocationBottomSheetDialogViewModel.Factory + ): CWAViewModelFactory<out CWAViewModel> +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/sheets/location/ContactDiaryLocationBottomSheetDialogViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/sheets/location/ContactDiaryLocationBottomSheetDialogViewModel.kt new file mode 100644 index 0000000000000000000000000000000000000000..974945328e528c840ef76b74fd9ad9fd814a4c8b --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/sheets/location/ContactDiaryLocationBottomSheetDialogViewModel.kt @@ -0,0 +1,49 @@ +package de.rki.coronawarnapp.contactdiary.ui.day.sheets.location + +import androidx.lifecycle.asLiveData +import com.squareup.inject.assisted.AssistedInject +import de.rki.coronawarnapp.contactdiary.storage.entity.ContactDiaryLocationEntity +import de.rki.coronawarnapp.contactdiary.storage.repo.ContactDiaryRepository +import de.rki.coronawarnapp.ui.SingleLiveEvent +import de.rki.coronawarnapp.util.coroutine.DispatcherProvider +import de.rki.coronawarnapp.util.viewmodel.CWAViewModel +import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.map + +class ContactDiaryLocationBottomSheetDialogViewModel @AssistedInject constructor( + dispatcherProvider: DispatcherProvider, + private val contactDiaryRepository: ContactDiaryRepository +) : CWAViewModel(dispatcherProvider = dispatcherProvider) { + private val text = MutableStateFlow("") + + val isValid = text.map { + it.isNotEmpty() && it.length <= MAX_LOCATION_NAME_LENGTH + }.asLiveData() + + val shouldClose = SingleLiveEvent<Unit>() + + fun textChanged(locationName: String) { + text.value = locationName + } + + fun saveLocation() = launch { + contactDiaryRepository.addLocation( + ContactDiaryLocationEntity( + locationName = text.value.take(MAX_LOCATION_NAME_LENGTH) + ) + ) + shouldClose.postValue(null) + } + + fun closePressed() { + shouldClose.postValue(null) + } + + companion object { + private const val MAX_LOCATION_NAME_LENGTH = 250 + } + + @AssistedInject.Factory + interface Factory : SimpleCWAViewModelFactory<ContactDiaryLocationBottomSheetDialogViewModel> +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/sheets/person/ContactDiaryPersonBottomSheetDialogFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/sheets/person/ContactDiaryPersonBottomSheetDialogFragment.kt new file mode 100644 index 0000000000000000000000000000000000000000..a96fdb12fad55af99e47ff7baacc33a019bf3d3b --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/sheets/person/ContactDiaryPersonBottomSheetDialogFragment.kt @@ -0,0 +1,57 @@ +package de.rki.coronawarnapp.contactdiary.ui.day.sheets.person + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.core.widget.doAfterTextChanged +import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import de.rki.coronawarnapp.databinding.ContactDiaryPersonBottomSheetFragmentBinding +import de.rki.coronawarnapp.util.di.AutoInject +import de.rki.coronawarnapp.util.ui.observe2 +import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider +import de.rki.coronawarnapp.util.viewmodel.cwaViewModels +import javax.inject.Inject + +class ContactDiaryPersonBottomSheetDialogFragment : BottomSheetDialogFragment(), AutoInject { + private var _binding: ContactDiaryPersonBottomSheetFragmentBinding? = null + private val binding get() = _binding!! + + @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory + private val viewModel: ContactDiaryPersonBottomSheetDialogViewModel by cwaViewModels { viewModelFactory } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + _binding = ContactDiaryPersonBottomSheetFragmentBinding.inflate(inflater) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + binding.contactDiaryPersonBottomSheetCloseButton.buttonIcon.setOnClickListener { + viewModel.closePressed() + } + + binding.contactDiaryPersonBottomSheetSaveButton.setOnClickListener { + viewModel.savePerson() + } + + binding.contactDiaryPersonBottomSheetTextInputEditText.doAfterTextChanged { + viewModel.textChanged(it.toString()) + } + + viewModel.shouldClose.observe2(this) { + dismiss() + } + + viewModel.isValid.observe2(this) { + binding.contactDiaryPersonBottomSheetTextInputLayout.isErrorEnabled = it + binding.contactDiaryPersonBottomSheetSaveButton.isEnabled = it + } + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/sheets/person/ContactDiaryPersonBottomSheetDialogModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/sheets/person/ContactDiaryPersonBottomSheetDialogModule.kt new file mode 100644 index 0000000000000000000000000000000000000000..4b710bec800209629ecdd9bf080b271150c790db --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/sheets/person/ContactDiaryPersonBottomSheetDialogModule.kt @@ -0,0 +1,18 @@ +package de.rki.coronawarnapp.contactdiary.ui.day.sheets.person + +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 ContactDiaryPersonBottomSheetDialogModule { + @Binds + @IntoMap + @CWAViewModelKey(ContactDiaryPersonBottomSheetDialogViewModel::class) + abstract fun contactDiaryPersonBottomSheetDialogFragment( + factory: ContactDiaryPersonBottomSheetDialogViewModel.Factory + ): CWAViewModelFactory<out CWAViewModel> +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/sheets/person/ContactDiaryPersonBottomSheetDialogViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/sheets/person/ContactDiaryPersonBottomSheetDialogViewModel.kt new file mode 100644 index 0000000000000000000000000000000000000000..39f00ca23fb42fe041bf8845c800acbe43a488b0 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/sheets/person/ContactDiaryPersonBottomSheetDialogViewModel.kt @@ -0,0 +1,49 @@ +package de.rki.coronawarnapp.contactdiary.ui.day.sheets.person + +import androidx.lifecycle.asLiveData +import com.squareup.inject.assisted.AssistedInject +import de.rki.coronawarnapp.contactdiary.storage.entity.ContactDiaryPersonEntity +import de.rki.coronawarnapp.contactdiary.storage.repo.ContactDiaryRepository +import de.rki.coronawarnapp.ui.SingleLiveEvent +import de.rki.coronawarnapp.util.coroutine.DispatcherProvider +import de.rki.coronawarnapp.util.viewmodel.CWAViewModel +import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.map + +class ContactDiaryPersonBottomSheetDialogViewModel @AssistedInject constructor( + dispatcherProvider: DispatcherProvider, + private val contactDiaryRepository: ContactDiaryRepository +) : CWAViewModel(dispatcherProvider = dispatcherProvider) { + private val text = MutableStateFlow("") + + val isValid = text.map { + it.isNotEmpty() && it.length <= MAX_PERSON_NAME_LENGTH + }.asLiveData() + + val shouldClose = SingleLiveEvent<Unit>() + + fun textChanged(locationName: String) { + text.value = locationName + } + + fun savePerson() = launch { + contactDiaryRepository.addPerson( + ContactDiaryPersonEntity( + fullName = text.value.take(MAX_PERSON_NAME_LENGTH) + ) + ) + shouldClose.postValue(null) + } + + fun closePressed() { + shouldClose.postValue(null) + } + + companion object { + private const val MAX_PERSON_NAME_LENGTH = 250 + } + + @AssistedInject.Factory + interface Factory : SimpleCWAViewModelFactory<ContactDiaryPersonBottomSheetDialogViewModel> +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/ContactDiaryDayFragmentsAdapter.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/ContactDiaryDayFragmentsAdapter.kt new file mode 100644 index 0000000000000000000000000000000000000000..cbb7a2b77b11cc28b5475489561581318d687a52 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/ContactDiaryDayFragmentsAdapter.kt @@ -0,0 +1,14 @@ +package de.rki.coronawarnapp.contactdiary.ui.day.tabs + +import androidx.fragment.app.Fragment +import androidx.viewpager2.adapter.FragmentStateAdapter + +class ContactDiaryDayFragmentsAdapter( + fragment: Fragment, + val tabs: List<ContactDiaryDayTab>, + private val day: String +) : FragmentStateAdapter(fragment) { + override fun getItemCount() = tabs.size + + override fun createFragment(position: Int): Fragment = tabs[position].fragmentInstantiation(day) +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/ContactDiaryDayTab.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/ContactDiaryDayTab.kt new file mode 100644 index 0000000000000000000000000000000000000000..59c65922a385c40e034ce97821f78f2bd47e5f03 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/ContactDiaryDayTab.kt @@ -0,0 +1,36 @@ +package de.rki.coronawarnapp.contactdiary.ui.day.tabs + +import androidx.fragment.app.Fragment +import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.contactdiary.ui.day.tabs.location.ContactDiaryLocationListFragment +import de.rki.coronawarnapp.contactdiary.ui.day.tabs.location.ContactDiaryLocationListFragmentArgs +import de.rki.coronawarnapp.contactdiary.ui.day.tabs.person.ContactDiaryPersonListFragment +import de.rki.coronawarnapp.contactdiary.ui.day.tabs.person.ContactDiaryPersonListFragmentArgs + +sealed class ContactDiaryDayTab( + val tabNameResource: Int, + val fabTextResource: Int, + val fragmentInstantiation: (day: String) -> Fragment +) { + object PersonTab : ContactDiaryDayTab( + R.string.contact_diary_day_person_tab_title, + R.string.contact_diary_day_person_fab_title, + { day -> + ContactDiaryPersonListFragment().apply { + // Feels kind of hacky but i like the free typesafety for the args + arguments = ContactDiaryPersonListFragmentArgs(day).toBundle() + } + } + ) + + object LocationTab : ContactDiaryDayTab( + R.string.contact_diary_day_location_tab_title, + R.string.contact_diary_day_location_fab_title, + { day -> + ContactDiaryLocationListFragment().apply { + // Feels kind of hacky but i like the free typesafety for the args + arguments = ContactDiaryLocationListFragmentArgs(day).toBundle() + } + } + ) +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/location/ContactDiaryLocationListAdapter.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/location/ContactDiaryLocationListAdapter.kt new file mode 100644 index 0000000000000000000000000000000000000000..70490cc8ca2e2837b073834e1348a344b2e4cc1b --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/location/ContactDiaryLocationListAdapter.kt @@ -0,0 +1,52 @@ +package de.rki.coronawarnapp.contactdiary.ui.day.tabs.location + +import android.view.ViewGroup +import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.contactdiary.model.ContactDiaryLocation +import de.rki.coronawarnapp.contactdiary.util.SelectableItem +import de.rki.coronawarnapp.databinding.ContactDiaryLocationListLineBinding +import de.rki.coronawarnapp.ui.lists.BaseAdapter +import de.rki.coronawarnapp.util.lists.BindableVH +import de.rki.coronawarnapp.util.lists.diffutil.AsyncDiffUtilAdapter +import de.rki.coronawarnapp.util.lists.diffutil.AsyncDiffer + +class ContactDiaryLocationListAdapter( + private val onTappedCallback: (item: SelectableItem<ContactDiaryLocation>) -> Unit +) : BaseAdapter<ContactDiaryLocationListAdapter.CachedLocationViewHolder>(), + AsyncDiffUtilAdapter<SelectableItem<ContactDiaryLocation>> { + + override val asyncDiffer: AsyncDiffer<SelectableItem<ContactDiaryLocation>> = AsyncDiffer(this) + + override fun getItemCount(): Int = data.size + + override fun getItemId(position: Int): Long = data[position].stableId + + override fun onCreateBaseVH(parent: ViewGroup, viewType: Int): CachedLocationViewHolder = + CachedLocationViewHolder(parent) + + override fun onBindBaseVH(holder: CachedLocationViewHolder, position: Int) { + val item = data[position] + holder.itemView.setOnClickListener { + onTappedCallback(item) + } + holder.bind(item) + } + + class CachedLocationViewHolder( + parent: ViewGroup + ) : BaseAdapter.VH(R.layout.contact_diary_location_list_line, parent), + BindableVH<SelectableItem<ContactDiaryLocation>, ContactDiaryLocationListLineBinding> { + override val viewBinding = lazy { ContactDiaryLocationListLineBinding.bind(itemView) } + + override val onBindData: ContactDiaryLocationListLineBinding.( + key: SelectableItem<ContactDiaryLocation> + ) -> Unit = + { + contactDiaryLocationListLineName.text = it.item.locationName + when (it.selected) { + true -> contactDiaryLocationListLineIcon.setImageResource(R.drawable.ic_selected) + false -> contactDiaryLocationListLineIcon.setImageResource(R.drawable.ic_unselected) + } + } + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/location/ContactDiaryLocationListFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/location/ContactDiaryLocationListFragment.kt new file mode 100644 index 0000000000000000000000000000000000000000..4d7582902d16efe1b84021187476299154077738 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/location/ContactDiaryLocationListFragment.kt @@ -0,0 +1,55 @@ +package de.rki.coronawarnapp.contactdiary.ui.day.tabs.location + +import android.os.Bundle +import android.view.View +import androidx.fragment.app.Fragment +import androidx.navigation.fragment.navArgs +import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.contactdiary.util.MarginRecyclerViewDecoration +import de.rki.coronawarnapp.databinding.ContactDiaryLocationListFragmentBinding +import de.rki.coronawarnapp.util.di.AutoInject +import de.rki.coronawarnapp.util.lists.diffutil.update +import de.rki.coronawarnapp.util.ui.observe2 +import de.rki.coronawarnapp.util.ui.setInvisible +import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider +import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted +import javax.inject.Inject + +class ContactDiaryLocationListFragment : Fragment(R.layout.contact_diary_location_list_fragment), AutoInject { + private val binding: ContactDiaryLocationListFragmentBinding by viewBindingLazy() + + private val navArgs by navArgs<ContactDiaryLocationListFragmentArgs>() + + @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory + private val viewModel: ContactDiaryLocationListViewModel by cwaViewModelsAssisted( + factoryProducer = { viewModelFactory }, + constructorCall = { factory, _ -> + factory as ContactDiaryLocationListViewModel.Factory + factory.create(navArgs.selectedDay) + } + ) + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + val locationListAdapter = ContactDiaryLocationListAdapter { + viewModel.locationSelectionChanged(it) + } + + binding.contactDiaryLocationListRecyclerView.apply { + adapter = locationListAdapter + addItemDecoration( + MarginRecyclerViewDecoration( + resources.getDimensionPixelSize(R.dimen.spacing_tiny) + ) + ) + } + + viewModel.uiList.observe2(this) { + locationListAdapter.update(it) + + binding.contactDiaryLocationListNoItemsGroup.setInvisible(it.isNotEmpty()) + } + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/location/ContactDiaryLocationListModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/location/ContactDiaryLocationListModule.kt new file mode 100644 index 0000000000000000000000000000000000000000..199dfbcb7629c7114a68c2c1dfb6e755f8426e7e --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/location/ContactDiaryLocationListModule.kt @@ -0,0 +1,18 @@ +package de.rki.coronawarnapp.contactdiary.ui.day.tabs.location + +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 ContactDiaryLocationListModule { + @Binds + @IntoMap + @CWAViewModelKey(ContactDiaryLocationListViewModel::class) + abstract fun contactDiaryLocationListFragment( + factory: ContactDiaryLocationListViewModel.Factory + ): CWAViewModelFactory<out CWAViewModel> +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/location/ContactDiaryLocationListViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/location/ContactDiaryLocationListViewModel.kt new file mode 100644 index 0000000000000000000000000000000000000000..e0b822eabef121591fc3b5acdaf61874b0d5f128 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/location/ContactDiaryLocationListViewModel.kt @@ -0,0 +1,57 @@ +package de.rki.coronawarnapp.contactdiary.ui.day.tabs.location + +import androidx.lifecycle.asLiveData +import com.squareup.inject.assisted.Assisted +import com.squareup.inject.assisted.AssistedInject +import de.rki.coronawarnapp.contactdiary.model.ContactDiaryLocation +import de.rki.coronawarnapp.contactdiary.model.DefaultContactDiaryLocationVisit +import de.rki.coronawarnapp.contactdiary.storage.repo.ContactDiaryRepository +import de.rki.coronawarnapp.contactdiary.util.SelectableItem +import de.rki.coronawarnapp.util.coroutine.DispatcherProvider +import de.rki.coronawarnapp.util.viewmodel.CWAViewModel +import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.first +import org.joda.time.LocalDate + +class ContactDiaryLocationListViewModel @AssistedInject constructor( + dispatcherProvider: DispatcherProvider, + @Assisted selectedDay: String, + private val contactDiaryRepository: ContactDiaryRepository +) : CWAViewModel(dispatcherProvider = dispatcherProvider) { + + private val localDate = LocalDate.parse(selectedDay) + + private val dayElement = contactDiaryRepository.locationVisitsForDate(localDate) + private val selectableLocations = contactDiaryRepository.locations + + val uiList = selectableLocations.combine(dayElement) { locations, dayElement -> + locations.map { contactDiaryLocation -> + if (dayElement.any { it.contactDiaryLocation.locationId == contactDiaryLocation.locationId }) { + SelectableItem(true, contactDiaryLocation) + } else { + SelectableItem(false, contactDiaryLocation) + } + } + }.asLiveData() + + fun locationSelectionChanged(item: SelectableItem<ContactDiaryLocation>) = launch { + if (!item.selected) { + contactDiaryRepository.addLocationVisit( + DefaultContactDiaryLocationVisit( + date = localDate, + contactDiaryLocation = item.item + ) + ) + } else { + val visit = dayElement.first() + .find { it.contactDiaryLocation.locationId == item.item.locationId } + visit?.let { contactDiaryRepository.deleteLocationVisit(it) } + } + } + + @AssistedInject.Factory + interface Factory : CWAViewModelFactory<ContactDiaryLocationListViewModel> { + fun create(selectedDay: String): ContactDiaryLocationListViewModel + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/person/ContactDiaryPersonListAdapter.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/person/ContactDiaryPersonListAdapter.kt new file mode 100644 index 0000000000000000000000000000000000000000..7829a7492cbc9cdac6c0bf7b1e9275058abcc4fb --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/person/ContactDiaryPersonListAdapter.kt @@ -0,0 +1,51 @@ +package de.rki.coronawarnapp.contactdiary.ui.day.tabs.person + +import android.view.ViewGroup +import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.contactdiary.model.ContactDiaryPerson +import de.rki.coronawarnapp.contactdiary.util.SelectableItem +import de.rki.coronawarnapp.databinding.ContactDiaryPersonListLineBinding +import de.rki.coronawarnapp.ui.lists.BaseAdapter +import de.rki.coronawarnapp.util.lists.BindableVH +import de.rki.coronawarnapp.util.lists.diffutil.AsyncDiffUtilAdapter +import de.rki.coronawarnapp.util.lists.diffutil.AsyncDiffer + +class ContactDiaryPersonListAdapter( + private val onTappedCallback: (item: SelectableItem<ContactDiaryPerson>) -> Unit +) : BaseAdapter<ContactDiaryPersonListAdapter.CachedPersonViewHolder>(), + AsyncDiffUtilAdapter<SelectableItem<ContactDiaryPerson>> { + + override val asyncDiffer: AsyncDiffer<SelectableItem<ContactDiaryPerson>> = AsyncDiffer(this) + + override fun getItemCount(): Int = data.size + + override fun getItemId(position: Int): Long = data[position].stableId + + override fun onCreateBaseVH(parent: ViewGroup, viewType: Int): CachedPersonViewHolder = + CachedPersonViewHolder(parent) + + override fun onBindBaseVH(holder: CachedPersonViewHolder, position: Int) { + val item = data[position] + holder.itemView.setOnClickListener { + onTappedCallback(item) + } + holder.bind(item) + } + + class CachedPersonViewHolder( + parent: ViewGroup + ) : BaseAdapter.VH(R.layout.contact_diary_person_list_line, parent), + BindableVH<SelectableItem<ContactDiaryPerson>, ContactDiaryPersonListLineBinding> { + override val viewBinding = lazy { ContactDiaryPersonListLineBinding.bind(itemView) } + + override val onBindData: ContactDiaryPersonListLineBinding.( + key: SelectableItem<ContactDiaryPerson> + ) -> Unit = { + contactDiaryPersonListLineName.text = it.item.fullName + when (it.selected) { + true -> contactDiaryPersonListLineIcon.setImageResource(R.drawable.ic_selected) + false -> contactDiaryPersonListLineIcon.setImageResource(R.drawable.ic_unselected) + } + } + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/person/ContactDiaryPersonListFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/person/ContactDiaryPersonListFragment.kt new file mode 100644 index 0000000000000000000000000000000000000000..d5ed5aef570169fdff70e7219a804d91ee8f79fd --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/person/ContactDiaryPersonListFragment.kt @@ -0,0 +1,55 @@ +package de.rki.coronawarnapp.contactdiary.ui.day.tabs.person + +import android.os.Bundle +import android.view.View +import androidx.fragment.app.Fragment +import androidx.navigation.fragment.navArgs +import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.contactdiary.util.MarginRecyclerViewDecoration +import de.rki.coronawarnapp.databinding.ContactDiaryPersonListFragmentBinding +import de.rki.coronawarnapp.util.di.AutoInject +import de.rki.coronawarnapp.util.lists.diffutil.update +import de.rki.coronawarnapp.util.ui.observe2 +import de.rki.coronawarnapp.util.ui.setInvisible +import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider +import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted +import javax.inject.Inject + +class ContactDiaryPersonListFragment : Fragment(R.layout.contact_diary_person_list_fragment), AutoInject { + private val binding: ContactDiaryPersonListFragmentBinding by viewBindingLazy() + + private val navArgs by navArgs<ContactDiaryPersonListFragmentArgs>() + + @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory + private val viewModel: ContactDiaryPersonListViewModel by cwaViewModelsAssisted( + factoryProducer = { viewModelFactory }, + constructorCall = { factory, _ -> + factory as ContactDiaryPersonListViewModel.Factory + factory.create(navArgs.selectedDay) + } + ) + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + val personListAdapter = ContactDiaryPersonListAdapter { + viewModel.personSelectionChanged(it) + } + + binding.contactDiaryPersonListRecyclerView.apply { + adapter = personListAdapter + addItemDecoration( + MarginRecyclerViewDecoration( + resources.getDimensionPixelSize(R.dimen.spacing_tiny) + ) + ) + } + + viewModel.uiList.observe2(this) { + personListAdapter.update(it) + + binding.contactDiaryPersonListNoItemsGroup.setInvisible(it.isNotEmpty()) + } + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/person/ContactDiaryPersonListModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/person/ContactDiaryPersonListModule.kt new file mode 100644 index 0000000000000000000000000000000000000000..22c393ce2d2d5a6657fd505c2f4ce69f65420499 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/person/ContactDiaryPersonListModule.kt @@ -0,0 +1,18 @@ +package de.rki.coronawarnapp.contactdiary.ui.day.tabs.person + +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 ContactDiaryPersonListModule { + @Binds + @IntoMap + @CWAViewModelKey(ContactDiaryPersonListViewModel::class) + abstract fun contactDiaryPersonListFragment( + factory: ContactDiaryPersonListViewModel.Factory + ): CWAViewModelFactory<out CWAViewModel> +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/person/ContactDiaryPersonListViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/person/ContactDiaryPersonListViewModel.kt new file mode 100644 index 0000000000000000000000000000000000000000..29b48d3b6652f4963981a3edd51bb144766df758 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/person/ContactDiaryPersonListViewModel.kt @@ -0,0 +1,57 @@ +package de.rki.coronawarnapp.contactdiary.ui.day.tabs.person + +import androidx.lifecycle.asLiveData +import com.squareup.inject.assisted.Assisted +import com.squareup.inject.assisted.AssistedInject +import de.rki.coronawarnapp.contactdiary.model.ContactDiaryPerson +import de.rki.coronawarnapp.contactdiary.model.DefaultContactDiaryPersonEncounter +import de.rki.coronawarnapp.contactdiary.storage.repo.ContactDiaryRepository +import de.rki.coronawarnapp.contactdiary.util.SelectableItem +import de.rki.coronawarnapp.util.coroutine.DispatcherProvider +import de.rki.coronawarnapp.util.viewmodel.CWAViewModel +import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.first +import org.joda.time.LocalDate + +class ContactDiaryPersonListViewModel @AssistedInject constructor( + dispatcherProvider: DispatcherProvider, + @Assisted selectedDay: String, + private val contactDiaryRepository: ContactDiaryRepository +) : CWAViewModel(dispatcherProvider = dispatcherProvider) { + + private val localDate = LocalDate.parse(selectedDay) + + private val dayElement = contactDiaryRepository.personEncountersForDate(localDate) + private val selectablePersons = contactDiaryRepository.people + + val uiList = selectablePersons.combine(dayElement) { persons, dayElement -> + persons.map { contactDiaryPerson -> + if (dayElement.any { it.contactDiaryPerson.personId == contactDiaryPerson.personId }) { + SelectableItem(true, contactDiaryPerson) + } else { + SelectableItem(false, contactDiaryPerson) + } + } + }.asLiveData() + + fun personSelectionChanged(item: SelectableItem<ContactDiaryPerson>) = launch { + if (!item.selected) { + contactDiaryRepository.addPersonEncounter( + DefaultContactDiaryPersonEncounter( + date = localDate, + contactDiaryPerson = item.item + ) + ) + } else { + val visit = dayElement.first() + .find { it.contactDiaryPerson.personId == item.item.personId } + visit?.let { contactDiaryRepository.deletePersonEncounter(it) } + } + } + + @AssistedInject.Factory + interface Factory : CWAViewModelFactory<ContactDiaryPersonListViewModel> { + fun create(selectedDay: String): ContactDiaryPersonListViewModel + } +} 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 c037f5c4e46945d938a72eab1b09623762ccd4f2..d4bdaafbc3add6900446fb303e3a4294a8752c0e 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 @@ -3,7 +3,6 @@ package de.rki.coronawarnapp.contactdiary.ui.onboarding import android.os.Bundle import android.view.View import androidx.fragment.app.Fragment -import androidx.navigation.ActionOnlyNavDirections import de.rki.coronawarnapp.R import de.rki.coronawarnapp.contactdiary.ui.ContactDiaryActivity import de.rki.coronawarnapp.databinding.ContactDiaryOnboardingFragmentBinding @@ -46,24 +45,18 @@ class ContactDiaryOnboardingFragment : Fragment(R.layout.contact_diary_onboardin ContactDiaryOnboardingNavigationEvents.NavigateToPrivacyFragment -> { doNavigate( - ActionOnlyNavDirections( - R.id.action_contactDiaryOnboardingFragment_to_contactDiaryInformationPrivacyFragment - ) + ContactDiaryOnboardingFragmentDirections + .actionContactDiaryOnboardingFragmentToContactDiaryInformationPrivacyFragment() ) } ContactDiaryOnboardingNavigationEvents.NavigateToOverviewFragment -> { doNavigate( - ActionOnlyNavDirections( - R.id.action_contactDiaryOnboardingFragment_to_contactDiaryOverviewFragment - ) + ContactDiaryOnboardingFragmentDirections + .actionContactDiaryOnboardingFragmentToContactDiaryOverviewFragment() ) } } } } - - override fun onResume() { - super.onResume() - } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/onboarding/ContactDiaryOnboardingFragmentModul.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/onboarding/ContactDiaryOnboardingFragmentModul.kt deleted file mode 100644 index 0b338fb706ed76c00846cb72814e46a4c521c15f..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/onboarding/ContactDiaryOnboardingFragmentModul.kt +++ /dev/null @@ -1,23 +0,0 @@ -package de.rki.coronawarnapp.contactdiary.ui.onboarding - -import dagger.Binds -import dagger.Module -import dagger.android.ContributesAndroidInjector -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 ContactDiaryOnboardingFragmentModul { - - @Binds - @IntoMap - @CWAViewModelKey(ContactDiaryOnboardingFragmentViewModel::class) - abstract fun contactDiaryOnboardingFragmentVM( - factory: ContactDiaryOnboardingFragmentViewModel.Factory - ): CWAViewModelFactory<out CWAViewModel> - - @ContributesAndroidInjector - abstract fun contactDiaryOnboardingFragmentVM(): ContactDiaryOnboardingFragment -} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/onboarding/ContactDiaryOnboardingFragmentModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/onboarding/ContactDiaryOnboardingFragmentModule.kt index 55afd7903e47e57f62c739a85ccb27edfb38c448..9f96cf4c50de3c1916af695c69e4c278107e914c 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/onboarding/ContactDiaryOnboardingFragmentModule.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/onboarding/ContactDiaryOnboardingFragmentModule.kt @@ -9,7 +9,6 @@ import de.rki.coronawarnapp.util.viewmodel.CWAViewModelKey @Module abstract class ContactDiaryOnboardingFragmentModule { - @Binds @IntoMap @CWAViewModelKey(ContactDiaryOnboardingFragmentViewModel::class) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/onboarding/ContactDiaryOnboardingNavigationEvents.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/onboarding/ContactDiaryOnboardingNavigationEvents.kt index 62578f22e7ef6f117fe12dc25461cf2176f7dce1..2ead88460287865a691543fdca71969fc0ff38df 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/onboarding/ContactDiaryOnboardingNavigationEvents.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/onboarding/ContactDiaryOnboardingNavigationEvents.kt @@ -1,7 +1,6 @@ package de.rki.coronawarnapp.contactdiary.ui.onboarding sealed class ContactDiaryOnboardingNavigationEvents { - object NavigateToMainActivity : ContactDiaryOnboardingNavigationEvents() object NavigateToPrivacyFragment : ContactDiaryOnboardingNavigationEvents() object NavigateToOverviewFragment : ContactDiaryOnboardingNavigationEvents() 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 6711d86dd01261b4862d058151d80df98b4a72ec..63a39c72f3055e641fbb4e325599a59bae72169b 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 @@ -2,12 +2,12 @@ package de.rki.coronawarnapp.contactdiary.ui.overview import android.os.Bundle import android.view.View -import android.widget.Toast import androidx.fragment.app.Fragment import de.rki.coronawarnapp.R import de.rki.coronawarnapp.contactdiary.ui.overview.adapter.ContactDiaryOverviewAdapter import de.rki.coronawarnapp.databinding.ContactDiaryOverviewFragmentBinding import de.rki.coronawarnapp.util.di.AutoInject +import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.viewBindingLazy import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider @@ -48,12 +48,10 @@ class ContactDiaryOverviewFragment : Fragment(R.layout.contact_diary_overview_fr } is ContactDiaryOverviewNavigationEvents.NavigateToContactDiaryDayFragment -> { - // TODO(Really navigate to ContactDiaryDayFragment once it is merged) - Toast.makeText( - requireContext(), - "Navigate to ContactDiaryDayFragment with date ${it.localDateString}", - Toast.LENGTH_SHORT - ).show() + doNavigate( + ContactDiaryOverviewFragmentDirections + .actionContactDiaryOverviewFragmentToContactDiaryDayFragment(it.localDateString) + ) } } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/overview/ContactDiaryOverviewFragmentModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/overview/ContactDiaryOverviewFragmentModule.kt index 23c65456ceb16af6f01825c6af00080cda69cf26..ca3dba936f6eaab1acd6fb31c3930f83c2f55a40 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/overview/ContactDiaryOverviewFragmentModule.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/overview/ContactDiaryOverviewFragmentModule.kt @@ -2,7 +2,6 @@ package de.rki.coronawarnapp.contactdiary.ui.overview import dagger.Binds import dagger.Module -import dagger.android.ContributesAndroidInjector import dagger.multibindings.IntoMap import de.rki.coronawarnapp.util.viewmodel.CWAViewModel import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory @@ -10,14 +9,10 @@ import de.rki.coronawarnapp.util.viewmodel.CWAViewModelKey @Module abstract class ContactDiaryOverviewFragmentModule { - @Binds @IntoMap @CWAViewModelKey(ContactDiaryOverviewViewModel::class) abstract fun contactDiaryOverviewFragmentVM( factory: ContactDiaryOverviewViewModel.Factory ): CWAViewModelFactory<out CWAViewModel> - - @ContributesAndroidInjector - abstract fun contactDiaryOverviewFragmentVM(): ContactDiaryOverviewFragment } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/overview/ContactDiaryOverviewMenu.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/overview/ContactDiaryOverviewMenu.kt index e3827f479228eeae6751ddfad4c0ace71d0d1651..6f757e6811108917dafffe58a7322fa8a5b457de 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/overview/ContactDiaryOverviewMenu.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/overview/ContactDiaryOverviewMenu.kt @@ -3,8 +3,6 @@ package de.rki.coronawarnapp.contactdiary.ui.overview import android.content.Context import android.view.View import android.widget.PopupMenu -import androidx.navigation.NavController -import androidx.navigation.fragment.findNavController import de.rki.coronawarnapp.R import javax.inject.Inject @@ -13,9 +11,6 @@ class ContactDiaryOverviewMenu @Inject constructor( ) { private val context: Context = contactDiaryOverviewFragment.requireContext() - private val navController: NavController - get() = contactDiaryOverviewFragment.findNavController() - fun showMenuFor(view: View) = PopupMenu(context, view).apply { inflate(R.menu.menu_contact_diary_overview) setOnMenuItemClickListener { diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/overview/ContactDiaryOverviewNavigationEvents.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/overview/ContactDiaryOverviewNavigationEvents.kt index dc5c1b9206e1b62b0b6680f08d8027ae5f60e728..0b23724e910c6d4711b478724e6a79265800f0f0 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/overview/ContactDiaryOverviewNavigationEvents.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/overview/ContactDiaryOverviewNavigationEvents.kt @@ -3,7 +3,6 @@ package de.rki.coronawarnapp.contactdiary.ui.overview import org.joda.time.LocalDate sealed class ContactDiaryOverviewNavigationEvents { - object NavigateToMainActivity : ContactDiaryOverviewNavigationEvents() class NavigateToContactDiaryDayFragment(localDate: LocalDate) : ContactDiaryOverviewNavigationEvents() { val localDateString = localDate.toString() diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/overview/ContactDiaryOverviewViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/overview/ContactDiaryOverviewViewModel.kt index 6040579a78464217a9ac619651aefdaadb611181..2d77b68d9c762c9c102ceda7fefbbf3f10523b01 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/overview/ContactDiaryOverviewViewModel.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/overview/ContactDiaryOverviewViewModel.kt @@ -18,7 +18,6 @@ import timber.log.Timber class ContactDiaryOverviewViewModel @AssistedInject constructor( contactDiaryRepository: ContactDiaryRepository ) : CWAViewModel() { - val routeToScreen: SingleLiveEvent<ContactDiaryOverviewNavigationEvents> = SingleLiveEvent() private val dates = flowOf((0 until DAY_COUNT).map { LocalDate.now().minusDays(it) }) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/util/ContactDiaryExtensions.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/util/ContactDiaryExtensions.kt new file mode 100644 index 0000000000000000000000000000000000000000..e8083d9a51275277c302c0491e6697936ff7cf80 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/util/ContactDiaryExtensions.kt @@ -0,0 +1,11 @@ +package de.rki.coronawarnapp.contactdiary.util + +import androidx.viewpager2.widget.ViewPager2 + +fun ViewPager2.registerOnPageChangeCallback(cb: (position: Int) -> Unit) { + this.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { + override fun onPageSelected(position: Int) { + cb(position) + } + }) +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/util/MarginRecyclerViewDecoration.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/util/MarginRecyclerViewDecoration.kt new file mode 100644 index 0000000000000000000000000000000000000000..683215f3fb20c89d8dd17729f6d57773cd6f92d5 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/util/MarginRecyclerViewDecoration.kt @@ -0,0 +1,23 @@ +package de.rki.coronawarnapp.contactdiary.util + +import android.graphics.Rect +import android.view.View +import androidx.recyclerview.widget.RecyclerView + +class MarginRecyclerViewDecoration(private val size: Int) : RecyclerView.ItemDecoration() { + override fun getItemOffsets( + outRect: Rect, + view: View, + parent: RecyclerView, + state: RecyclerView.State + ) { + with(outRect) { + if (parent.getChildAdapterPosition(view) == 0) { + top = size + } + left = size + right = size + bottom = size + } + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/util/SelectableItem.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/util/SelectableItem.kt new file mode 100644 index 0000000000000000000000000000000000000000..bcb816f356014e3f267057683a3aa87acc04bc4f --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/util/SelectableItem.kt @@ -0,0 +1,9 @@ +package de.rki.coronawarnapp.contactdiary.util + +import de.rki.coronawarnapp.util.lists.HasStableId + +data class SelectableItem<T : HasStableId>( + val selected: Boolean, + val item: T, + override val stableId: Long = item.stableId +) : HasStableId 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 fcb08e3b13c390a660e3b35f12327e9fa7e21786..be99bd0647f1cfd07e087f595989465870bc5099 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,8 +2,6 @@ package de.rki.coronawarnapp.ui import dagger.Module import dagger.android.ContributesAndroidInjector -import de.rki.coronawarnapp.contactdiary.ui.ContactDiaryActivity -import de.rki.coronawarnapp.contactdiary.ui.ContactDiaryModule import de.rki.coronawarnapp.ui.launcher.LauncherActivity import de.rki.coronawarnapp.ui.launcher.LauncherActivityModule import de.rki.coronawarnapp.ui.main.MainActivity @@ -22,7 +20,4 @@ abstract class ActivityBinder { @ContributesAndroidInjector(modules = [OnboardingActivityModule::class]) abstract fun onboardingActivity(): OnboardingActivity - - @ContributesAndroidInjector(modules = [ContactDiaryModule::class]) - abstract fun contactDiaryActivity(): ContactDiaryActivity } 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 9e23785a4d36a4bfeaff26b44520258ec36cede2..6a81216b0f222dbcf5b2229d6b709ef6d0726988 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 @@ -9,7 +9,7 @@ import de.rki.coronawarnapp.appconfig.AppConfigModule import de.rki.coronawarnapp.appconfig.AppConfigProvider import de.rki.coronawarnapp.bugreporting.BugReporter import de.rki.coronawarnapp.bugreporting.BugReportingModule -import de.rki.coronawarnapp.contactdiary.ContactDiaryModule +import de.rki.coronawarnapp.contactdiary.ContactDiaryRootModule import de.rki.coronawarnapp.diagnosiskeys.DiagnosisKeysModule import de.rki.coronawarnapp.diagnosiskeys.DownloadDiagnosisKeysTaskModule import de.rki.coronawarnapp.diagnosiskeys.storage.KeyCacheRepository @@ -70,7 +70,7 @@ import javax.inject.Singleton BugReportingModule::class, SerializationModule::class, WorkerBinder::class, - ContactDiaryModule::class + ContactDiaryRootModule::class ] ) interface ApplicationComponent : AndroidInjector<CoronaWarnApplication> { diff --git a/Corona-Warn-App/src/main/res/drawable-night/ic_illustration_no_locations.xml b/Corona-Warn-App/src/main/res/drawable-night/ic_illustration_no_locations.xml new file mode 100644 index 0000000000000000000000000000000000000000..f5249e0bf715a0d70094fe7990ce3824d1aecf46 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable-night/ic_illustration_no_locations.xml @@ -0,0 +1,23 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="200dp" + android:height="200dp" + android:viewportWidth="200" + android:viewportHeight="200"> + <group> + <clip-path android:pathData="M100,100m-100,0a100,100 0,1 1,200 0a100,100 0,1 1,-200 0" /> + <path + android:fillColor="#333337" + android:pathData="M-9.091,-6.818h224.242v257.576h-224.242z" /> + <path + android:fillColor="#2B2B2D" + android:fillType="evenOdd" + android:pathData="M123.056,77.044L122.85,129.087H105.802V124.166H51.935V116.945H19.715V140.922H8.134V149.907H-40V208H-21.569H-3.443H8.134H19.715H26.26H64.019V207.823H100.77V208H125.436H137.272H170.549H172.957H184.967H203.524H226.846H233.365H261.227H272.254H291.063V198.63L349,206.658V146.985H291.063V114.886H272.254V106.935H226.846V118.06H211.78V102.174H184.967V77L123.056,77.044Z" /> + <path + android:fillColor="#747576" + android:pathData="M100,39C76.227,39 57,58.093 57,81.7C57,113.725 100,161 100,161C100,161 143,113.725 143,81.7C143,58.093 123.773,39 100,39ZM100,96.95C91.523,96.95 84.643,90.118 84.643,81.7C84.643,73.282 91.523,66.45 100,66.45C108.477,66.45 115.357,73.282 115.357,81.7C115.357,90.118 108.477,96.95 100,96.95Z" /> + <path + android:fillColor="#3F3F43" + android:fillType="evenOdd" + android:pathData="M112.677,163.277C76.438,163.277 60.651,141.575 26.816,145.683C18.774,146.66 8.561,149.711 -2.909,158.268V212.582L375.514,213.931V166.239C373.414,165.038 371.319,164.012 369.336,163.262C369.336,163.262 331.203,148.534 288.973,161.136C252.802,171.94 211.135,143.661 191.174,142.928C189.31,142.859 187.511,142.827 185.783,142.827C142.656,142.824 140.594,163.277 112.677,163.277Z" /> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable-night/ic_illustration_no_people.xml b/Corona-Warn-App/src/main/res/drawable-night/ic_illustration_no_people.xml new file mode 100644 index 0000000000000000000000000000000000000000..9d7916d3e975eade9c22b8c60d8d67f65316ecaf --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable-night/ic_illustration_no_people.xml @@ -0,0 +1,75 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="200dp" + android:height="200dp" + android:viewportWidth="200" + android:viewportHeight="200"> + <group> + <clip-path android:pathData="M100,100m-100,0a100,100 0,1 1,200 0a100,100 0,1 1,-200 0" /> + <path + android:fillColor="#2D2D2F" + android:pathData="M-9.091,-6.818h224.242v257.576h-224.242z" /> + <path + android:fillColor="#3F3F43" + android:fillType="evenOdd" + android:pathData="M-31.146,141.336C-83.144,141.336 -105.797,110.204 -154.347,116.098C-165.887,117.499 -180.542,121.876 -197,134.151V212.065L346,214V145.585C342.986,143.863 339.98,142.391 337.135,141.314C337.135,141.314 282.418,120.186 221.821,138.264C169.92,153.763 110.133,113.197 81.49,112.145C78.816,112.046 76.234,112 73.754,112C11.872,111.996 8.913,141.336 -31.146,141.336Z" /> + <path + android:fillColor="#333337" + android:fillType="evenOdd" + android:pathData="M20.842,73.288C15.227,73.431 12.013,81.43 11.745,85.229C10.601,101.491 0.658,113.088 1.579,138.418C2.182,155.016 8,172.068 14.153,175.053C26.002,180.802 33.951,167.998 35.288,156.057C36.626,144.117 37.428,126.749 28.6,105.039C23.698,92.984 32.086,73.001 20.842,73.288Z" /> + <path + android:fillColor="#1E1E1F" + android:fillType="evenOdd" + android:pathData="M17.012,119.964C16.994,119.943 10.349,112.043 10.795,106.151L11.404,106.201C10.979,111.826 17.459,119.523 17.475,119.544L17.012,119.964Z" /> + <path + android:fillColor="#1E1E1F" + android:fillType="evenOdd" + android:pathData="M20.399,177.094C19.353,172.585 17.004,149.987 16.942,125.523C16.905,110.67 17.708,95.122 20.158,82.504L20.817,82.624C18.376,95.201 17.575,110.707 17.612,125.523C17.674,149.936 20.011,172.463 21.053,176.952L20.399,177.094Z" /> + <path + android:fillColor="#1E1E1F" + android:fillType="evenOdd" + android:pathData="M17.641,148.7C17.665,148.659 25.378,135.949 26.567,130.827L27.223,130.971C26.01,136.193 18.244,148.991 18.219,149.033L17.641,148.7Z" /> + <path + android:fillColor="#333337" + android:fillType="evenOdd" + android:pathData="M53.811,180.104C59.227,174.076 63.096,164.64 60.001,144.982C56.905,125.324 54.326,120.868 49.428,120.082C44.528,119.296 41.433,122.441 40.143,129.256C38.854,136.071 39.112,142.885 37.049,145.506C34.986,148.127 23.124,162.805 29.828,175.386C36.533,187.967 47.88,184.56 53.811,180.104Z" /> + <path + android:fillColor="#1E1E1F" + android:fillType="evenOdd" + android:pathData="M40.205,184.142C41.997,180.218 45.421,169.493 47.584,157.563C49.035,149.562 49.921,141.012 49.37,133.599L48.734,133.643C49.28,141.003 48.4,149.497 46.958,157.451C44.805,169.325 41.403,179.984 39.625,183.878L40.205,184.142Z" /> + <path + android:fillColor="#1E1E1F" + android:fillType="evenOdd" + android:pathData="M45.584,166.565C45.179,167.02 54.675,160.761 56.473,154.589L55.881,154.413C54.151,160.352 45.595,165.755 45.571,165.772L45.584,166.565Z" /> + <path + android:fillColor="#1E1E1F" + android:fillType="evenOdd" + android:pathData="M42.598,177.794C42.582,177.772 37.066,170.055 36.239,164.323L35.661,164.424C36.512,170.331 42.121,178.175 42.137,178.197L42.598,177.794Z" /> + <path + android:fillColor="#747576" + android:pathData="M105.519,81.291L115.162,95.661C115.162,95.661 120.519,100.476 116.844,102.233C113.172,103.99 112.404,97.19 112.404,97.19L105.288,90.31L105.519,81.291Z" /> + <path + android:fillColor="#747576" + android:pathData="M75.389,164.357L73.138,168.626C72.827,169.214 73.035,169.939 73.609,170.276C76.328,171.859 83.762,175.905 86.969,174.817C87.42,174.663 87.529,174.077 87.18,173.755C85.133,171.873 78.769,165.869 79.26,164.396L75.389,164.357Z" /> + <path + android:fillColor="#747576" + android:pathData="M75.182,164.753L79.533,165.333L101.049,115.716L89.845,93.238L89.715,124.004C89.715,124.004 79.722,143.843 78.126,151.626C76.55,159.311 75.182,164.753 75.182,164.753Z" /> + <path + android:fillColor="#747576" + android:pathData="M89.141,86.062L106.025,86.287C106.025,86.287 120.659,159.583 126.511,164.529L123.36,166.777C123.36,166.777 105.35,142.27 106.925,126.53C106.925,126.53 84.639,90.783 89.141,86.062Z" /> + <path + android:fillColor="#747576" + android:pathData="M101.055,57.863L99.971,50.202C99.971,50.202 104.686,50.412 104.58,43.839C104.559,42.621 104.473,40.538 103.348,38.956L99.136,37.74L96.302,46.289L94.084,57.085L98.304,59.777L101.473,59.694L101.055,57.863Z" /> + <path + android:fillColor="#747576" + android:pathData="M123.356,166.777L124.049,171.551C124.144,172.208 124.74,172.675 125.403,172.607C128.533,172.29 136.927,171.193 138.879,168.427C139.151,168.04 138.896,167.498 138.422,167.445C135.659,167.126 126.976,166.014 126.505,164.532L123.356,166.777Z" /> + <path + android:fillColor="#747576" + android:pathData="M85.468,96.196L86.644,81.855L92.715,83.586L88.453,98.337C88.453,98.337 87.381,106.898 83.785,104.375C79.319,101.242 85.314,97.953 85.468,96.196Z" /> + <path + android:fillColor="#747576" + android:pathData="M86.614,82.063C86.614,82.063 86.623,81.992 86.641,81.855C86.961,79.504 89.958,58.056 93.322,57.195C96.879,56.281 98.689,59.659 100.315,57.831C101.941,56.003 111.507,71.124 106.022,86.29L91.963,86.304L96.675,65.217L92.712,83.592C92.712,83.586 87.633,84.905 86.614,82.063Z" /> + <path + android:fillColor="#747576" + android:pathData="M104.574,43.825C104.574,43.825 107.974,41.707 105.723,35.876C105.723,35.876 105.222,33.377 101.722,33.463C101.722,33.463 96.136,28.467 90.882,32.714C85.628,36.962 89.215,41.207 89.215,41.207C89.215,41.207 82.21,47.537 84.63,56.115C84.63,56.115 87.215,61.694 90.216,59.78C93.219,57.863 93.05,62.028 94.634,56.449C96.219,50.87 98.97,51.702 97.886,42.292C97.886,42.292 101.639,42.541 102.471,38.71C102.471,38.71 104.592,39.509 104.574,43.825Z" /> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_illustration_no_locations.xml b/Corona-Warn-App/src/main/res/drawable/ic_illustration_no_locations.xml new file mode 100644 index 0000000000000000000000000000000000000000..7a57c9a752ca42c621f7cec83260ec247d5860eb --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_illustration_no_locations.xml @@ -0,0 +1,23 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="200dp" + android:height="200dp" + android:viewportWidth="200" + android:viewportHeight="200"> + <group> + <clip-path android:pathData="M100,100m-100,0a100,100 0,1 1,200 0a100,100 0,1 1,-200 0" /> + <path + android:fillColor="#E8F5FF" + android:pathData="M-9.091,-6.818h224.242v257.576h-224.242z" /> + <path + android:fillColor="#B8E0FA" + android:fillType="evenOdd" + android:pathData="M123.056,77.044L122.85,129.087H105.802V124.166H51.935V116.945H19.715V140.922H8.134V149.907H-40V208H-21.569H-3.443H8.134H19.715H26.26H64.019V207.823H100.77V208H125.436H137.272H170.549H172.957H184.967H203.524H226.846H233.365H261.227H272.254H291.063V198.63L349,206.658V146.985H291.063V114.886H272.254V106.935H226.846V118.06H211.78V102.174H184.967V77L123.056,77.044Z" /> + <path + android:fillColor="#ffffff" + android:pathData="M100,39C76.227,39 57,58.093 57,81.7C57,113.725 100,161 100,161C100,161 143,113.725 143,81.7C143,58.093 123.773,39 100,39ZM100,96.95C91.523,96.95 84.643,90.118 84.643,81.7C84.643,73.282 91.523,66.45 100,66.45C108.477,66.45 115.357,73.282 115.357,81.7C115.357,90.118 108.477,96.95 100,96.95Z" /> + <path + android:fillColor="#D8ECF9" + android:fillType="evenOdd" + android:pathData="M112.677,163.277C76.438,163.277 60.651,141.575 26.816,145.683C18.774,146.66 8.561,149.711 -2.909,158.268V212.582L375.514,213.931V166.239C373.414,165.038 371.319,164.012 369.336,163.262C369.336,163.262 331.203,148.534 288.973,161.136C252.802,171.94 211.135,143.661 191.174,142.928C189.31,142.859 187.511,142.827 185.783,142.827C142.656,142.824 140.594,163.277 112.677,163.277Z" /> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_illustration_no_people.xml b/Corona-Warn-App/src/main/res/drawable/ic_illustration_no_people.xml new file mode 100644 index 0000000000000000000000000000000000000000..10c43a63c4aaab25d890f86a53335640186a9897 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_illustration_no_people.xml @@ -0,0 +1,62 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="200dp" + android:height="200dp" + android:viewportWidth="200" + android:viewportHeight="200"> + <group> + <clip-path android:pathData="M100,100m-100,0a100,100 0,1 1,200 0a100,100 0,1 1,-200 0" /> + <path + android:fillColor="#E8F5FF" + android:pathData="M-9.091,-6.818h224.242v257.576H-9.091z" /> + <path + android:fillColor="#D8ECF9" + android:fillType="evenOdd" + android:pathData="M-31.146,141.336c-51.998,0 -74.651,-31.132 -123.201,-25.238 -11.54,1.401 -26.195,5.778 -42.653,18.053v77.914L346,214v-68.415c-3.014,-1.722 -6.02,-3.194 -8.865,-4.271 0,0 -54.717,-21.128 -115.314,-3.05 -51.901,15.499 -111.688,-25.067 -140.331,-26.119a209.205,209.205 0,0 0,-7.736 -0.145c-61.882,-0.004 -64.841,29.336 -104.9,29.336z" /> + <path + android:fillColor="#B8E0FA" + android:fillType="evenOdd" + android:pathData="M20.842,73.288c-5.615,0.143 -8.829,8.142 -9.097,11.94 -1.144,16.263 -11.087,27.86 -10.166,53.19 0.603,16.598 6.42,33.65 12.574,36.635 11.849,5.749 19.797,-7.055 21.135,-18.996 1.338,-11.94 2.14,-29.308 -6.688,-51.018 -4.902,-12.055 3.486,-32.038 -7.758,-31.751z" /> + <path + android:fillColor="#fff" + android:fillType="evenOdd" + android:pathData="M17.012,119.964c-0.018,-0.021 -6.663,-7.921 -6.217,-13.813l0.609,0.05c-0.425,5.625 6.055,13.322 6.07,13.343l-0.462,0.42z" /> + <path + android:fillColor="#fff" + android:fillType="evenOdd" + android:pathData="M20.399,177.094c-1.046,-4.509 -3.395,-27.107 -3.457,-51.571 -0.037,-14.853 0.766,-30.401 3.216,-43.02l0.659,0.12c-2.441,12.578 -3.242,28.084 -3.205,42.9 0.062,24.413 2.4,46.94 3.44,51.429l-0.653,0.142z" /> + <path + android:fillColor="#fff" + android:fillType="evenOdd" + android:pathData="M17.64,148.7c0.025,-0.04 7.738,-12.751 8.927,-17.873l0.656,0.144c-1.213,5.222 -8.979,18.02 -9.004,18.062l-0.578,-0.333z" /> + <path + android:fillColor="#B8E0FA" + android:fillType="evenOdd" + android:pathData="M53.81,180.104c5.417,-6.028 9.285,-15.464 6.191,-35.122 -3.095,-19.658 -5.674,-24.114 -10.573,-24.9 -4.9,-0.786 -7.995,2.359 -9.285,9.174 -1.29,6.815 -1.03,13.629 -3.094,16.25 -2.063,2.621 -13.925,17.299 -7.221,29.88 6.705,12.581 18.052,9.174 23.983,4.718z" /> + <path + android:fillColor="#fff" + android:fillType="evenOdd" + android:pathData="M40.205,184.142c1.792,-3.924 5.216,-14.649 7.38,-26.579 1.45,-8.001 2.336,-16.551 1.785,-23.964l-0.636,0.044c0.546,7.361 -0.334,15.854 -1.776,23.808 -2.154,11.874 -5.555,22.533 -7.332,26.427l0.579,0.264z" /> + <path + android:fillColor="#fff" + android:fillType="evenOdd" + android:pathData="M45.584,166.565c-0.405,0.455 9.09,-5.804 10.889,-11.976l-0.593,-0.176c-1.729,5.939 -10.285,11.342 -10.31,11.359l0.014,0.793zM42.598,177.794c-0.016,-0.022 -5.532,-7.739 -6.359,-13.472l-0.578,0.102c0.85,5.907 6.46,13.751 6.476,13.773l0.46,-0.403z" /> + <path + android:fillColor="#fff" + android:pathData="M105.519,81.29l9.643,14.37s5.357,4.816 1.682,6.573c-3.672,1.757 -4.44,-5.043 -4.44,-5.043l-7.116,-6.88 0.231,-9.02zM75.39,164.357l-2.252,4.269a1.239,1.239 0,0 0,0.471 1.65c2.72,1.583 10.153,5.629 13.36,4.541 0.45,-0.154 0.56,-0.74 0.21,-1.062 -2.046,-1.882 -8.41,-7.886 -7.919,-9.359l-3.87,-0.039z" /> + <path + android:fillColor="#fff" + android:pathData="M75.182,164.754l4.35,0.579 21.517,-49.617 -11.204,-22.478 -0.13,30.766s-9.993,19.839 -11.589,27.622c-1.576,7.685 -2.944,13.128 -2.944,13.128z" /> + <path + android:fillColor="#fff" + android:pathData="M89.14,86.062l16.885,0.225s14.634,73.296 20.486,78.242l-3.151,2.248s-18.01,-24.507 -16.435,-40.247c0,0 -22.286,-35.747 -17.784,-40.468zM101.055,57.863l-1.084,-7.661s4.715,0.21 4.609,-6.363c-0.021,-1.218 -0.107,-3.3 -1.232,-4.883l-4.212,-1.216 -2.834,8.548 -2.219,10.797 4.22,2.692 3.17,-0.083 -0.418,-1.83z" /> + <path + android:fillColor="#fff" + android:pathData="M123.356,166.777l0.693,4.774a1.24,1.24 0,0 0,1.354 1.056c3.13,-0.317 11.524,-1.414 13.476,-4.18 0.272,-0.387 0.017,-0.929 -0.457,-0.982 -2.763,-0.319 -11.446,-1.431 -11.917,-2.913l-3.149,2.245zM85.468,96.196l1.175,-14.34 6.072,1.73 -4.262,14.751s-1.072,8.561 -4.668,6.038c-4.466,-3.133 1.529,-6.422 1.683,-8.18z" /> + <path + android:fillColor="#fff" + android:pathData="M86.614,82.063l0.027,-0.207c0.32,-2.352 3.317,-23.8 6.681,-24.661 3.557,-0.914 5.367,2.464 6.993,0.636 1.626,-1.828 11.192,13.293 5.707,28.459l-14.059,0.014 4.712,-21.087 -3.963,18.375c0,-0.006 -5.079,1.313 -6.098,-1.53z" /> + <path + android:fillColor="#fff" + android:pathData="M104.574,43.825s3.4,-2.118 1.149,-7.949c0,0 -0.501,-2.5 -4.001,-2.413 0,0 -5.586,-4.996 -10.84,-0.749 -5.254,4.248 -1.667,8.493 -1.667,8.493s-7.005,6.33 -4.585,14.908c0,0 2.586,5.579 5.586,3.665 3.003,-1.917 2.834,2.248 4.418,-3.33 1.585,-5.58 4.336,-4.748 3.252,-14.158 0,0 3.753,0.249 4.585,-3.582 0,0 2.121,0.799 2.103,5.115z" /> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_selected.xml b/Corona-Warn-App/src/main/res/drawable/ic_selected.xml new file mode 100644 index 0000000000000000000000000000000000000000..9e0e983beea5a53791953faf45fc7b6c3a7ad8bf --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_selected.xml @@ -0,0 +1,10 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="32dp" + android:height="32dp" + android:viewportWidth="32" + android:viewportHeight="32"> + <path + android:fillColor="#007FAD" + android:fillType="evenOdd" + android:pathData="M32,16.008C32,24.777 24.773,32 16,32S0,24.777 0,16.008C0,7.238 7.211,0 15.985,0 24.758,0 32,7.239 32,16.008zM12.342,23.29c0.444,0.536 0.949,0.827 1.592,0.827 0.612,0 1.164,-0.306 1.531,-0.873l7.778,-11.967c0.23,-0.367 0.398,-0.78 0.398,-1.148 0,-0.888 -0.78,-1.484 -1.623,-1.484 -0.551,0 -1.01,0.29 -1.393,0.887l-6.737,10.743 -3.506,-4.346c-0.398,-0.474 -0.812,-0.689 -1.332,-0.689 -0.858,0 -1.577,0.69 -1.577,1.577 0,0.413 0.153,0.81 0.459,1.178l4.41,5.295z" /> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_unselected.xml b/Corona-Warn-App/src/main/res/drawable/ic_unselected.xml new file mode 100644 index 0000000000000000000000000000000000000000..75f82140fecebaf77b08d701b8ef9b48b4f7e490 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_unselected.xml @@ -0,0 +1,11 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="34dp" + android:height="34dp" + android:viewportWidth="34" + android:viewportHeight="34"> + <path + android:fillColor="#00000000" + android:pathData="M17,17m-16,0a16,16 0,1 1,32 0a16,16 0,1 1,-32 0" + android:strokeWidth="1" + android:strokeColor="#007FAD" /> +</vector> 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 index cff3bed3fa3ec1b0ded251ab818b382bc28b0f69..f105f4d50aaa6c18abf3a949220649d9a399095f 100644 --- a/Corona-Warn-App/src/main/res/layout/contact_diary_activity.xml +++ b/Corona-Warn-App/src/main/res/layout/contact_diary_activity.xml @@ -14,4 +14,4 @@ app:defaultNavHost="true" app:navGraph="@navigation/contact_diary_nav_graph" /> -</androidx.coordinatorlayout.widget.CoordinatorLayout> \ No newline at end of file +</androidx.coordinatorlayout.widget.CoordinatorLayout> diff --git a/Corona-Warn-App/src/main/res/layout/contact_diary_day_fragment.xml b/Corona-Warn-App/src/main/res/layout/contact_diary_day_fragment.xml new file mode 100644 index 0000000000000000000000000000000000000000..f0de56a4c609f93ade30c6066c574c279d0cf23e --- /dev/null +++ b/Corona-Warn-App/src/main/res/layout/contact_diary_day_fragment.xml @@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="utf-8"?> +<layout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="match_parent" + android:contentDescription="@string/settings_title" + android:focusable="true"> + + <include + android:id="@+id/contact_diary_day_header" + layout="@layout/include_header" + android:layout_width="0dp" + android:layout_height="wrap_content" + app:icon="@{@drawable/ic_back}" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:title="@{@string/settings_title}" /> + + <com.google.android.material.tabs.TabLayout + android:id="@+id/contact_diary_day_tab_layout" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/contact_diary_day_header" /> + + <androidx.viewpager2.widget.ViewPager2 + android:id="@+id/contact_diary_day_view_pager" + android:layout_width="@dimen/match_constraint" + android:layout_height="@dimen/match_constraint" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/contact_diary_day_tab_layout" /> + + <com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton + android:id="@+id/contact_diary_day_fab" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_margin="@dimen/spacing_normal" + style="@style/Widget.App.ExtendedFloatingActionButton" + android:text="@string/contact_diary_day_person_fab_title" + app:icon="@android:drawable/ic_input_add" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" /> + + </androidx.constraintlayout.widget.ConstraintLayout> + +</layout> diff --git a/Corona-Warn-App/src/main/res/layout/contact_diary_location_bottom_sheet_fragment.xml b/Corona-Warn-App/src/main/res/layout/contact_diary_location_bottom_sheet_fragment.xml new file mode 100644 index 0000000000000000000000000000000000000000..8a2c25860d045eb86d35820ff70ec5502e2bf440 --- /dev/null +++ b/Corona-Warn-App/src/main/res/layout/contact_diary_location_bottom_sheet_fragment.xml @@ -0,0 +1,65 @@ +<?xml version="1.0" encoding="utf-8"?> +<layout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <include + android:id="@+id/contact_diary_location_bottom_sheet_close_button" + layout="@layout/include_button_icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/spacing_normal" + android:layout_marginTop="@dimen/spacing_small" + app:icon="@{@drawable/ic_close}" + app:iconDescription="@{@string/accessibility_close}" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <TextView + android:id="@+id/contact_diary_location_bottom_sheet_title" + style="@style/headline6" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/spacing_normal" + android:text="@string/contact_diary_location_bottom_sheet_title" + app:layout_constraintBottom_toBottomOf="@+id/contact_diary_location_bottom_sheet_close_button" + app:layout_constraintStart_toEndOf="@+id/contact_diary_location_bottom_sheet_close_button" + app:layout_constraintTop_toTopOf="@+id/contact_diary_location_bottom_sheet_close_button" /> + + <com.google.android.material.textfield.TextInputLayout + android:id="@+id/contact_diary_location_bottom_sheet_text_input_layout" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginHorizontal="@dimen/spacing_normal" + android:layout_marginTop="@dimen/spacing_small" + android:hint="@string/contact_diary_location_bottom_sheet_text_input_hint" + app:counterEnabled="true" + app:counterMaxLength="250" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/contact_diary_location_bottom_sheet_close_button"> + + <com.google.android.material.textfield.TextInputEditText + android:id="@+id/contact_diary_location_bottom_sheet_text_input_edit_text" + android:layout_width="match_parent" + android:layout_height="wrap_content" /> + + </com.google.android.material.textfield.TextInputLayout> + + <Button + android:id="@+id/contact_diary_location_bottom_sheet_save_button" + style="@style/buttonPrimary" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginHorizontal="@dimen/spacing_normal" + android:layout_marginTop="@dimen/spacing_normal" + android:layout_marginBottom="@dimen/spacing_small" + android:text="@string/contact_diary_location_bottom_sheet_save_button" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/contact_diary_location_bottom_sheet_text_input_layout" /> + </androidx.constraintlayout.widget.ConstraintLayout> +</layout> diff --git a/Corona-Warn-App/src/main/res/layout/contact_diary_location_list_fragment.xml b/Corona-Warn-App/src/main/res/layout/contact_diary_location_list_fragment.xml new file mode 100644 index 0000000000000000000000000000000000000000..9d491caba4a732b4b5dc6b78a2a489cd48feda25 --- /dev/null +++ b/Corona-Warn-App/src/main/res/layout/contact_diary_location_list_fragment.xml @@ -0,0 +1,67 @@ +<?xml version="1.0" encoding="utf-8"?> +<layout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <androidx.recyclerview.widget.RecyclerView + android:id="@+id/contact_diary_location_list_recycler_view" + app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" + android:layout_width="@dimen/match_constraint" + android:layout_height="@dimen/match_constraint" + android:layout_margin="@dimen/spacing_normal" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <androidx.constraintlayout.widget.Group + android:id="@+id/contact_diary_location_list_no_items_group" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + app:constraint_referenced_ids="contact_diary_location_list_no_items_image,contact_diary_location_list_no_items_title,contact_diary_location_list_no_items_subtitle" /> + + <ImageView + android:id="@+id/contact_diary_location_list_no_items_image" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + app:layout_constraintBottom_toTopOf="@id/contact_diary_location_list_no_items_title" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintVertical_chainStyle="packed" + app:srcCompat="@drawable/ic_illustration_no_locations" /> + + <TextView + android:id="@+id/contact_diary_location_list_no_items_title" + style="@style/subtitleMedium" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginHorizontal="@dimen/spacing_huge" + android:layout_marginTop="@dimen/spacing_normal" + android:text="@string/contact_diary_location_list_no_items_title" + android:textAlignment="center" + app:layout_constraintBottom_toTopOf="@id/contact_diary_location_list_no_items_subtitle" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/contact_diary_location_list_no_items_image" /> + + <TextView + android:id="@+id/contact_diary_location_list_no_items_subtitle" + style="@style/body2Medium" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginHorizontal="@dimen/spacing_huge" + android:layout_marginTop="@dimen/spacing_tiny" + android:text="@string/contact_diary_location_list_no_items_subtitle" + android:textAlignment="center" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/contact_diary_location_list_no_items_title" /> + + </androidx.constraintlayout.widget.ConstraintLayout> + +</layout> diff --git a/Corona-Warn-App/src/main/res/layout/contact_diary_location_list_line.xml b/Corona-Warn-App/src/main/res/layout/contact_diary_location_list_line.xml new file mode 100644 index 0000000000000000000000000000000000000000..0023574f3bb21e28673a7502aaccd9709777e9dd --- /dev/null +++ b/Corona-Warn-App/src/main/res/layout/contact_diary_location_list_line.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8"?> +<layout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minHeight="60dp" + android:background="@color/colorSurface2"> + + <ImageView + android:id="@+id/contact_diary_location_list_line_icon" + android:layout_width="32dp" + android:layout_height="32dp" + android:layout_marginStart="@dimen/spacing_small" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + tools:srcCompat="@drawable/ic_selected" /> + + <TextView + android:id="@+id/contact_diary_location_list_line_name" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginHorizontal="@dimen/spacing_small" + android:layout_marginVertical="@dimen/spacing_small" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toEndOf="@+id/contact_diary_location_list_line_icon" + app:layout_constraintTop_toTopOf="parent" /> + </androidx.constraintlayout.widget.ConstraintLayout> + +</layout> diff --git a/Corona-Warn-App/src/main/res/layout/contact_diary_person_bottom_sheet_fragment.xml b/Corona-Warn-App/src/main/res/layout/contact_diary_person_bottom_sheet_fragment.xml new file mode 100644 index 0000000000000000000000000000000000000000..8cfcbf0ff4d1b7b51a1bcfa77f060782c13ee6db --- /dev/null +++ b/Corona-Warn-App/src/main/res/layout/contact_diary_person_bottom_sheet_fragment.xml @@ -0,0 +1,65 @@ +<?xml version="1.0" encoding="utf-8"?> +<layout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <include + android:id="@+id/contact_diary_person_bottom_sheet_close_button" + layout="@layout/include_button_icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/spacing_normal" + android:layout_marginTop="@dimen/spacing_small" + app:icon="@{@drawable/ic_close}" + app:iconDescription="@{@string/accessibility_close}" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <TextView + android:id="@+id/contact_diary_person_bottom_sheet_title" + style="@style/headline6" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/spacing_normal" + android:text="@string/contact_diary_person_bottom_sheet_title" + app:layout_constraintBottom_toBottomOf="@+id/contact_diary_person_bottom_sheet_close_button" + app:layout_constraintStart_toEndOf="@+id/contact_diary_person_bottom_sheet_close_button" + app:layout_constraintTop_toTopOf="@+id/contact_diary_person_bottom_sheet_close_button" /> + + <com.google.android.material.textfield.TextInputLayout + android:id="@+id/contact_diary_person_bottom_sheet_text_input_layout" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginHorizontal="@dimen/spacing_normal" + android:layout_marginTop="@dimen/spacing_small" + app:counterEnabled="true" + app:counterMaxLength="250" + android:hint="@string/contact_diary_person_bottom_sheet_text_input_hint" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/contact_diary_person_bottom_sheet_close_button"> + + <com.google.android.material.textfield.TextInputEditText + android:id="@+id/contact_diary_person_bottom_sheet_text_input_edit_text" + android:layout_width="match_parent" + android:layout_height="wrap_content" /> + + </com.google.android.material.textfield.TextInputLayout> + + <Button + android:id="@+id/contact_diary_person_bottom_sheet_save_button" + style="@style/buttonPrimary" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginHorizontal="@dimen/spacing_normal" + android:layout_marginTop="@dimen/spacing_normal" + android:layout_marginBottom="@dimen/spacing_small" + android:text="@string/contact_diary_person_bottom_sheet_save_button" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/contact_diary_person_bottom_sheet_text_input_layout" /> + </androidx.constraintlayout.widget.ConstraintLayout> +</layout> diff --git a/Corona-Warn-App/src/main/res/layout/contact_diary_person_list_fragment.xml b/Corona-Warn-App/src/main/res/layout/contact_diary_person_list_fragment.xml new file mode 100644 index 0000000000000000000000000000000000000000..47f1a6197427c4f56b06b85c7d08aac8f9a942e7 --- /dev/null +++ b/Corona-Warn-App/src/main/res/layout/contact_diary_person_list_fragment.xml @@ -0,0 +1,67 @@ +<?xml version="1.0" encoding="utf-8"?> +<layout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <androidx.recyclerview.widget.RecyclerView + android:id="@+id/contact_diary_person_list_recycler_view" + app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" + android:layout_width="@dimen/match_constraint" + android:layout_height="@dimen/match_constraint" + android:layout_margin="@dimen/spacing_normal" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <androidx.constraintlayout.widget.Group + android:id="@+id/contact_diary_person_list_no_items_group" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + app:constraint_referenced_ids="contact_diary_person_list_no_items_image,contact_diary_person_list_no_items_title,contact_diary_person_list_no_items_subtitle" /> + + <ImageView + android:id="@+id/contact_diary_person_list_no_items_image" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + app:layout_constraintBottom_toTopOf="@id/contact_diary_person_list_no_items_title" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintVertical_chainStyle="packed" + app:srcCompat="@drawable/ic_illustration_no_people" /> + + <TextView + android:id="@+id/contact_diary_person_list_no_items_title" + style="@style/subtitleMedium" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginHorizontal="@dimen/spacing_huge" + android:layout_marginTop="@dimen/spacing_normal" + android:text="@string/contact_diary_person_list_no_items_title" + android:textAlignment="center" + app:layout_constraintBottom_toTopOf="@id/contact_diary_person_list_no_items_subtitle" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/contact_diary_person_list_no_items_image" /> + + <TextView + android:id="@+id/contact_diary_person_list_no_items_subtitle" + style="@style/body2Medium" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginHorizontal="@dimen/spacing_huge" + android:layout_marginTop="@dimen/spacing_tiny" + android:text="@string/contact_diary_person_list_no_items_subtitle" + android:textAlignment="center" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/contact_diary_person_list_no_items_title" /> + + </androidx.constraintlayout.widget.ConstraintLayout> + +</layout> diff --git a/Corona-Warn-App/src/main/res/layout/contact_diary_person_list_line.xml b/Corona-Warn-App/src/main/res/layout/contact_diary_person_list_line.xml new file mode 100644 index 0000000000000000000000000000000000000000..9f364109ace03f4f79971eab1ae80949f72d9cd0 --- /dev/null +++ b/Corona-Warn-App/src/main/res/layout/contact_diary_person_list_line.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8"?> +<layout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minHeight="60dp" + android:background="@color/colorSurface2"> + + <ImageView + android:id="@+id/contact_diary_person_list_line_icon" + android:layout_width="32dp" + android:layout_height="32dp" + android:layout_marginStart="@dimen/spacing_small" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + tools:srcCompat="@drawable/ic_selected" /> + + <TextView + android:id="@+id/contact_diary_person_list_line_name" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginHorizontal="@dimen/spacing_small" + android:layout_marginVertical="@dimen/spacing_small" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toEndOf="@+id/contact_diary_person_list_line_icon" + app:layout_constraintTop_toTopOf="parent" /> + </androidx.constraintlayout.widget.ConstraintLayout> + +</layout> 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 80999eff0efc081033181e1cca167975eb36569f..c5ceb76712b340b3450f710317a482801dcbf8e6 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 @@ -4,10 +4,49 @@ xmlns:tools="http://schemas.android.com/tools" android:id="@+id/contact_diary_nav_graph" app:startDestination="@id/contactDiaryOnboardingFragment"> + <fragment + android:id="@+id/contactDiaryDayFragment" + android:name="de.rki.coronawarnapp.contactdiary.ui.day.ContactDiaryDayFragment" + android:label="ContactDiaryDayFragment"> + <argument + android:name="selectedDay" + android:defaultValue="2020-03-25" + app:argType="string" /> + <action + android:id="@+id/action_contactDiaryDayFragment_to_contactDiaryPersonBottomSheetDialogFragment" + app:destination="@id/contactDiaryPersonBottomSheetDialogFragment" /> + <action + android:id="@+id/action_contactDiaryDayFragment_to_contactDiaryLocationBottomSheetDialogFragment" + app:destination="@id/contactDiaryLocationBottomSheetDialogFragment" /> + </fragment> + <fragment + android:id="@+id/contactDiaryPersonListFragment" + android:name="de.rki.coronawarnapp.contactdiary.ui.day.tabs.person.ContactDiaryPersonListFragment" + android:label="ContactDiaryPersonListFragment"> + <argument + android:name="selectedDay" + app:argType="string" /> + </fragment> + <fragment + android:id="@+id/contactDiaryPlaceListFragment" + android:name="de.rki.coronawarnapp.contactdiary.ui.day.tabs.location.ContactDiaryLocationListFragment" + android:label="ContactDiaryPlaceListFragment"> + <argument + android:name="selectedDay" + app:argType="string" /> + </fragment> + <dialog + android:id="@+id/contactDiaryPersonBottomSheetDialogFragment" + android:name="de.rki.coronawarnapp.contactdiary.ui.day.sheets.person.ContactDiaryPersonBottomSheetDialogFragment" + android:label="ContactDiaryPersonBottomSheetDialogFragment" /> + <dialog + android:id="@+id/contactDiaryLocationBottomSheetDialogFragment" + android:name="de.rki.coronawarnapp.contactdiary.ui.day.sheets.location.ContactDiaryLocationBottomSheetDialogFragment" + android:label="ContactDiaryLocationBottomSheetDialogFragment" /> <fragment android:id="@+id/contactDiaryOnboardingFragment" android:name="de.rki.coronawarnapp.contactdiary.ui.onboarding.ContactDiaryOnboardingFragment" - android:label="ContactDiaryOnboardingFragment" > + android:label="ContactDiaryOnboardingFragment"> <action android:id="@+id/action_contactDiaryOnboardingFragment_to_contactDiaryInformationPrivacyFragment" app:destination="@id/contactDiaryInformationPrivacyFragment" /> @@ -23,5 +62,9 @@ android:id="@+id/contactDiaryOverviewFragment" android:name="de.rki.coronawarnapp.contactdiary.ui.overview.ContactDiaryOverviewFragment" android:label="contact_diary_overview_fragment" - tools:layout="@layout/contact_diary_overview_fragment" /> + tools:layout="@layout/contact_diary_overview_fragment"> + <action + android:id="@+id/action_contactDiaryOverviewFragment_to_contactDiaryDayFragment" + app:destination="@id/contactDiaryDayFragment" /> + </fragment> </navigation> diff --git a/Corona-Warn-App/src/main/res/values/contact_diary_strings.xml b/Corona-Warn-App/src/main/res/values/contact_diary_strings.xml index d696d648c9e8242ce6f923eef9eecb9a1b18aa83..836d1fe87a9fd418b85c66323aa2a5dd9202a5fa 100644 --- a/Corona-Warn-App/src/main/res/values/contact_diary_strings.xml +++ b/Corona-Warn-App/src/main/res/values/contact_diary_strings.xml @@ -3,21 +3,20 @@ <!-- #################################### Contact Diary ###################################### --> - <string name="contact_diary_day_person_tab_title">"Personen"</string> - <string name="contact_diary_day_person_fab_title">"Person"</string> - <string name="contact_diary_day_location_tab_title">"Orte"</string> - <string name="contact_diary_day_location_fab_title">"Ort"</string> - <string name="contact_diary_location_list_no_items_title">"Noch keine Orte vorhanden"</string> - <string name="contact_diary_location_list_no_items_subtitle">"Legen Sie einen Ort an und fügen Sie ihn in Ihrem Kontakt-Tagebuch hinzu."</string> - <string name="contact_diary_person_list_no_items_title">"Noch keine Personen vorhanden"</string> - <string name="contact_diary_person_list_no_items_subtitle">"Legen Sie eine Person an und fügen Sie sie in Ihrem Kontakt-Tagebuch hinzu."</string> - <string name="contact_diary_person_bottom_sheet_title">"Person"</string> - <string name="contact_diary_person_bottom_sheet_text_input_hint">"Vorname, Nachname"</string> - <string name="contact_diary_person_bottom_sheet_save_button">"Speichern"</string> - <string name="contact_diary_location_bottom_sheet_title">"Ort"</string> - <string name="contact_diary_location_bottom_sheet_text_input_hint">"Bezeichnung"</string> - <string name="contact_diary_location_bottom_sheet_save_button">"Speichern"</string> - + <string name="contact_diary_day_person_tab_title"></string> + <string name="contact_diary_day_person_fab_title"></string> + <string name="contact_diary_day_location_tab_title"></string> + <string name="contact_diary_day_location_fab_title"></string> + <string name="contact_diary_location_list_no_items_title"></string> + <string name="contact_diary_location_list_no_items_subtitle"></string> + <string name="contact_diary_person_list_no_items_title"></string> + <string name="contact_diary_person_list_no_items_subtitle"></string> + <string name="contact_diary_person_bottom_sheet_title"></string> + <string name="contact_diary_person_bottom_sheet_text_input_hint"></string> + <string name="contact_diary_person_bottom_sheet_save_button"></string> + <string name="contact_diary_location_bottom_sheet_title"></string> + <string name="contact_diary_location_bottom_sheet_text_input_hint"></string> + <string name="contact_diary_location_bottom_sheet_save_button"></string> <!-- XHED: Title for the contact diary card displayed in the homescreen --> <string name="contact_diary_homescreen_card_header" /> <!-- XTXT: Body for the contact diary card displayed in the homescreen --> diff --git a/Corona-Warn-App/src/main/res/values/styles.xml b/Corona-Warn-App/src/main/res/values/styles.xml index f52ee4665b1eb151ed2baddaa4ebd72cf8356405..7670cb51be75d36d5043876ffabe1c6fd67aa6c9 100644 --- a/Corona-Warn-App/src/main/res/values/styles.xml +++ b/Corona-Warn-App/src/main/res/values/styles.xml @@ -12,10 +12,36 @@ <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/dialog</item> + </style> + + <style name="MaterialAppTheme.NoActionBar" parent="MaterialAppTheme"> + <item name="windowActionBar">false</item> + <item name="windowNoTitle">true</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> + <item name="colorOnSurface">@color/colorAccentTintButtonPressed</item> + </style> + + <style name="Widget.App.ExtendedFloatingActionButton" parent="Widget.MaterialComponents.ExtendedFloatingActionButton.Icon"> + <item name="materialThemeOverlay"> + @style/ThemeOverlay.App.ExtendedFloatingActionButton + </item> + </style> + <!-- Launcher theme with background --> <style name="AppTheme.Launcher" parent="AppTheme.NoActionBar"> <item name="android:windowBackground">@drawable/splash_screen</item>