From b0ed2f7b074161cb36700511dc1c2137e687deac Mon Sep 17 00:00:00 2001 From: razeeman Date: Sat, 19 Nov 2022 14:17:47 +0300 Subject: [PATCH] add selected icon category indication --- .../core/mapper/IconEmojiMapper.kt | 4 +- .../core/mapper/IconImageMapper.kt | 4 +- ...geRecordTypeIconCategoryAdapterDelegate.kt | 14 +++- .../ChangeRecordTypeViewDataInteractor.kt | 9 ++- .../mapper/ChangeRecordTypeMapper.kt | 74 +++++++++---------- .../view/ChangeRecordTypeFragment.kt | 9 +++ ...hangeRecordTypeIconCategoryInfoViewData.kt | 3 +- .../ChangeRecordTypeIconCategoryViewData.kt | 4 +- .../ChangeRecordTypeIconTypeViewData.kt | 4 +- .../viewModel/ChangeRecordTypeViewModel.kt | 40 ++++++++-- ..._record_type_item_icon_category_layout.xml | 31 ++++++-- 11 files changed, 130 insertions(+), 66 deletions(-) diff --git a/core/src/main/java/com/example/util/simpletimetracker/core/mapper/IconEmojiMapper.kt b/core/src/main/java/com/example/util/simpletimetracker/core/mapper/IconEmojiMapper.kt index 47fb4e1a..0dbc139c 100644 --- a/core/src/main/java/com/example/util/simpletimetracker/core/mapper/IconEmojiMapper.kt +++ b/core/src/main/java/com/example/util/simpletimetracker/core/mapper/IconEmojiMapper.kt @@ -63,9 +63,7 @@ class IconEmojiMapper @Inject constructor( ) fun getAvailableEmojis(): Map> = - getAvailableEmojiCategories() - .map() { it to mapTypeToCodes(it.type) } - .toMap() + getAvailableEmojiCategories().associateWith { mapTypeToCodes(it.type) } fun hasSkinToneVariations(codes: String): Boolean = codes.contains(IconEmojiRepo.SKIN_TONE) diff --git a/core/src/main/java/com/example/util/simpletimetracker/core/mapper/IconImageMapper.kt b/core/src/main/java/com/example/util/simpletimetracker/core/mapper/IconImageMapper.kt index 0cbdfdcc..a4b8a1bf 100644 --- a/core/src/main/java/com/example/util/simpletimetracker/core/mapper/IconImageMapper.kt +++ b/core/src/main/java/com/example/util/simpletimetracker/core/mapper/IconImageMapper.kt @@ -101,9 +101,7 @@ class IconImageMapper @Inject constructor( ) fun getAvailableImages(): Map> = - getAvailableCategories() - .map { it to mapTypeToArray(it.type).let(repo::getImages) } - .toMap() + getAvailableCategories().associateWith { mapTypeToArray(it.type).let(repo::getImages) } fun mapToDrawableResId(iconName: String): Int { return context.resources diff --git a/features/feature_change_record_type/src/main/java/com/example/util/simpletimetracker/feature_change_record_type/adapter/ChangeRecordTypeIconCategoryAdapterDelegate.kt b/features/feature_change_record_type/src/main/java/com/example/util/simpletimetracker/feature_change_record_type/adapter/ChangeRecordTypeIconCategoryAdapterDelegate.kt index 8e981dc3..1107f5c1 100644 --- a/features/feature_change_record_type/src/main/java/com/example/util/simpletimetracker/feature_change_record_type/adapter/ChangeRecordTypeIconCategoryAdapterDelegate.kt +++ b/features/feature_change_record_type/src/main/java/com/example/util/simpletimetracker/feature_change_record_type/adapter/ChangeRecordTypeIconCategoryAdapterDelegate.kt @@ -4,6 +4,9 @@ import com.example.util.simpletimetracker.feature_base_adapter.createRecyclerBin import com.example.util.simpletimetracker.feature_views.extension.setOnClickWith import com.example.util.simpletimetracker.feature_change_record_type.databinding.ChangeRecordTypeItemIconCategoryLayoutBinding as Binding import com.example.util.simpletimetracker.feature_change_record_type.viewData.ChangeRecordTypeIconCategoryViewData as ViewData +import androidx.core.view.isVisible +import com.example.util.simpletimetracker.core.extension.getThemedAttr +import com.example.util.simpletimetracker.feature_change_record_type.R fun createChangeRecordTypeIconCategoryAdapterDelegate( onItemClick: ((ViewData) -> Unit) @@ -13,8 +16,15 @@ fun createChangeRecordTypeIconCategoryAdapterDelegate( with(binding) { item as ViewData - ivChangeRecordTypeIconCategoryItem.setImageResource(item.categoryIcon) - ivChangeRecordTypeIconCategoryItem.tag = item.categoryIcon + val tint = root.context.getThemedAttr( + if (item.selected) R.attr.appLightTextColor else R.attr.colorPrimary + ) + with(ivChangeRecordTypeIconCategoryItem) { + setImageResource(item.categoryIcon) + setColorFilter(tint) + tag = item.categoryIcon + } + viewChangeRecordTypeIconCategoryItem.isVisible = item.selected root.setOnClickWith(item, onItemClick) } } \ No newline at end of file diff --git a/features/feature_change_record_type/src/main/java/com/example/util/simpletimetracker/feature_change_record_type/interactor/ChangeRecordTypeViewDataInteractor.kt b/features/feature_change_record_type/src/main/java/com/example/util/simpletimetracker/feature_change_record_type/interactor/ChangeRecordTypeViewDataInteractor.kt index a5830009..dc79487c 100644 --- a/features/feature_change_record_type/src/main/java/com/example/util/simpletimetracker/feature_change_record_type/interactor/ChangeRecordTypeViewDataInteractor.kt +++ b/features/feature_change_record_type/src/main/java/com/example/util/simpletimetracker/feature_change_record_type/interactor/ChangeRecordTypeViewDataInteractor.kt @@ -97,11 +97,14 @@ class ChangeRecordTypeViewDataInteractor @Inject constructor( } } - fun getIconCategoriesViewData(iconType: IconType): List { + fun getIconCategoriesViewData( + iconType: IconType, + selectedIndex: Long, + ): List { return when (iconType) { - IconType.IMAGE -> mapper.mapIconImageCategories() + IconType.IMAGE -> mapper.mapIconImageCategories(selectedIndex) IconType.TEXT -> emptyList() - IconType.EMOJI -> mapper.mapIconEmojiCategories() + IconType.EMOJI -> mapper.mapIconEmojiCategories(selectedIndex) } } } \ No newline at end of file diff --git a/features/feature_change_record_type/src/main/java/com/example/util/simpletimetracker/feature_change_record_type/mapper/ChangeRecordTypeMapper.kt b/features/feature_change_record_type/src/main/java/com/example/util/simpletimetracker/feature_change_record_type/mapper/ChangeRecordTypeMapper.kt index c3bcf7ba..ae019045 100644 --- a/features/feature_change_record_type/src/main/java/com/example/util/simpletimetracker/feature_change_record_type/mapper/ChangeRecordTypeMapper.kt +++ b/features/feature_change_record_type/src/main/java/com/example/util/simpletimetracker/feature_change_record_type/mapper/ChangeRecordTypeMapper.kt @@ -6,8 +6,6 @@ import com.example.util.simpletimetracker.core.mapper.IconImageMapper import com.example.util.simpletimetracker.core.mapper.TimeMapper import com.example.util.simpletimetracker.core.repo.ResourceRepo import com.example.util.simpletimetracker.domain.model.AppColor -import com.example.util.simpletimetracker.domain.model.IconEmojiCategory -import com.example.util.simpletimetracker.domain.model.IconImageCategory import com.example.util.simpletimetracker.domain.model.IconType import com.example.util.simpletimetracker.feature_base_adapter.ViewHolderType import com.example.util.simpletimetracker.feature_base_adapter.emoji.EmojiViewData @@ -40,11 +38,17 @@ class ChangeRecordTypeMapper @Inject constructor( newColor: AppColor, isDarkTheme: Boolean, ): List { - return iconImageMapper.getAvailableImages().map { (category, images) -> - listOf(mapImageCategoryHintViewData(category)) + - images.map { (iconName, iconResId) -> - mapImageViewData(iconName, iconResId, newColor, isDarkTheme) - } + val iconCategories = iconImageMapper.getAvailableImages() + return iconCategories.toList().mapIndexed { index, (category, images) -> + listOf( + ChangeRecordTypeIconCategoryInfoViewData( + type = ChangeRecordTypeIconTypeViewData.Image(category.type, index.toLong()), + text = category.name, + isLast = index == iconCategories.size - 1, + ) + ) + images.map { (iconName, iconResId) -> + mapImageViewData(iconName, iconResId, newColor, isDarkTheme) + } }.flatten() } @@ -52,28 +56,40 @@ class ChangeRecordTypeMapper @Inject constructor( newColor: AppColor, isDarkTheme: Boolean, ): List { - return iconEmojiMapper.getAvailableEmojis().map { (category, codes) -> - listOf(mapEmojiCategoryHintViewData(category)) + - codes.map { code -> - mapEmojiViewData(code, newColor, isDarkTheme) - } + val iconCategories = iconEmojiMapper.getAvailableEmojis() + return iconCategories.toList().mapIndexed { index, (category, codes) -> + listOf( + ChangeRecordTypeIconCategoryInfoViewData( + type = ChangeRecordTypeIconTypeViewData.Emoji(category.type, index.toLong()), + text = category.name, + isLast = index == iconCategories.size - 1, + ) + ) + codes.map { code -> + mapEmojiViewData(code, newColor, isDarkTheme) + } }.flatten() } - fun mapIconImageCategories(): List { - return iconImageMapper.getAvailableCategories().map { + fun mapIconImageCategories( + selectedIndex: Long, + ): List { + return iconImageMapper.getAvailableCategories().mapIndexed { index, iconImageCategory -> ChangeRecordTypeIconCategoryViewData( - type = ChangeRecordTypeIconTypeViewData.Image(it.type), - categoryIcon = it.categoryIcon + type = ChangeRecordTypeIconTypeViewData.Image(iconImageCategory.type, index.toLong()), + categoryIcon = iconImageCategory.categoryIcon, + selected = selectedIndex == index.toLong(), ) } } - fun mapIconEmojiCategories(): List { - return iconEmojiMapper.getAvailableEmojiCategories().map { + fun mapIconEmojiCategories( + selectedIndex: Long, + ): List { + return iconEmojiMapper.getAvailableEmojiCategories().mapIndexed { index, iconEmojiCategory -> ChangeRecordTypeIconCategoryViewData( - type = ChangeRecordTypeIconTypeViewData.Emoji(it.type), - categoryIcon = it.categoryIcon + type = ChangeRecordTypeIconTypeViewData.Emoji(iconEmojiCategory.type, index.toLong()), + categoryIcon = iconEmojiCategory.categoryIcon, + selected = selectedIndex == index.toLong(), ) } } @@ -139,22 +155,4 @@ class ChangeRecordTypeMapper @Inject constructor( .let { colorMapper.mapToColorInt(it, isDarkTheme) } ) } - - private fun mapImageCategoryHintViewData( - category: IconImageCategory, - ): ChangeRecordTypeIconCategoryInfoViewData { - return ChangeRecordTypeIconCategoryInfoViewData( - type = ChangeRecordTypeIconTypeViewData.Image(category.type), - text = category.name - ) - } - - private fun mapEmojiCategoryHintViewData( - category: IconEmojiCategory, - ): ChangeRecordTypeIconCategoryInfoViewData { - return ChangeRecordTypeIconCategoryInfoViewData( - type = ChangeRecordTypeIconTypeViewData.Emoji(category.type), - text = category.name - ) - } } \ No newline at end of file diff --git a/features/feature_change_record_type/src/main/java/com/example/util/simpletimetracker/feature_change_record_type/view/ChangeRecordTypeFragment.kt b/features/feature_change_record_type/src/main/java/com/example/util/simpletimetracker/feature_change_record_type/view/ChangeRecordTypeFragment.kt index 9fbf4aa6..eab4cbc3 100644 --- a/features/feature_change_record_type/src/main/java/com/example/util/simpletimetracker/feature_change_record_type/view/ChangeRecordTypeFragment.kt +++ b/features/feature_change_record_type/src/main/java/com/example/util/simpletimetracker/feature_change_record_type/view/ChangeRecordTypeFragment.kt @@ -51,6 +51,7 @@ import com.example.util.simpletimetracker.feature_change_record_type.viewData.Ch import com.example.util.simpletimetracker.feature_change_record_type.viewData.ChangeRecordTypeIconSwitchViewData import com.example.util.simpletimetracker.feature_change_record_type.viewData.ChangeRecordTypeScrollViewData import com.example.util.simpletimetracker.feature_change_record_type.viewModel.ChangeRecordTypeViewModel +import com.example.util.simpletimetracker.feature_views.extension.addOnScrollListenerAdapter import com.example.util.simpletimetracker.feature_views.extension.dpToPx import com.example.util.simpletimetracker.feature_views.extension.pxToDp import com.example.util.simpletimetracker.feature_views.extension.rotateDown @@ -188,6 +189,14 @@ class ChangeRecordTypeFragment : updateIconContainerScroll(it) viewModel.onIconTypeClick(it) } + rvChangeRecordTypeIcon.addOnScrollListenerAdapter(onScrolled = { _, _, _ -> + iconsLayoutManager?.let { + viewModel.onIconsScrolled( + firstVisiblePosition = it.findFirstCompletelyVisibleItemPosition(), + lastVisiblePosition = it.findLastCompletelyVisibleItemPosition(), + ) + } + }) } override fun initViewModel(): Unit = with(binding) { diff --git a/features/feature_change_record_type/src/main/java/com/example/util/simpletimetracker/feature_change_record_type/viewData/ChangeRecordTypeIconCategoryInfoViewData.kt b/features/feature_change_record_type/src/main/java/com/example/util/simpletimetracker/feature_change_record_type/viewData/ChangeRecordTypeIconCategoryInfoViewData.kt index 8d46a961..e1982225 100644 --- a/features/feature_change_record_type/src/main/java/com/example/util/simpletimetracker/feature_change_record_type/viewData/ChangeRecordTypeIconCategoryInfoViewData.kt +++ b/features/feature_change_record_type/src/main/java/com/example/util/simpletimetracker/feature_change_record_type/viewData/ChangeRecordTypeIconCategoryInfoViewData.kt @@ -4,7 +4,8 @@ import com.example.util.simpletimetracker.feature_base_adapter.ViewHolderType data class ChangeRecordTypeIconCategoryInfoViewData( val type: ChangeRecordTypeIconTypeViewData, - val text: String + val text: String, + val isLast: Boolean, ) : ViewHolderType { override fun getUniqueId(): Long = type.id diff --git a/features/feature_change_record_type/src/main/java/com/example/util/simpletimetracker/feature_change_record_type/viewData/ChangeRecordTypeIconCategoryViewData.kt b/features/feature_change_record_type/src/main/java/com/example/util/simpletimetracker/feature_change_record_type/viewData/ChangeRecordTypeIconCategoryViewData.kt index 84c60b87..3dda6982 100644 --- a/features/feature_change_record_type/src/main/java/com/example/util/simpletimetracker/feature_change_record_type/viewData/ChangeRecordTypeIconCategoryViewData.kt +++ b/features/feature_change_record_type/src/main/java/com/example/util/simpletimetracker/feature_change_record_type/viewData/ChangeRecordTypeIconCategoryViewData.kt @@ -1,10 +1,12 @@ package com.example.util.simpletimetracker.feature_change_record_type.viewData +import androidx.annotation.DrawableRes import com.example.util.simpletimetracker.feature_base_adapter.ViewHolderType data class ChangeRecordTypeIconCategoryViewData( val type: ChangeRecordTypeIconTypeViewData, - val categoryIcon: Int + @DrawableRes val categoryIcon: Int, + val selected: Boolean, ) : ViewHolderType { override fun getUniqueId(): Long = type.id diff --git a/features/feature_change_record_type/src/main/java/com/example/util/simpletimetracker/feature_change_record_type/viewData/ChangeRecordTypeIconTypeViewData.kt b/features/feature_change_record_type/src/main/java/com/example/util/simpletimetracker/feature_change_record_type/viewData/ChangeRecordTypeIconTypeViewData.kt index 44e531d1..fea650a7 100644 --- a/features/feature_change_record_type/src/main/java/com/example/util/simpletimetracker/feature_change_record_type/viewData/ChangeRecordTypeIconTypeViewData.kt +++ b/features/feature_change_record_type/src/main/java/com/example/util/simpletimetracker/feature_change_record_type/viewData/ChangeRecordTypeIconTypeViewData.kt @@ -8,11 +8,11 @@ sealed class ChangeRecordTypeIconTypeViewData { data class Image( val type: IconImageType, - override val id: Long = type.ordinal.toLong() + override val id: Long, ) : ChangeRecordTypeIconTypeViewData() data class Emoji( val type: IconEmojiType, - override val id: Long = type.ordinal.toLong() + override val id: Long, ) : ChangeRecordTypeIconTypeViewData() } \ No newline at end of file diff --git a/features/feature_change_record_type/src/main/java/com/example/util/simpletimetracker/feature_change_record_type/viewModel/ChangeRecordTypeViewModel.kt b/features/feature_change_record_type/src/main/java/com/example/util/simpletimetracker/feature_change_record_type/viewModel/ChangeRecordTypeViewModel.kt index 2c2ff22b..9bc78d79 100644 --- a/features/feature_change_record_type/src/main/java/com/example/util/simpletimetracker/feature_change_record_type/viewModel/ChangeRecordTypeViewModel.kt +++ b/features/feature_change_record_type/src/main/java/com/example/util/simpletimetracker/feature_change_record_type/viewModel/ChangeRecordTypeViewModel.kt @@ -199,7 +199,7 @@ class ChangeRecordTypeViewModel @Inject constructor( } iconType = viewData.iconType updateIconsTypeViewData() - updateIconCategories() + updateIconCategories(selectedIndex = 0) updateIcons() } } @@ -220,6 +220,29 @@ class ChangeRecordTypeViewModel @Inject constructor( } } + fun onIconsScrolled( + firstVisiblePosition: Int, + lastVisiblePosition: Int, + ) { + val items = (icons.value as? ChangeRecordTypeIconStateViewData.Icons?) + ?.items ?: return + val infoItems = items.filterIsInstance() + + // Last image category has small number of icons, need to check if it is visible, + // otherwise it would never be selected by the second check. + infoItems + .firstOrNull { it.isLast } + ?.takeIf { items.indexOf(it) <= lastVisiblePosition } + ?.let { + updateIconCategories(it.getUniqueId()) + return + } + + infoItems + .lastOrNull() { items.indexOf(it) <= firstVisiblePosition } + ?.let { updateIconCategories(it.getUniqueId()) } + } + fun onEmojiClick(item: EmojiViewData) { if (iconEmojiMapper.hasSkinToneVariations(item.emojiCodes)) { openEmojiSelectionDialog(item) @@ -440,13 +463,20 @@ class ChangeRecordTypeViewModel @Inject constructor( return viewDataInteractor.getIconsViewData(newColor, iconType) } - private fun updateIconCategories() = viewModelScope.launch { - val data = loadIconCategoriesViewData() + private fun updateIconCategories( + selectedIndex: Long, + ) = viewModelScope.launch { + val data = loadIconCategoriesViewData(selectedIndex) iconCategories.set(data) } - private fun loadIconCategoriesViewData(): List { - return viewDataInteractor.getIconCategoriesViewData(iconType) + private fun loadIconCategoriesViewData( + selectedIndex: Long = 0, + ): List { + return viewDataInteractor.getIconCategoriesViewData( + iconType = iconType, + selectedIndex = selectedIndex, + ) } private fun updateIconsTypeViewData() { diff --git a/features/feature_change_record_type/src/main/res/layout/change_record_type_item_icon_category_layout.xml b/features/feature_change_record_type/src/main/res/layout/change_record_type_item_icon_category_layout.xml index 7ef29e3c..8a3d6e97 100644 --- a/features/feature_change_record_type/src/main/res/layout/change_record_type_item_icon_category_layout.xml +++ b/features/feature_change_record_type/src/main/res/layout/change_record_type_item_icon_category_layout.xml @@ -1,11 +1,26 @@ - \ No newline at end of file + android:layout_height="wrap_content" + android:background="?selectableItemBackgroundBorderless"> + + + + + + \ No newline at end of file -- 2.51.2