Skip to content

Commit 35af1b6

Browse files
committed
add categories as predefined filters
1 parent a3840e1 commit 35af1b6

File tree

46 files changed

+301
-57
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+301
-57
lines changed

core/src/main/java/com/example/util/simpletimetracker/core/interactor/ActivityFilterViewDataInteractor.kt

Lines changed: 59 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,29 @@ package com.example.util.simpletimetracker.core.interactor
22

33
import com.example.util.simpletimetracker.core.mapper.ActivityFilterViewDataMapper
44
import com.example.util.simpletimetracker.domain.activityFilter.interactor.ActivityFilterInteractor
5-
import com.example.util.simpletimetracker.domain.prefs.interactor.PrefsInteractor
6-
import com.example.util.simpletimetracker.domain.category.interactor.RecordTypeCategoryInteractor
5+
import com.example.util.simpletimetracker.domain.activityFilter.interactor.PredefinedFilterInteractor
76
import com.example.util.simpletimetracker.domain.activityFilter.model.ActivityFilter
7+
import com.example.util.simpletimetracker.domain.activityFilter.model.PredefinedFilter
8+
import com.example.util.simpletimetracker.domain.category.interactor.RecordTypeCategoryInteractor
9+
import com.example.util.simpletimetracker.domain.prefs.interactor.PrefsInteractor
810
import com.example.util.simpletimetracker.domain.recordType.model.RecordType
911
import com.example.util.simpletimetracker.feature_base_adapter.ViewHolderType
1012
import javax.inject.Inject
1113

