diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/eventregistration/ui/EventRegistrationTestFragment.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/eventregistration/ui/EventRegistrationTestFragment.kt index 3138af290d66f75e9829c6cdb1fa3443880e3fe1..f51c1ee6909f31692e16c9acf76621d5e3c705c6 100644 --- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/eventregistration/ui/EventRegistrationTestFragment.kt +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/eventregistration/ui/EventRegistrationTestFragment.kt @@ -50,6 +50,10 @@ class EventRegistrationTestFragment : Fragment(R.layout.fragment_test_eventregis showEventsButton.setOnClickListener { findNavController().navigate(R.id.showStoredEventsTestFragment) } + + startCreateEventFlowButton.setOnClickListener { + findNavController().navigate(R.id.traceLocationOrganizerCategoriesFragment) + } } binding.runMatcher.setOnClickListener { Toast.makeText(context, "Not implemented", Toast.LENGTH_SHORT).show() diff --git a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_eventregistration.xml b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_eventregistration.xml index 86c86ce5570d7facbf73970d91f3b371b13d392c..a3b154690a303422c4e43e194c2324a2709c4a46 100644 --- a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_eventregistration.xml +++ b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_eventregistration.xml @@ -147,6 +147,17 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@id/create_event_button" app:layout_constraintTop_toBottomOf="@id/events_body" /> + + <com.google.android.material.button.MaterialButton + android:id="@+id/start_create_event_flow_button" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:text="Start Create Event Flow" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="@id/create_event_button" + app:layout_constraintTop_toBottomOf="@id/create_event_button" /> + </androidx.constraintlayout.widget.ConstraintLayout> </LinearLayout> </androidx.core.widget.NestedScrollView> diff --git a/Corona-Warn-App/src/deviceForTesters/res/navigation/test_nav_graph.xml b/Corona-Warn-App/src/deviceForTesters/res/navigation/test_nav_graph.xml index 5f3d417bb90e61a607e9fb9a7950d147a8b2f30f..dc81ad56f31a02deeb6f63ab438364bd9fcb2018 100644 --- a/Corona-Warn-App/src/deviceForTesters/res/navigation/test_nav_graph.xml +++ b/Corona-Warn-App/src/deviceForTesters/res/navigation/test_nav_graph.xml @@ -167,6 +167,10 @@ android:name="de.rki.coronawarnapp.test.eventregistration.ui.showevents.ShowStoredEventsTestFragment" android:label="ShowStoredEventsTestFragment" tools:layout="@layout/fragment_test_showstoredevents" /> - + <fragment + android:id="@+id/traceLocationOrganizerCategoriesFragment" + android:name="de.rki.coronawarnapp.ui.eventregistration.organizer.category.TraceLocationCategoryFragment" + android:label="TraceLocationCategoryFragment" + tools:layout="@layout/trace_location_organizer_category_fragment" /> </navigation> diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/EventRegistrationUIModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/EventRegistrationUIModule.kt index d3f7c17ba2dae360a155f691928aab50e5f52e97..c45fb6984e1ef191a696a6861ff3feb534be0911 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/EventRegistrationUIModule.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/EventRegistrationUIModule.kt @@ -8,6 +8,8 @@ import de.rki.coronawarnapp.ui.eventregistration.attendee.confirm.ConfirmCheckIn import de.rki.coronawarnapp.ui.eventregistration.attendee.confirm.ConfirmCheckInModule import de.rki.coronawarnapp.ui.eventregistration.attendee.scan.ScanCheckInQrCodeFragment import de.rki.coronawarnapp.ui.eventregistration.attendee.scan.ScanCheckInQrCodeModule +import de.rki.coronawarnapp.ui.eventregistration.organizer.category.TraceLocationCategoryFragment +import de.rki.coronawarnapp.ui.eventregistration.organizer.category.TraceLocationCategoryModule @Module internal abstract class EventRegistrationUIModule { @@ -20,4 +22,7 @@ internal abstract class EventRegistrationUIModule { @ContributesAndroidInjector(modules = [CheckInsModule::class]) abstract fun checkInsFragment(): CheckInsFragment + + @ContributesAndroidInjector(modules = [TraceLocationCategoryModule::class]) + abstract fun traceLocationCategoryFragment(): TraceLocationCategoryFragment } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/category/TraceLocationCategoryFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/category/TraceLocationCategoryFragment.kt new file mode 100644 index 0000000000000000000000000000000000000000..251a4a1a873f567cfed9936d4fb31b787b34c663 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/category/TraceLocationCategoryFragment.kt @@ -0,0 +1,44 @@ +package de.rki.coronawarnapp.ui.eventregistration.organizer.category + +import android.os.Bundle +import android.view.View +import android.view.accessibility.AccessibilityEvent +import androidx.fragment.app.Fragment +import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.databinding.TraceLocationOrganizerCategoryFragmentBinding +import de.rki.coronawarnapp.ui.eventregistration.organizer.category.adapter.TraceLocationCategoryAdapter +import de.rki.coronawarnapp.util.di.AutoInject +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.cwaViewModels +import timber.log.Timber +import javax.inject.Inject + +class TraceLocationCategoryFragment : Fragment(R.layout.trace_location_organizer_category_fragment), AutoInject { + + @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory + private val vm: TraceLocationCategoryViewModel by cwaViewModels { viewModelFactory } + + private val binding: TraceLocationOrganizerCategoryFragmentBinding by viewBindingLazy() + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + binding.toolbar.setNavigationOnClickListener { popBackStack() } + + vm.categoryItems.observe2(this) { categoryItems -> + val adapter = TraceLocationCategoryAdapter(categoryItems) { + // TODO: Set click-listener - Continue with event creation flow in next PR + Timber.d("Clicked on TraceLocationCategory: $it") + } + binding.recyclerViewCategories.adapter = adapter + } + } + + override fun onResume() { + super.onResume() + binding.categoryRoot.sendAccessibilityEvent(AccessibilityEvent.TYPE_ANNOUNCEMENT) + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/category/TraceLocationCategoryModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/category/TraceLocationCategoryModule.kt new file mode 100644 index 0000000000000000000000000000000000000000..c410c0643c032220ae9282a22b9642a11aa45380 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/category/TraceLocationCategoryModule.kt @@ -0,0 +1,18 @@ +package de.rki.coronawarnapp.ui.eventregistration.organizer.category + +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 TraceLocationCategoryModule { + + @Binds + @IntoMap + @CWAViewModelKey(TraceLocationCategoryViewModel::class) + abstract fun traceLocationCategoryViewModel(factory: TraceLocationCategoryViewModel.Factory): + CWAViewModelFactory<out CWAViewModel> +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/category/TraceLocationCategoryViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/category/TraceLocationCategoryViewModel.kt new file mode 100644 index 0000000000000000000000000000000000000000..e57a4be08b5372ff3399456a2ff9889690dea497 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/category/TraceLocationCategoryViewModel.kt @@ -0,0 +1,30 @@ +package de.rki.coronawarnapp.ui.eventregistration.organizer.category + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.ui.eventregistration.organizer.category.adapter.CategoryItem +import de.rki.coronawarnapp.ui.eventregistration.organizer.category.adapter.category.TraceLocationUIType +import de.rki.coronawarnapp.ui.eventregistration.organizer.category.adapter.category.traceLocationCategories +import de.rki.coronawarnapp.ui.eventregistration.organizer.category.adapter.header.TraceLocationHeaderItem +import de.rki.coronawarnapp.ui.eventregistration.organizer.category.adapter.separator.TraceLocationSeparatorItem +import de.rki.coronawarnapp.util.viewmodel.CWAViewModel +import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory + +class TraceLocationCategoryViewModel @AssistedInject constructor() : CWAViewModel() { + + @AssistedFactory + interface Factory : SimpleCWAViewModelFactory<TraceLocationCategoryViewModel> + + private val categoryItemList = mutableListOf<CategoryItem>().apply { + add(TraceLocationHeaderItem(R.string.tracelocation_organizer_category_type_location_header)) + addAll(traceLocationCategories.filter { it.uiType == TraceLocationUIType.LOCATION }) + add(TraceLocationSeparatorItem) + add(TraceLocationHeaderItem(R.string.tracelocation_organizer_category_type_event_header)) + addAll(traceLocationCategories.filter { it.uiType == TraceLocationUIType.EVENT }) + }.toList() + + val categoryItems: LiveData<List<CategoryItem>> = MutableLiveData(categoryItemList) +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/category/adapter/CategoryItem.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/category/adapter/CategoryItem.kt new file mode 100644 index 0000000000000000000000000000000000000000..9907dd6c4387dd423cebbe1beed71cb9853c31f7 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/category/adapter/CategoryItem.kt @@ -0,0 +1,5 @@ +package de.rki.coronawarnapp.ui.eventregistration.organizer.category.adapter + +import de.rki.coronawarnapp.util.lists.HasStableId + +interface CategoryItem : HasStableId diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/category/adapter/TraceLocationCategoryAdapter.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/category/adapter/TraceLocationCategoryAdapter.kt new file mode 100644 index 0000000000000000000000000000000000000000..2899ca946644d2da758001e76365ee7a4e814571 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/category/adapter/TraceLocationCategoryAdapter.kt @@ -0,0 +1,55 @@ +package de.rki.coronawarnapp.ui.eventregistration.organizer.category.adapter + +import android.view.ViewGroup +import androidx.annotation.LayoutRes +import androidx.viewbinding.ViewBinding +import de.rki.coronawarnapp.ui.eventregistration.organizer.category.adapter.category.TraceLocationCategory +import de.rki.coronawarnapp.ui.eventregistration.organizer.category.adapter.category.TraceLocationCategoryVH +import de.rki.coronawarnapp.ui.eventregistration.organizer.category.adapter.header.TraceLocationHeaderItem +import de.rki.coronawarnapp.ui.eventregistration.organizer.category.adapter.header.TraceLocationHeaderVH +import de.rki.coronawarnapp.ui.eventregistration.organizer.category.adapter.separator.TraceLocationSeparatorItem +import de.rki.coronawarnapp.ui.eventregistration.organizer.category.adapter.separator.TraceLocationSeparatorVH +import de.rki.coronawarnapp.util.lists.BindableVH +import de.rki.coronawarnapp.util.lists.diffutil.AsyncDiffUtilAdapter +import de.rki.coronawarnapp.util.lists.diffutil.AsyncDiffer +import de.rki.coronawarnapp.util.lists.diffutil.update +import de.rki.coronawarnapp.util.lists.modular.ModularAdapter +import de.rki.coronawarnapp.util.lists.modular.mods.DataBinderMod +import de.rki.coronawarnapp.util.lists.modular.mods.StableIdMod +import de.rki.coronawarnapp.util.lists.modular.mods.TypedVHCreatorMod + +class TraceLocationCategoryAdapter( + categoryList: List<CategoryItem>, + private val itemClickListener: (category: TraceLocationCategory) -> Unit +) : ModularAdapter<TraceLocationCategoryAdapter.ItemVH<CategoryItem, ViewBinding>>(), + AsyncDiffUtilAdapter<CategoryItem> { + + override val asyncDiffer: AsyncDiffer<CategoryItem> = AsyncDiffer(adapter = this) + + init { + modules.addAll( + listOf( + StableIdMod(data), + DataBinderMod<CategoryItem, ItemVH<CategoryItem, ViewBinding>>(data), + TypedVHCreatorMod({ data[it] is TraceLocationHeaderItem }) { TraceLocationHeaderVH(it) }, + TypedVHCreatorMod({ data[it] is TraceLocationCategory }) { + TraceLocationCategoryVH( + it, + itemClickListener + ) + }, + TypedVHCreatorMod({ data[it] is TraceLocationSeparatorItem }) { TraceLocationSeparatorVH(it) } + ) + ) + update(categoryList) + } + + override fun getItemCount(): Int { + return data.size + } + + abstract class ItemVH<Item : CategoryItem, VB : ViewBinding>( + @LayoutRes layoutRes: Int, + parent: ViewGroup + ) : ModularAdapter.VH(layoutRes, parent), BindableVH<Item, VB> +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/category/adapter/category/TraceLocationCategory.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/category/adapter/category/TraceLocationCategory.kt new file mode 100644 index 0000000000000000000000000000000000000000..39472f4af3e3d612e0d0b336527c3744c2354daf --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/category/adapter/category/TraceLocationCategory.kt @@ -0,0 +1,105 @@ +package de.rki.coronawarnapp.ui.eventregistration.organizer.category.adapter.category + +import androidx.annotation.StringRes +import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass +import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_PERMANENT_CRAFT +import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_PERMANENT_EDUCATIONAL_INSTITUTION +import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_PERMANENT_FOOD_SERVICE +import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_PERMANENT_OTHER +import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_PERMANENT_PUBLIC_BUILDING +import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_PERMANENT_RETAIL +import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_PERMANENT_WORKPLACE +import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_TEMPORARY_CLUB_ACTIVITY +import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_TEMPORARY_CULTURAL_EVENT +import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_TEMPORARY_OTHER +import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_TEMPORARY_PRIVATE_EVENT +import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_TEMPORARY_WORSHIP_SERVICE +import de.rki.coronawarnapp.ui.eventregistration.organizer.category.adapter.CategoryItem +import de.rki.coronawarnapp.ui.eventregistration.organizer.category.adapter.category.TraceLocationUIType.EVENT +import de.rki.coronawarnapp.ui.eventregistration.organizer.category.adapter.category.TraceLocationUIType.LOCATION + +data class TraceLocationCategory( + val type: TraceLocationOuterClass.TraceLocationType, + val uiType: TraceLocationUIType, + @StringRes val title: Int, + @StringRes val subtitle: Int? = null +) : CategoryItem { + override val stableId = hashCode().toLong() +} + +enum class TraceLocationUIType { + LOCATION, EVENT +} + +val traceLocationCategories = listOf( + TraceLocationCategory( + LOCATION_TYPE_PERMANENT_RETAIL, + LOCATION, + R.string.tracelocation_organizer_category_retail_title, + R.string.tracelocation_organizer_category_retail_subtitle + ), + TraceLocationCategory( + LOCATION_TYPE_PERMANENT_FOOD_SERVICE, + LOCATION, + R.string.tracelocation_organizer_category_food_service_title, + R.string.tracelocation_organizer_category_food_service_subtitle + ), + TraceLocationCategory( + LOCATION_TYPE_PERMANENT_CRAFT, + LOCATION, + R.string.tracelocation_organizer_category_craft_title, + R.string.tracelocation_organizer_category_craft_subtitle + ), + TraceLocationCategory( + LOCATION_TYPE_PERMANENT_WORKPLACE, + LOCATION, + R.string.tracelocation_organizer_category_workplace_title, + R.string.tracelocation_organizer_category_workplace_subtitle + ), + TraceLocationCategory( + LOCATION_TYPE_PERMANENT_EDUCATIONAL_INSTITUTION, + LOCATION, + R.string.tracelocation_organizer_category_educational_institution_title, + R.string.tracelocation_organizer_category_educational_institution_subtitle + ), + TraceLocationCategory( + LOCATION_TYPE_PERMANENT_PUBLIC_BUILDING, + LOCATION, + R.string.tracelocation_organizer_category_public_building_title, + R.string.tracelocation_organizer_category_public_building_subtitle + ), + TraceLocationCategory( + LOCATION_TYPE_PERMANENT_OTHER, + LOCATION, + R.string.tracelocation_organizer_category_other_location_title + ), + TraceLocationCategory( + LOCATION_TYPE_TEMPORARY_CULTURAL_EVENT, + EVENT, + R.string.tracelocation_organizer_category_cultural_event_title, + R.string.tracelocation_organizer_category_cultural_event_subtitle + ), + TraceLocationCategory( + LOCATION_TYPE_TEMPORARY_CLUB_ACTIVITY, + EVENT, + R.string.tracelocation_organizer_category_club_activity_title, + R.string.tracelocation_organizer_category_club_activity_subtitle + ), + TraceLocationCategory( + LOCATION_TYPE_TEMPORARY_PRIVATE_EVENT, + EVENT, + R.string.tracelocation_organizer_category_private_event_title, + R.string.tracelocation_organizer_category_private_event_subtitle + ), + TraceLocationCategory( + LOCATION_TYPE_TEMPORARY_WORSHIP_SERVICE, + EVENT, + R.string.tracelocation_organizer_category_worship_service_title + ), + TraceLocationCategory( + LOCATION_TYPE_TEMPORARY_OTHER, + EVENT, + R.string.tracelocation_organizer_category_other_event_title + ) +) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/category/adapter/category/TraceLocationCategoryVH.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/category/adapter/category/TraceLocationCategoryVH.kt new file mode 100644 index 0000000000000000000000000000000000000000..bb7318797e7ff65d6e26a63d0e62c35672e35f30 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/category/adapter/category/TraceLocationCategoryVH.kt @@ -0,0 +1,27 @@ +package de.rki.coronawarnapp.ui.eventregistration.organizer.category.adapter.category + +import android.view.ViewGroup +import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.databinding.TraceLocationOrganizerCategoryItemBinding +import de.rki.coronawarnapp.ui.eventregistration.organizer.category.adapter.TraceLocationCategoryAdapter + +class TraceLocationCategoryVH(parent: ViewGroup, onItemClickListener: (category: TraceLocationCategory) -> Unit) : + TraceLocationCategoryAdapter.ItemVH<TraceLocationCategory, TraceLocationOrganizerCategoryItemBinding>( + layoutRes = R.layout.trace_location_organizer_category_item, + parent = parent + ) { + + override val viewBinding: Lazy<TraceLocationOrganizerCategoryItemBinding> = lazy { + TraceLocationOrganizerCategoryItemBinding.bind(itemView) + } + + override val onBindData: + TraceLocationOrganizerCategoryItemBinding.(item: TraceLocationCategory, payloads: List<Any>) -> Unit = + { item, _ -> + title.text = context.getString(item.title) + if (item.subtitle != null) { + subtitle.text = context.getString(item.subtitle) + } + root.setOnClickListener { onItemClickListener.invoke(item) } + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/category/adapter/header/TraceLocationHeaderItem.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/category/adapter/header/TraceLocationHeaderItem.kt new file mode 100644 index 0000000000000000000000000000000000000000..d860e32713e025baaf8ca09b962095b2cf13c826 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/category/adapter/header/TraceLocationHeaderItem.kt @@ -0,0 +1,8 @@ +package de.rki.coronawarnapp.ui.eventregistration.organizer.category.adapter.header + +import androidx.annotation.StringRes +import de.rki.coronawarnapp.ui.eventregistration.organizer.category.adapter.CategoryItem + +data class TraceLocationHeaderItem(@StringRes val headerText: Int) : CategoryItem { + override val stableId = this.hashCode().toLong() +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/category/adapter/header/TraceLocationHeaderVH.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/category/adapter/header/TraceLocationHeaderVH.kt new file mode 100644 index 0000000000000000000000000000000000000000..890569170a09f52e98a32792f4ebd0e129f9b2a8 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/category/adapter/header/TraceLocationHeaderVH.kt @@ -0,0 +1,21 @@ +package de.rki.coronawarnapp.ui.eventregistration.organizer.category.adapter.header + +import android.view.ViewGroup +import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.databinding.TraceLocationOrganizerCategoryHeaderBinding +import de.rki.coronawarnapp.ui.eventregistration.organizer.category.adapter.TraceLocationCategoryAdapter + +class TraceLocationHeaderVH(parent: ViewGroup) : + TraceLocationCategoryAdapter.ItemVH<TraceLocationHeaderItem, TraceLocationOrganizerCategoryHeaderBinding>( + layoutRes = R.layout.trace_location_organizer_category_header, + parent = parent + ) { + override val viewBinding: Lazy<TraceLocationOrganizerCategoryHeaderBinding> = + lazy { TraceLocationOrganizerCategoryHeaderBinding.bind(itemView) } + + override val onBindData: + TraceLocationOrganizerCategoryHeaderBinding.(item: TraceLocationHeaderItem, payloads: List<Any>) -> Unit = + { item, _ -> + categoryHeader.text = context.getString(item.headerText) + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/category/adapter/separator/TraceLocationSeparatorItem.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/category/adapter/separator/TraceLocationSeparatorItem.kt new file mode 100644 index 0000000000000000000000000000000000000000..8486a55f6f27834579a64d6707567050260ee415 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/category/adapter/separator/TraceLocationSeparatorItem.kt @@ -0,0 +1,7 @@ +package de.rki.coronawarnapp.ui.eventregistration.organizer.category.adapter.separator + +import de.rki.coronawarnapp.ui.eventregistration.organizer.category.adapter.CategoryItem + +object TraceLocationSeparatorItem : CategoryItem { + override val stableId = this.hashCode().toLong() +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/category/adapter/separator/TraceLocationSeparatorVH.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/category/adapter/separator/TraceLocationSeparatorVH.kt new file mode 100644 index 0000000000000000000000000000000000000000..d458a720b898dce40010d408850beb1e35034d68 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/category/adapter/separator/TraceLocationSeparatorVH.kt @@ -0,0 +1,22 @@ +package de.rki.coronawarnapp.ui.eventregistration.organizer.category.adapter.separator + +import android.view.ViewGroup +import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.databinding.TraceLocationOrganizerCategorySeparatorBinding +import de.rki.coronawarnapp.ui.eventregistration.organizer.category.adapter.TraceLocationCategoryAdapter + +class TraceLocationSeparatorVH(parent: ViewGroup) : + TraceLocationCategoryAdapter.ItemVH<TraceLocationSeparatorItem, TraceLocationOrganizerCategorySeparatorBinding>( + layoutRes = R.layout.trace_location_organizer_category_separator, + parent = parent + ) { + + override val viewBinding: Lazy<TraceLocationOrganizerCategorySeparatorBinding> = + lazy { TraceLocationOrganizerCategorySeparatorBinding.bind(itemView) } + + override val onBindData: + TraceLocationOrganizerCategorySeparatorBinding.(item: TraceLocationSeparatorItem, payloads: List<Any>) -> Unit = + { _, _ -> + // NOOP + } +} diff --git a/Corona-Warn-App/src/main/res/layout/trace_location_organizer_category_fragment.xml b/Corona-Warn-App/src/main/res/layout/trace_location_organizer_category_fragment.xml new file mode 100644 index 0000000000000000000000000000000000000000..0aa9f86df11d785bdab0f55ce33802a6e6126df7 --- /dev/null +++ b/Corona-Warn-App/src/main/res/layout/trace_location_organizer_category_fragment.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@+id/category_root" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:contentDescription="@string/tracelocation_organizer_category_title" + android:orientation="vertical"> + + <com.google.android.material.appbar.MaterialToolbar + android:id="@+id/toolbar" + style="@style/CWAToolbar.Close.Transparent" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:title="@string/tracelocation_organizer_category_title" /> + + <androidx.recyclerview.widget.RecyclerView + android:id="@+id/recycler_view_categories" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1" + app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" /> + +</LinearLayout> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/layout/trace_location_organizer_category_header.xml b/Corona-Warn-App/src/main/res/layout/trace_location_organizer_category_header.xml new file mode 100644 index 0000000000000000000000000000000000000000..dbd763aa49af1820e8c813040c33a585c7e3b300 --- /dev/null +++ b/Corona-Warn-App/src/main/res/layout/trace_location_organizer_category_header.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?> +<TextView xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/category_header" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/spacing_normal" + android:layout_marginTop="@dimen/spacing_tiny" + android:layout_marginBottom="@dimen/spacing_tiny" + android:text="@string/tracelocation_organizer_category_type_location_header" /> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/layout/trace_location_organizer_category_item.xml b/Corona-Warn-App/src/main/res/layout/trace_location_organizer_category_item.xml new file mode 100644 index 0000000000000000000000000000000000000000..72e17ad6666f7cd05a611095941d5a8264f22caa --- /dev/null +++ b/Corona-Warn-App/src/main/res/layout/trace_location_organizer_category_item.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + xmlns:tools="http://schemas.android.com/tools" + android:paddingTop="10dp" + android:paddingBottom="10dp" + android:paddingStart="@dimen/spacing_normal" + android:paddingEnd="@dimen/spacing_normal" + android:background="?android:selectableItemBackground" + android:orientation="vertical"> + + <TextView + android:id="@+id/title" + style="@style/body1" + android:textSize="17sp" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + tools:text="Einzelhandel" /> + + <TextView + android:id="@+id/subtitle" + style="@style/subtitleMedium" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + tools:text="Geschäft, Verkaufsraum" /> + +</LinearLayout> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/layout/trace_location_organizer_category_separator.xml b/Corona-Warn-App/src/main/res/layout/trace_location_organizer_category_separator.xml new file mode 100644 index 0000000000000000000000000000000000000000..98aa983536cdfe0d1b97da6423a05f3607434b3f --- /dev/null +++ b/Corona-Warn-App/src/main/res/layout/trace_location_organizer_category_separator.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<View xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="1dp" + android:layout_marginBottom="@dimen/spacing_small" + android:background="@color/colorHairline" /> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/values-de/event_registration_strings.xml b/Corona-Warn-App/src/main/res/values-de/event_registration_strings.xml index 15ac22e978165febddb8090d2be80649e19c0e66..325f836ce95f1c71eb316c6e812343a74a4868d8 100644 --- a/Corona-Warn-App/src/main/res/values-de/event_registration_strings.xml +++ b/Corona-Warn-App/src/main/res/values-de/event_registration_strings.xml @@ -34,4 +34,68 @@ <string name="trace_location_checkins_remove_single_title">Wollen Sie diesen Eintrag wirklich entfernen?</string> <!-- XTXT: My checkin-ins: Confirmation dialog description when removing all/single items --> <string name="trace_location_checkins_remove_message">Sie können dann Personen, die zur selben Zeit für diesen Ort oder Event eingecheckt waren, bei Bedarf nicht mehr warnen oder von ihnen gewarnt werden.</string> + + <!-- XHED: Title of the category list screen of the event creation --> + <string name="tracelocation_organizer_category_title">QR-Code erstellen</string> + + <!-- XHED: Title of location types in the category list screen of the event creation --> + <string name="tracelocation_organizer_category_type_location_header">Ort</string> + + <!-- XTXT: Title for the retail category --> + <string name="tracelocation_organizer_category_retail_title">Einzelhandel</string> + <!-- XTXT: Subtitle for the retail category --> + <string name="tracelocation_organizer_category_retail_subtitle">Geschäft, Verkaufsraum</string> + + <!-- XTXT: Title for the food service category --> + <string name="tracelocation_organizer_category_food_service_title">Gastronomiebetrieb</string> + <!-- XTXT: Subtitle for the food service category --> + <string name="tracelocation_organizer_category_food_service_subtitle">Café, Kneipe, Restaurant, Hotel</string> + + <!-- XTXT: Title for the craft category --> + <string name="tracelocation_organizer_category_craft_title">Handwerksbetrieb</string> + <!-- XTXT: Subtitle for the craft category --> + <string name="tracelocation_organizer_category_craft_subtitle">Friseur, Schreinerei</string> + + <!-- XTXT: Title for the workplace category --> + <string name="tracelocation_organizer_category_workplace_title">Arbeitsstätte</string> + <!-- XTXT: Subtitle for the workplace category --> + <string name="tracelocation_organizer_category_workplace_subtitle">Büro, Konferenzraum, Kantine</string> + + <!-- XTXT: Title for the educational institution category --> + <string name="tracelocation_organizer_category_educational_institution_title">Bildungsstätte</string> + <!-- XTXT: Subtitle for the educational institution category --> + <string name="tracelocation_organizer_category_educational_institution_subtitle">Klassenzimmer, Vorlesungssaal, Bibliothek</string> + + <!-- XTXT: Title for the public building category --> + <string name="tracelocation_organizer_category_public_building_title">öffentliches Gebäude</string> + <!-- XTXT: Subtitle for the public building category --> + <string name="tracelocation_organizer_category_public_building_subtitle">Bürgeramt, Museum</string> + + <!-- XTXT: Title for other location --> + <string name="tracelocation_organizer_category_other_location_title">anderer Ort</string> + + <!-- XHED: Title of event types in the category list screen of the event creation --> + <string name="tracelocation_organizer_category_type_event_header">Event</string> + + <!-- XTXT: Title for the cultural event category --> + <string name="tracelocation_organizer_category_cultural_event_title">Kulturveranstaltung</string> + <!-- XTXT: Subtitle for the cultural event category --> + <string name="tracelocation_organizer_category_cultural_event_subtitle">Konzert, Kunstausstellung</string> + + <!-- XTXT: Title for the club activity category --> + <string name="tracelocation_organizer_category_club_activity_title">Vereinsaktivität</string> + <!-- XTXT: Subtitle for the club activity category --> + <string name="tracelocation_organizer_category_club_activity_subtitle">Sporttraining, Mitgliederversammlung</string> + + <!-- XTXT: Title for the private event category --> + <string name="tracelocation_organizer_category_private_event_title">private Feier</string> + <!-- XTXT: Subtitle for the private event category --> + <string name="tracelocation_organizer_category_private_event_subtitle">Geburtstag, Familienfeier</string> + + <!-- XTXT: Title for the worship service category --> + <string name="tracelocation_organizer_category_worship_service_title">Gottesdienst</string> + + <!-- XTXT: Title for other event --> + <string name="tracelocation_organizer_category_other_event_title">anderes Event</string> + </resources> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/values/event_registration_strings.xml b/Corona-Warn-App/src/main/res/values/event_registration_strings.xml index 15ac22e978165febddb8090d2be80649e19c0e66..021789dc3a8b4929e4cee4b414458904d86af80e 100644 --- a/Corona-Warn-App/src/main/res/values/event_registration_strings.xml +++ b/Corona-Warn-App/src/main/res/values/event_registration_strings.xml @@ -34,4 +34,67 @@ <string name="trace_location_checkins_remove_single_title">Wollen Sie diesen Eintrag wirklich entfernen?</string> <!-- XTXT: My checkin-ins: Confirmation dialog description when removing all/single items --> <string name="trace_location_checkins_remove_message">Sie können dann Personen, die zur selben Zeit für diesen Ort oder Event eingecheckt waren, bei Bedarf nicht mehr warnen oder von ihnen gewarnt werden.</string> + + <!-- XHED: Title of the category list screen of the event creation --> + <string name="tracelocation_organizer_category_title">QR-Code erstellen</string> + + <!-- XHED: Title of location types in the category list screen of the event creation --> + <string name="tracelocation_organizer_category_type_location_header">Ort</string> + + <!-- XTXT: Title for the retail category --> + <string name="tracelocation_organizer_category_retail_title">Einzelhandel</string> + <!-- XTXT: Subtitle for the retail category --> + <string name="tracelocation_organizer_category_retail_subtitle">Geschäft, Verkaufsraum</string> + + <!-- XTXT: Title for the food service category --> + <string name="tracelocation_organizer_category_food_service_title">Gastronomiebetrieb</string> + <!-- XTXT: Subtitle for the food service category --> + <string name="tracelocation_organizer_category_food_service_subtitle">Café, Kneipe, Restaurant, Hotel</string> + + <!-- XTXT: Title for the craft category --> + <string name="tracelocation_organizer_category_craft_title">Handwerksbetrieb</string> + <!-- XTXT: Subtitle for the craft category --> + <string name="tracelocation_organizer_category_craft_subtitle">Friseur, Schreinerei</string> + + <!-- XTXT: Title for the workplace category --> + <string name="tracelocation_organizer_category_workplace_title">Arbeitsstätte</string> + <!-- XTXT: Subtitle for the workplace category --> + <string name="tracelocation_organizer_category_workplace_subtitle">Büro, Konferenzraum, Kantine</string> + + <!-- XTXT: Title for the educational institution category --> + <string name="tracelocation_organizer_category_educational_institution_title">Bildungsstätte</string> + <!-- XTXT: Subtitle for the educational institution category --> + <string name="tracelocation_organizer_category_educational_institution_subtitle">Klassenzimmer, Vorlesungssaal, Bibliothek</string> + + <!-- XTXT: Title for the public building category --> + <string name="tracelocation_organizer_category_public_building_title">öffentliches Gebäude</string> + <!-- XTXT: Subtitle for the public building category --> + <string name="tracelocation_organizer_category_public_building_subtitle">Bürgeramt, Museum</string> + + <!-- XTXT: Title for other location --> + <string name="tracelocation_organizer_category_other_location_title">anderer Ort</string> + + <!-- XHED: Title of event types in the category list screen of the event creation --> + <string name="tracelocation_organizer_category_type_event_header">Event</string> + + <!-- XTXT: Title for the cultural event category --> + <string name="tracelocation_organizer_category_cultural_event_title">Kulturveranstaltung</string> + <!-- XTXT: Subtitle for the cultural event category --> + <string name="tracelocation_organizer_category_cultural_event_subtitle">Konzert, Kunstausstellung</string> + + <!-- XTXT: Title for the club activity category --> + <string name="tracelocation_organizer_category_club_activity_title">Vereinsaktivität</string> + <!-- XTXT: Subtitle for the club activity category --> + <string name="tracelocation_organizer_category_club_activity_subtitle">Sporttraining, Mitgliederversammlung</string> + + <!-- XTXT: Title for the private event category --> + <string name="tracelocation_organizer_category_private_event_title">private Feier</string> + <!-- XTXT: Subtitle for the private event category --> + <string name="tracelocation_organizer_category_private_event_subtitle">Geburtstag, Familienfeier</string> + + <!-- XTXT: Title for the worship service category --> + <string name="tracelocation_organizer_category_worship_service_title">Gottesdienst</string> + + <!-- XTXT: Title for other event --> + <string name="tracelocation_organizer_category_other_event_title">anderes Event</string> </resources> \ No newline at end of file diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/eventregistration/organizer/category/TraceLocationCategoryViewModelTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/eventregistration/organizer/category/TraceLocationCategoryViewModelTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..fb3176ba1196f7aa8f7e5e45fa1526aea7f666f5 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/eventregistration/organizer/category/TraceLocationCategoryViewModelTest.kt @@ -0,0 +1,110 @@ +package de.rki.coronawarnapp.ui.eventregistration.organizer.category + +import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass +import de.rki.coronawarnapp.ui.eventregistration.organizer.category.adapter.category.TraceLocationCategory +import de.rki.coronawarnapp.ui.eventregistration.organizer.category.adapter.category.TraceLocationUIType +import de.rki.coronawarnapp.ui.eventregistration.organizer.category.adapter.header.TraceLocationHeaderItem +import de.rki.coronawarnapp.ui.eventregistration.organizer.category.adapter.separator.TraceLocationSeparatorItem +import io.kotest.matchers.shouldBe +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import testhelpers.BaseTest +import testhelpers.extensions.InstantExecutorExtension +import testhelpers.extensions.observeForTesting + +@ExtendWith(InstantExecutorExtension::class) +internal class TraceLocationCategoryViewModelTest : BaseTest(){ + + @Test + fun `viewModel should emit correct categoryItems`() { + val viewModel = TraceLocationCategoryViewModel() + + viewModel.categoryItems.observeForTesting { + viewModel.categoryItems.value shouldBe listOf( + + // Location Header + TraceLocationHeaderItem(R.string.tracelocation_organizer_category_type_location_header), + + // Location Categories + TraceLocationCategory( + TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_PERMANENT_RETAIL, + TraceLocationUIType.LOCATION, + R.string.tracelocation_organizer_category_retail_title, + R.string.tracelocation_organizer_category_retail_subtitle + ), + TraceLocationCategory( + TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_PERMANENT_FOOD_SERVICE, + TraceLocationUIType.LOCATION, + R.string.tracelocation_organizer_category_food_service_title, + R.string.tracelocation_organizer_category_food_service_subtitle + ), + TraceLocationCategory( + TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_PERMANENT_CRAFT, + TraceLocationUIType.LOCATION, + R.string.tracelocation_organizer_category_craft_title, + R.string.tracelocation_organizer_category_craft_subtitle + ), + TraceLocationCategory( + TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_PERMANENT_WORKPLACE, + TraceLocationUIType.LOCATION, + R.string.tracelocation_organizer_category_workplace_title, + R.string.tracelocation_organizer_category_workplace_subtitle + ), + TraceLocationCategory( + TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_PERMANENT_EDUCATIONAL_INSTITUTION, + TraceLocationUIType.LOCATION, + R.string.tracelocation_organizer_category_educational_institution_title, + R.string.tracelocation_organizer_category_educational_institution_subtitle + ), + TraceLocationCategory( + TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_PERMANENT_PUBLIC_BUILDING, + TraceLocationUIType.LOCATION, + R.string.tracelocation_organizer_category_public_building_title, + R.string.tracelocation_organizer_category_public_building_subtitle + ), + TraceLocationCategory( + TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_PERMANENT_OTHER, + TraceLocationUIType.LOCATION, + R.string.tracelocation_organizer_category_other_location_title + ), + + // Separator + TraceLocationSeparatorItem, + + // Event Header + TraceLocationHeaderItem(R.string.tracelocation_organizer_category_type_event_header), + + // Event Categories + TraceLocationCategory( + TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_TEMPORARY_CULTURAL_EVENT, + TraceLocationUIType.EVENT, + R.string.tracelocation_organizer_category_cultural_event_title, + R.string.tracelocation_organizer_category_cultural_event_subtitle + ), + TraceLocationCategory( + TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_TEMPORARY_CLUB_ACTIVITY, + TraceLocationUIType.EVENT, + R.string.tracelocation_organizer_category_club_activity_title, + R.string.tracelocation_organizer_category_club_activity_subtitle + ), + TraceLocationCategory( + TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_TEMPORARY_PRIVATE_EVENT, + TraceLocationUIType.EVENT, + R.string.tracelocation_organizer_category_private_event_title, + R.string.tracelocation_organizer_category_private_event_subtitle + ), + TraceLocationCategory( + TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_TEMPORARY_WORSHIP_SERVICE, + TraceLocationUIType.EVENT, + R.string.tracelocation_organizer_category_worship_service_title + ), + TraceLocationCategory( + TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_TEMPORARY_OTHER, + TraceLocationUIType.EVENT, + R.string.tracelocation_organizer_category_other_event_title + ) + ) + } + } +}