Skip to content

Commit c14ff7e

Browse files
committed
add search to archive
1 parent 6f666d9 commit c14ff7e

29 files changed

Lines changed: 334 additions & 65 deletions

File tree

data_local/src/main/java/com/example/util/simpletimetracker/data_local/backup/BackupPrefsRepo.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import com.example.util.simpletimetracker.data_local.prefs.PrefsRepoImpl.Compani
3535
import com.example.util.simpletimetracker.data_local.prefs.PrefsRepoImpl.Companion.KEY_INACTIVITY_REMINDER_DURATION
3636
import com.example.util.simpletimetracker.data_local.prefs.PrefsRepoImpl.Companion.KEY_INACTIVITY_REMINDER_RECURRENT
3737
import com.example.util.simpletimetracker.data_local.prefs.PrefsRepoImpl.Companion.KEY_IS_ACTIVITY_FILTERS_COLLAPSED
38+
import com.example.util.simpletimetracker.data_local.prefs.PrefsRepoImpl.Companion.KEY_IS_ARCHIVE_SEARCH_ENABLED
3839
import com.example.util.simpletimetracker.data_local.prefs.PrefsRepoImpl.Companion.KEY_IS_CATEGORIES_SEARCH_ENABLED
3940
import com.example.util.simpletimetracker.data_local.prefs.PrefsRepoImpl.Companion.KEY_IS_NAV_BAR_AT_THE_BOTTOM
4041
import com.example.util.simpletimetracker.data_local.prefs.PrefsRepoImpl.Companion.KEY_KEEP_SCREEN_ON
@@ -220,6 +221,7 @@ class BackupPrefsRepo @Inject constructor(
220221
PrefsProcessor(KEY_DEFAULT_TYPES_HIDDEN, ::defaultTypesHidden),
221222
PrefsProcessor(KEY_IS_NAV_BAR_AT_THE_BOTTOM, ::isNavBarAtTheBottom),
222223
PrefsProcessor(KEY_IS_CATEGORIES_SEARCH_ENABLED, ::isCategoriesSearchEnabled),
224+
PrefsProcessor(KEY_IS_ARCHIVE_SEARCH_ENABLED, ::isArchiveSearchEnabled),
223225
)
224226
}
225227

data_local/src/main/java/com/example/util/simpletimetracker/data_local/prefs/PrefsRepoImpl.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,10 @@ class PrefsRepoImpl @Inject constructor(
392392
KEY_IS_CATEGORIES_SEARCH_ENABLED, false,
393393
)
394394