1214
class ActivityFilterViewDataInteractor @Inject constructor(
1315
private val prefsInteractor: PrefsInteractor,
1416
private val activityFilterInteractor: ActivityFilterInteractor,
17+
private val predefinedFilterInteractor: PredefinedFilterInteractor,
1518
private val recordTypeCategoryInteractor: RecordTypeCategoryInteractor,
1619
private val activityFilterViewDataMapper: ActivityFilterViewDataMapper,
1720
) {
1821

1922
suspend fun getFilter(): Filter {
2023
return if (prefsInteractor.getShowActivityFilters()) {
21-
val activityFilters = activityFilterInteractor.getAll()
22-
Filter.ApplyFilter(activityFilters)
24+
Filter.ApplyFilter(
25+
userFilters = activityFilterInteractor.getAll(),
26+
predefinedFilters = predefinedFilterInteractor.getAll(),
27+
)
2328
} else {
2429
Filter.NoFilter
2530
}
@@ -36,18 +41,28 @@ class ActivityFilterViewDataInteractor @Inject constructor(
3641
emptyList()
3742
}
3843
is Filter.ApplyFilter -> {
44+
val filtersSize = filter.userFilters.size + filter.predefinedFilters.size
45+
3946
val result = mutableListOf<ViewHolderType>()
4047
if (!isFiltersCollapsed) {
41-
result += filter.activityFilters.map {
42-
activityFilterViewDataMapper.map(
48+
result += filter.predefinedFilters.map {
49+
activityFilterViewDataMapper.mapFiltered(
4350
filter = it,
4451
isDarkTheme = isDarkTheme,
52+
selected = it.selected,
53+
)
54+
}
55+
result += filter.userFilters.map {
56+
activityFilterViewDataMapper.mapFiltered(
57+
filter = it,
58+
isDarkTheme = isDarkTheme,
59+
selected = it.selected,
4560
)
4661
}
4762
}
4863
// Show collapse button if there are several filters,
4964
// or if they are collapsed, just in case (collapse and then remove all but one).
50-
if (filter.activityFilters.size > 1 || isFiltersCollapsed) {
65+
if (filtersSize > 1 || isFiltersCollapsed) {
5166
result += activityFilterViewDataMapper.mapToActivityFilterToggleItem(
5267
isFiltersCollapsed = isFiltersCollapsed,
5368
isDarkTheme = isDarkTheme,
@@ -67,18 +82,30 @@ class ActivityFilterViewDataInteractor @Inject constructor(
6782
list: List<RecordType>,
6883
filter: Filter,
6984
): List<RecordType> {
70-
return if (filter is Filter.ApplyFilter && filter.activityFilters.any { it.selected }) {
71-
val selectedTypes = getSelectedTypeIds(filter.activityFilters)
85+
if (filter !is Filter.ApplyFilter) return list
86+
87+
val hasAnySelectedFilters = filter.userFilters.any { it.selected } ||
88+
filter.predefinedFilters.any { it.selected }
89+
90+
return if (hasAnySelectedFilters) {
91+
val selectedTypes = getSelectedTypeIds(filter)
7292
list.filter { it.id in selectedTypes }
7393
} else {
7494
list
7595
}
7696
}
7797

78-
private suspend fun getSelectedTypeIds(filters: List<ActivityFilter>): List<Long> {
79-
val selectedFilters = filters.filter { it.selected }
98+
private suspend fun getSelectedTypeIds(
99+
filter: Filter.ApplyFilter,
100+
): List<Long> {
101+
val selectedFilters = filter.userFilters.filter { it.selected }
102+
val predefinedSelectedFilters = filter.predefinedFilters.filter { it.selected }
80103

81-
if (selectedFilters.isEmpty()) return emptyList()
104+
if (selectedFilters.isEmpty() &&
105+
predefinedSelectedFilters.isEmpty()
106+
) {
107+
return emptyList()
108+
}
82109

83110
val activityIds: List<Long> = selectedFilters
84111
.filter { it.type is ActivityFilter.Type.Activity }
@@ -90,25 +117,32 @@ class ActivityFilterViewDataInteractor @Inject constructor(
90117
.map { it.selectedIds }
91118
.flatten()
92119
.takeUnless { it.isEmpty() }
93-
?.let { tagIds ->
94-
val recordTypeCategories = recordTypeCategoryInteractor.getAll()
95-
.groupBy { it.categoryId }
96-
.mapValues { (_, value) -> value.map { it.recordTypeId } }
97-
tagIds.mapNotNull { tagId -> recordTypeCategories[tagId] }.flatten()
98-
}
120+
?.let { getTypeIdsFromCategories(it) }
99121
.orEmpty()
100122

101-
return when {
102-
fromCategoryIds.isEmpty() -> activityIds
103-
activityIds.isEmpty() -> fromCategoryIds
104-
else -> activityIds + fromCategoryIds
105-
}
123+
val fromPredefinedFilters: List<Long> = predefinedSelectedFilters
124+
.map { it.categoryId }
125+
.takeUnless { it.isEmpty() }
126+
?.let { getTypeIdsFromCategories(it) }
127+
.orEmpty()
128+
129+
return (activityIds + fromCategoryIds + fromPredefinedFilters).distinct()
130+
}
131+
132+
private suspend fun getTypeIdsFromCategories(
133+
tagIds: List<Long>,
134+
): List<Long> {
135+
val recordTypeCategories = recordTypeCategoryInteractor.getAll()
136+
.groupBy { it.categoryId }
137+
.mapValues { (_, value) -> value.map { it.recordTypeId } }
138+
return tagIds.mapNotNull { tagId -> recordTypeCategories[tagId] }.flatten()
106139
}
107140

108141
sealed interface Filter {
109-
object NoFilter : Filter
142+
data object NoFilter : Filter
110143
data class ApplyFilter(
111-
val activityFilters: List<ActivityFilter>,
144+
val userFilters: List<ActivityFilter>,
145+
val predefinedFilters: List<PredefinedFilter>,
112146
) : Filter
113147
}
114148
}

core/src/main/java/com/example/util/simpletimetracker/core/mapper/ActivityFilterViewDataMapper.kt

Lines changed: 54 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ package com.example.util.simpletimetracker.core.mapper
33
import com.example.util.simpletimetracker.core.R
44
import com.example.util.simpletimetracker.core.repo.ResourceRepo
55
import com.example.util.simpletimetracker.domain.activityFilter.model.ActivityFilter
6+
import com.example.util.simpletimetracker.domain.activityFilter.model.ActivityFilterType
7+
import com.example.util.simpletimetracker.domain.activityFilter.model.PredefinedFilter
8+
import com.example.util.simpletimetracker.domain.color.model.AppColor
69
import com.example.util.simpletimetracker.feature_base_adapter.activityFilter.ActivityFilterAddViewData
710
import com.example.util.simpletimetracker.feature_base_adapter.activityFilter.ActivityFilterViewData
811
import javax.inject.Inject
@@ -12,36 +15,47 @@ class ActivityFilterViewDataMapper @Inject constructor(
1215
private val resourceRepo: ResourceRepo,
1316
) {
1417

15-
fun map(
18+
fun mapFiltered(
1619
filter: ActivityFilter,
1720
isDarkTheme: Boolean,
21+
selected: Boolean,
1822
): ActivityFilterViewData {
19-
return mapFiltered(
20-
filter = filter,
21-
isDarkTheme = isDarkTheme,
22-
selected = filter.selected,
23+
return ActivityFilterViewData(
24+
id = filter.id,
25+
name = filter.name,
26+
iconColor = mapFilterIconColor(
27+
selected = selected,
28+
isDarkTheme = isDarkTheme,
29+
),
30+
color = mapFilterColor(
31+
selected = selected,
32+
color = filter.color,
33+
isDarkTheme = isDarkTheme,
34+
),
35+
selected = selected,
36+
type = ActivityFilterType.Default,
2337
)
2438
}
2539

2640
fun mapFiltered(
27-
filter: ActivityFilter,
41+
filter: PredefinedFilter,
2842
isDarkTheme: Boolean,
2943
selected: Boolean,
3044
): ActivityFilterViewData {
3145
return ActivityFilterViewData(
32-
id = filter.id,
46+
id = filter.categoryId,
3347
name = filter.name,
34-
iconColor = if (selected) {
35-
colorMapper.toIconColor(isDarkTheme)
36-
} else {
37-
colorMapper.toFilteredIconColor(isDarkTheme)
38-
},
39-
color = if (selected) {
40-
colorMapper.mapToColorInt(filter.color, isDarkTheme)
41-
} else {
42-
colorMapper.toFilteredColor(isDarkTheme)
43-
},
48+
iconColor = mapFilterIconColor(
49+
selected = selected,
50+
isDarkTheme = isDarkTheme,
51+
),
52+
color = mapFilterColor(
53+
selected = selected,
54+
color = filter.color,
55+
isDarkTheme = isDarkTheme,
56+
),
4457
selected = selected,
58+
type = ActivityFilterType.Predefined,
4559
)
4660
}
4761

@@ -70,4 +84,27 @@ class ActivityFilterViewDataMapper @Inject constructor(
7084
color = colorMapper.toInactiveColor(isDarkTheme),
7185
)
7286
}
87+
88+
private fun mapFilterIconColor(
89+
selected: Boolean,
90+
isDarkTheme: Boolean,
91+
): Int {
92+
return if (selected) {
93+
colorMapper.toIconColor(isDarkTheme)
94+
} else {
95+
colorMapper.toFilteredIconColor(isDarkTheme)
96+
}
97+
}
98+
99+
private fun mapFilterColor(
100+
selected: Boolean,
101+
color: AppColor,
102+
isDarkTheme: Boolean,
103+
): Int {
104+
return if (selected) {
105+
colorMapper.mapToColorInt(color, isDarkTheme)
106+
} else {
107+
colorMapper.toFilteredColor(isDarkTheme)
108+
}
109+
}
73110
}

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,10 @@ import com.example.util.simpletimetracker.data_local.prefs.PrefsRepoImpl.Compani
5555
import com.example.util.simpletimetracker.data_local.prefs.PrefsRepoImpl.Companion.KEY_REPEAT_BUTTON_TYPE
5656
import com.example.util.simpletimetracker.data_local.prefs.PrefsRepoImpl.Companion.KEY_RETROACTIVE_TRACKING_MODE
5757
import com.example.util.simpletimetracker.data_local.prefs.PrefsRepoImpl.Companion.KEY_REVERSE_ORDER_IN_CALENDAR
58+
import com.example.util.simpletimetracker.data_local.prefs.PrefsRepoImpl.Companion.KEY_SELECTED_PREDEFINED_FILTERS
5859
import com.example.util.simpletimetracker.data_local.prefs.PrefsRepoImpl.Companion.KEY_SHOW_ACTIVITY_FILTERS
5960
import com.example.util.simpletimetracker.data_local.prefs.PrefsRepoImpl.Companion.KEY_SHOW_CALENDAR_BUTTON_ON_RECORDS_TAB
61+
import com.example.util.simpletimetracker.data_local.prefs.PrefsRepoImpl.Companion.KEY_SHOW_CATEGORIES_AS_PREDEFINED_FILTERS
6062
import com.example.util.simpletimetracker.data_local.prefs.PrefsRepoImpl.Companion.KEY_SHOW_COMMENT_INPUT
6163
import com.example.util.simpletimetracker.data_local.prefs.PrefsRepoImpl.Companion.KEY_SHOW_COMMENT_INPUT_EXCLUDE_ACTIVITIES
6264
import com.example.util.simpletimetracker.data_local.prefs.PrefsRepoImpl.Companion.KEY_SHOW_GOALS_SEPARATELY
@@ -183,13 +185,15 @@ class BackupPrefsRepo @Inject constructor(
183185
PrefsProcessor(KEY_DAYS_IN_CALENDAR, ::daysInCalendar),
184186
PrefsProcessor(KEY_SHOW_ACTIVITY_FILTERS, ::showActivityFilters),
185187
PrefsProcessor(KEY_IS_ACTIVITY_FILTERS_COLLAPSED, ::isActivityFiltersCollapsed),
188+
PrefsProcessor(KEY_ALLOW_MULTIPLE_ACTIVITY_FILTERS, ::allowMultipleActivityFilters),
189+
PrefsProcessor(KEY_SHOW_CATEGORIES_AS_PREDEFINED_FILTERS, ::showCategoriesAsPredefinedFilters),
190+
PrefsProcessor(KEY_SELECTED_PREDEFINED_FILTERS, ::selectedPredefinedFilters),
186191
PrefsProcessor(KEY_ENABLE_REPEAT_BUTTON, ::enableRepeatButton),
187192
PrefsProcessor(KEY_ENABLE_POMODORO_MODE, ::enablePomodoroMode),
188193
PrefsProcessor(KEY_POMODORO_FOCUS_TIME, ::pomodoroFocusTime),
189194
PrefsProcessor(KEY_POMODORO_BREAK_TIME, ::pomodoroBreakTime),
190195
PrefsProcessor(KEY_POMODORO_LONG_BREAK_TIME, ::pomodoroLongBreakTime),
191196
PrefsProcessor(KEY_POMODORO_PERIODS_UNTIL_LONG_BREAK, ::pomodoroPeriodsUntilLongBreak),
192-
PrefsProcessor(KEY_ALLOW_MULTIPLE_ACTIVITY_FILTERS, ::allowMultipleActivityFilters),
193197
PrefsProcessor(KEY_SHOW_GOALS_SEPARATELY, ::showGoalsSeparately),
194198
PrefsProcessor(KEY_ALLOW_MULTITASKING, ::allowMultitasking),
195199
PrefsProcessor(KEY_SHOW_NOTIFICATIONS, ::showNotifications),

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

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,18 @@ class PrefsRepoImpl @Inject constructor(
189189
KEY_IS_ACTIVITY_FILTERS_COLLAPSED, false,
190190
)
191191

192+
override var allowMultipleActivityFilters: Boolean by prefs.delegate(
193+
KEY_ALLOW_MULTIPLE_ACTIVITY_FILTERS, true,
194+
)
195+
196+
override var showCategoriesAsPredefinedFilters: Boolean by prefs.delegate(
197+
KEY_SHOW_CATEGORIES_AS_PREDEFINED_FILTERS, false
198+
)
199+
200+
override var selectedPredefinedFilters: Set<String> by prefs.delegate(
201+
KEY_SELECTED_PREDEFINED_FILTERS, emptySet()
202+
)
203+
192204
override var enableRepeatButton: Boolean by prefs.delegate(
193205
KEY_ENABLE_REPEAT_BUTTON, false,
194206
)
@@ -217,10 +229,6 @@ class PrefsRepoImpl @Inject constructor(
217229
KEY_POMODORO_PERIODS_UNTIL_LONG_BREAK, POMODORO_DEFAULT_UNTIL_LONG_BREAK,
218230
)
219231

220-
override var allowMultipleActivityFilters: Boolean by prefs.delegate(
221-
KEY_ALLOW_MULTIPLE_ACTIVITY_FILTERS, true,
222-
)
223-
224232
override var showGoalsSeparately: Boolean by prefs.delegate(
225233
KEY_SHOW_GOALS_SEPARATELY, false,
226234
)
@@ -650,6 +658,8 @@ class PrefsRepoImpl @Inject constructor(
650658
const val KEY_POMODORO_LONG_BREAK_TIME = "pomodoroLongBreakTime"
651659
const val KEY_POMODORO_PERIODS_UNTIL_LONG_BREAK = "pomodoroPeriodsUntilLongBreak"
652660
const val KEY_ALLOW_MULTIPLE_ACTIVITY_FILTERS = "allowMultipleActivityFilters"
661+
const val KEY_SHOW_CATEGORIES_AS_PREDEFINED_FILTERS = "showCategoriesAsPredefinedFilters"
662+
const val KEY_SELECTED_PREDEFINED_FILTERS = "selectedPredefinedFilters"
653663
const val KEY_SHOW_GOALS_SEPARATELY = "showGoalsSeparately"
654664
const val KEY_ALLOW_MULTITASKING = "allowMultitasking"
655665
const val KEY_SHOW_NOTIFICATIONS = "showNotifications"

domain/src/main/java/com/example/util/simpletimetracker/domain/activityFilter/interactor/ActivityFilterInteractor.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ class ActivityFilterInteractor @Inject constructor(
2929
activityFilterRepo.changeSelected(id, selected)
3030
}
3131

32-
suspend fun changeSelectedAll(selected: Boolean) {
33-
activityFilterRepo.changeSelectedAll(selected)
32+
suspend fun disableAll() {
33+
activityFilterRepo.changeSelectedAll(selected = false)
3434
}
3535

3636
suspend fun remove(id: Long) {
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,32 @@
11
package com.example.util.simpletimetracker.domain.activityFilter.interactor
22

3+
import com.example.util.simpletimetracker.domain.activityFilter.model.ActivityFilterType
34
import com.example.util.simpletimetracker.domain.prefs.interactor.PrefsInteractor
45
import javax.inject.Inject
56

67
class ChangeSelectedActivityFilterMediator @Inject constructor(
78
private val prefsInteractor: PrefsInteractor,
89
private val activityFilterInteractor: ActivityFilterInteractor,
10+
private val predefinedFilterInteractor: PredefinedFilterInteractor,
911
) {
1012

1113
suspend fun onFilterClicked(
1214
id: Long,
15+
type: ActivityFilterType,
1316
selected: Boolean,
1417
) {
1518
val newValue = !selected
1619
if (newValue && !prefsInteractor.getAllowMultipleActivityFilters()) {
17-
activityFilterInteractor.changeSelectedAll(selected = false)
20+
activityFilterInteractor.disableAll()
21+
predefinedFilterInteractor.disableAll()
22+
}
23+
when (type) {
24+
is ActivityFilterType.Default -> {
25+
activityFilterInteractor.changeSelected(id, newValue)
26+
}
27+
is ActivityFilterType.Predefined-> {
28+
predefinedFilterInteractor.changeSelected(id, newValue)
29+
}
1830
}
19-
activityFilterInteractor.changeSelected(id, newValue)
2031
}
2132
}

0 commit comments

Comments
 (0)