395+
override var isArchiveSearchEnabled: Boolean by prefs.delegate(
396+
KEY_IS_ARCHIVE_SEARCH_ENABLED, false,
397+
)
398+
395399
override fun setWidget(widgetId: Int, recordType: Long) {
396400
val key = KEY_WIDGET + widgetId
397401
logPrefsDataAccess("set $key")
@@ -478,7 +482,7 @@ class PrefsRepoImpl @Inject constructor(
478482
val filteredTags = prefs
479483
.getStringSet(KEY_STATISTICS_WIDGET_FILTERED_TAGS + widgetId, emptySet())
480484
?.mapNotNull { it.toLongOrNull() }.orEmpty().toSet()
481-
val filteringType = when(prefs.getInt(KEY_STATISTICS_WIDGET_FILTERING_TYPE + widgetId, 0)) {
485+
val filteringType = when (prefs.getInt(KEY_STATISTICS_WIDGET_FILTERING_TYPE + widgetId, 0)) {
482486
0 -> StatisticsWidgetData.FilterType.FILTER
483487
1 -> StatisticsWidgetData.FilterType.SELECT
484488
else -> StatisticsWidgetData.FilterType.FILTER
@@ -654,6 +658,7 @@ class PrefsRepoImpl @Inject constructor(
654658
const val KEY_DEFAULT_TYPES_HIDDEN = "defaultTypesHidden"
655659
const val KEY_IS_NAV_BAR_AT_THE_BOTTOM = "isNavBarAtTheBottom"
656660
const val KEY_IS_CATEGORIES_SEARCH_ENABLED = "isCategoriesSearchEnabled"
661+
const val KEY_IS_ARCHIVE_SEARCH_ENABLED = "isArchiveSearchEnabled"
657662
const val KEY_CARD_ORDER_MANUAL = "cardOrderManual"
658663
const val KEY_CATEGORY_ORDER_MANUAL = "categoryOrderManual"
659664
const val KEY_TAG_ORDER_MANUAL = "tagOrderManual"

domain/src/main/java/com/example/util/simpletimetracker/domain/prefs/interactor/PrefsInteractor.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -875,6 +875,14 @@ class PrefsInteractor @Inject constructor(
875875
prefsRepo.isCategoriesSearchEnabled = value
876876
}
877877

878+
suspend fun getIsArchiveSearchEnabled(): Boolean = withContext(Dispatchers.IO) {
879+
prefsRepo.isArchiveSearchEnabled
880+
}
881+
882+
suspend fun setIsArchiveSearchEnabled(value: Boolean) = withContext(Dispatchers.IO) {
883+
prefsRepo.isArchiveSearchEnabled = value
884+
}
885+
878886
suspend fun clear() = withContext(Dispatchers.IO) {
879887
prefsRepo.clear()
880888
}

domain/src/main/java/com/example/util/simpletimetracker/domain/prefs/repo/PrefsRepo.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,8 @@ interface PrefsRepo {
170170

171171
var isCategoriesSearchEnabled: Boolean
172172

173+
var isArchiveSearchEnabled: Boolean
174+
173175
fun setWidget(widgetId: Int, recordType: Long)
174176

175177
fun getWidget(widgetId: Int): Long

domain/src/main/java/com/example/util/simpletimetracker/domain/record/interactor/RecordInteractor.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import com.example.util.simpletimetracker.domain.record.model.Record
55
import com.example.util.simpletimetracker.domain.record.repo.RecordRepo
66
import com.example.util.simpletimetracker.domain.record.model.RunningRecord
77
import com.example.util.simpletimetracker.domain.recordTag.repo.RecordToRecordTagRepo
8-
import com.example.util.simpletimetracker.domain.recordTag.repo.RecordTypeToTagRepo
98
import javax.inject.Inject
109

1110
class RecordInteractor @Inject constructor(

domain/src/main/java/com/example/util/simpletimetracker/domain/record/interactor/RunningRecordInteractor.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ package com.example.util.simpletimetracker.domain.record.interactor
22

33
import com.example.util.simpletimetracker.domain.record.model.RunningRecord
44
import com.example.util.simpletimetracker.domain.record.repo.RunningRecordRepo
5-
import com.example.util.simpletimetracker.domain.recordTag.model.RecordTypeToTag
6-
import com.example.util.simpletimetracker.domain.recordTag.repo.RecordTypeToTagRepo
75
import com.example.util.simpletimetracker.domain.recordTag.repo.RunningRecordToRecordTagRepo
86
import javax.inject.Inject
97

features/feature_archive/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import com.example.util.simpletimetracker.applyAndroidLibrary
44
plugins {
55
alias(libs.plugins.gradleLibrary)
66
alias(libs.plugins.kotlin)
7+
alias(libs.plugins.kotlinParcelize)
78
alias(libs.plugins.ksp)
89
alias(libs.plugins.hilt)
910
}

features/feature_archive/src/main/java/com/example/util/simpletimetracker/feature_archive/interactor/ArchiveViewDataInteractor.kt

Lines changed: 93 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,14 @@ import com.example.util.simpletimetracker.core.mapper.RecordTypeViewDataMapper
55
import com.example.util.simpletimetracker.core.repo.ResourceRepo
66
import com.example.util.simpletimetracker.domain.prefs.interactor.PrefsInteractor
77
import com.example.util.simpletimetracker.domain.recordTag.interactor.RecordTagInteractor
8+
import com.example.util.simpletimetracker.domain.recordTag.model.RecordTag
89
import com.example.util.simpletimetracker.domain.recordType.interactor.RecordTypeInteractor
10+
import com.example.util.simpletimetracker.domain.recordType.model.RecordType
911
import com.example.util.simpletimetracker.feature_archive.R
1012
import com.example.util.simpletimetracker.feature_archive.viewData.ArchiveViewData
1113
import com.example.util.simpletimetracker.feature_base_adapter.ViewHolderType
1214
import com.example.util.simpletimetracker.feature_base_adapter.divider.DividerViewData
15+
import com.example.util.simpletimetracker.feature_base_adapter.emptySpace.EmptySpaceViewData
1316
import com.example.util.simpletimetracker.feature_base_adapter.hint.HintViewData
1417
import com.example.util.simpletimetracker.feature_views.GoalCheckmarkView
1518
import javax.inject.Inject
@@ -25,52 +28,71 @@ class ArchiveViewDataInteractor @Inject constructor(
2528
private val categoryViewDataMapper: CategoryViewDataMapper,
2629
) {
2730

28-
suspend fun getViewData(): ArchiveViewData {
31+
suspend fun getViewData(
32+
navBarHeightDp: Int,
33+
searchEnabled: Boolean,
34+
searchText: String,
35+
): ArchiveViewData {
2936
val result: MutableList<ViewHolderType> = mutableListOf()
3037
val numberOfCards = prefsInteractor.getNumberOfCards()
3138
val isDarkTheme = prefsInteractor.getDarkMode()
39+
val isSearching: Boolean = searchEnabled && searchText.isNotEmpty()
3240

3341
val types = recordTypeInteractor.getAll().associateBy { it.id }
3442
val archivedTypes = types.values.filter { it.hidden }
3543
val archivedRecordTags = recordTagInteractor.getAll().filter { it.archived }
3644

37-
val typesViewData = archivedTypes.map { type ->
38-
recordTypeViewDataMapper.mapFiltered(
39-
recordType = type,
40-
numberOfCards = numberOfCards,
41-
isDarkTheme = isDarkTheme,
42-
isFiltered = false,
43-
checkState = GoalCheckmarkView.CheckState.HIDDEN,
44-
isComplete = false,
45-
)
46-
}
47-
48-
val recordTagsViewData = archivedRecordTags.map { tag ->
49-
categoryViewDataMapper.mapRecordTag(
50-
tag = tag,
51-
type = types[tag.iconColorSource],
52-
isDarkTheme = isDarkTheme,
53-
isFiltered = false,
54-
)
55-
}
56-
57-
if (typesViewData.isNotEmpty()) {
58-
HintViewData(resourceRepo.getString(R.string.activity_hint)).let(result::add)
59-
typesViewData.let(result::addAll)
45+
if (archivedTypes.isNotEmpty()) {
46+
val typesViewData = searchTypes(
47+
types = archivedTypes,
48+
isSearching = isSearching,
49+
searchText = searchText,
50+
).map { type ->
51+
recordTypeViewDataMapper.mapFiltered(
52+
recordType = type,
53+
numberOfCards = numberOfCards,
54+
isDarkTheme = isDarkTheme,
55+
isFiltered = false,
56+
checkState = GoalCheckmarkView.CheckState.HIDDEN,
57+
isComplete = false,
58+
)
59+
}
60+
result += HintViewData(resourceRepo.getString(R.string.activity_hint))
61+
result += if (typesViewData.isEmpty() && isSearching) {
62+
mapSearchEmpty()
63+
} else {
64+
typesViewData
65+
}
6066
}
6167

62-
if (recordTagsViewData.isNotEmpty()) {
63-
if (typesViewData.isNotEmpty()) {
64-
DividerViewData(1).let(result::add)
68+
if (archivedRecordTags.isNotEmpty()) {
69+
val recordTagsViewData = searchTags(
70+
tags = archivedRecordTags,
71+
isSearching = isSearching,
72+
searchText = searchText,
73+
).map { tag ->
74+
categoryViewDataMapper.mapRecordTag(
75+
tag = tag,
76+
type = types[tag.iconColorSource],
77+
isDarkTheme = isDarkTheme,
78+
isFiltered = false,
79+
)
80+
}
81+
if (archivedTypes.isNotEmpty()) result += DividerViewData(1)
82+
result += HintViewData(resourceRepo.getString(R.string.record_tag_hint))
83+
result += if (recordTagsViewData.isEmpty() && isSearching) {
84+
mapSearchEmpty()
85+
} else {
86+
recordTagsViewData
6587
}
66-
HintViewData(resourceRepo.getString(R.string.record_tag_hint)).let(result::add)
67-
recordTagsViewData.let(result::addAll)
6888
}
6989

7090
if (result.isEmpty()) {
71-
HintViewData(resourceRepo.getString(R.string.archive_empty)).let(result::add)
91+
result += HintViewData(resourceRepo.getString(R.string.archive_empty))
7292
}
7393

94+
result += getBottomEmptySpace(navBarHeightDp)
95+
7496
val showHint = archivedTypes.isNotEmpty() ||
7597
archivedRecordTags.isNotEmpty()
7698

@@ -79,4 +101,45 @@ class ArchiveViewDataInteractor @Inject constructor(
79101
showHint = showHint,
80102
)
81103
}
104+
105+
private fun getBottomEmptySpace(
106+
navBarHeightDp: Int,
107+
): ViewHolderType {
108+
val optionsButtonHeight = resourceRepo.getDimenInDp(R.dimen.button_height)
109+
val size = optionsButtonHeight + navBarHeightDp
110+
return EmptySpaceViewData(
111+
id = "archive_bottom_space".hashCode().toLong(),
112+
height = EmptySpaceViewData.ViewDimension.ExactSizeDp(size),
113+
wrapBefore = true,
114+
)
115+
}
116+
117+
private fun mapSearchEmpty(): List<ViewHolderType> {
118+
return HintViewData(text = resourceRepo.getString(R.string.widget_load_error))
119+
.let(::listOf)
120+
}
121+
122+
private fun searchTypes(
123+
types: List<RecordType>,
124+
isSearching: Boolean,
125+
searchText: String,
126+
): List<RecordType> {
127+
return if (isSearching) {
128+
types.filter { it.name.lowercase().contains(searchText) }
129+
} else {
130+
types
131+
}
132+
}
133+
134+
private fun searchTags(
135+
tags: List<RecordTag>,
136+
isSearching: Boolean,
137+
searchText: String,
138+
): List<RecordTag> {
139+
return if (isSearching) {
140+
tags.filter { it.name.lowercase().contains(searchText) }
141+
} else {
142+
tags
143+
}
144+
}
82145
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.example.util.simpletimetracker.feature_archive.mapper
2+
3+
import com.example.util.simpletimetracker.core.repo.ResourceRepo
4+
import com.example.util.simpletimetracker.domain.extension.plusAssign
5+
import com.example.util.simpletimetracker.domain.prefs.interactor.PrefsInteractor
6+
import com.example.util.simpletimetracker.feature_archive.R
7+
import com.example.util.simpletimetracker.feature_archive.model.ArchiveOptionsListItem
8+
import com.example.util.simpletimetracker.navigation.params.screen.OptionsListParams
9+
import javax.inject.Inject
10+
11+
class ArchiveOptionsListMapper @Inject constructor(
12+
private val resourceRepo: ResourceRepo,
13+
private val prefsInteractor: PrefsInteractor,
14+
) {
15+
16+
suspend fun map(): List<OptionsListParams.Item> {
17+
val result = mutableListOf<OptionsListParams.Item>()
18+
19+
result += OptionsListParams.Item(
20+
id = ArchiveOptionsListItem.EnabledSearch,
21+
text = resourceRepo.getString(R.string.enable_search_hint),
22+
icon = R.drawable.search,
23+
isIconCheckVisible = prefsInteractor.getIsArchiveSearchEnabled(),
24+
)
25+
26+
return result
27+
}
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.example.util.simpletimetracker.feature_archive.model
2+
3+
import com.example.util.simpletimetracker.navigation.params.screen.OptionsListParams
4+
import kotlinx.parcelize.Parcelize
5+
6+
sealed interface ArchiveOptionsListItem : OptionsListParams.Item.Id {
7+
8+
@Parcelize
9+
data object EnabledSearch : ArchiveOptionsListItem
10+
}

0 commit comments

Comments
 (0)