Skip to content

Commit 112b86b

Browse files
committed
add shortcuts to universal widget, apply filters to suggestions and shortcuts
1 parent 2bb2153 commit 112b86b

8 files changed

Lines changed: 182 additions & 69 deletions

File tree

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

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import com.example.util.simpletimetracker.domain.activityFilter.model.ActivityFi
77
import com.example.util.simpletimetracker.domain.activityFilter.model.PredefinedFilter
88
import com.example.util.simpletimetracker.domain.category.interactor.RecordTypeCategoryInteractor
99
import com.example.util.simpletimetracker.domain.prefs.interactor.PrefsInteractor
10+
import com.example.util.simpletimetracker.domain.recordShortcut.model.RecordShortcut
1011
import com.example.util.simpletimetracker.domain.recordType.model.RecordType
1112
import com.example.util.simpletimetracker.feature_base_adapter.ViewHolderType
1213
import javax.inject.Inject
@@ -82,14 +83,37 @@ class ActivityFilterViewDataInteractor @Inject constructor(
8283
list: List<RecordType>,
8384
filter: Filter,
8485
): List<RecordType> {
86+
return applyFilter(
87+
list = list,
88+
filter = filter,
89+
predicate = { data, typeIds -> data.id in typeIds },
90+
)
91+
}
92+
93+
suspend fun applyFilterToShortcuts(
94+
list: List<RecordShortcut>,
95+
filter: Filter,
96+
): List<RecordShortcut> {
97+
return applyFilter(
98+
list = list,
99+
filter = filter,
100+
predicate = { data, typeIds -> data.typeId in typeIds },
101+
)
102+
}
103+
104+
private suspend fun <T> applyFilter(
105+
list: List<T>,
106+
filter: Filter,
107+
predicate: (data: T, typeIds: List<Long>) -> Boolean,
108+
): List<T> {
85109
if (filter !is Filter.ApplyFilter) return list
86110

87111
val hasAnySelectedFilters = filter.userFilters.any { it.selected } ||
88112
filter.predefinedFilters.any { it.selected }
89113

90114
return if (hasAnySelectedFilters) {
91115
val selectedTypes = getSelectedTypeIds(filter)
92-
list.filter { it.id in selectedTypes }
116+
list.filter { predicate(it, selectedTypes) }
93117
} else {
94118
list
95119
}

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,28 +6,31 @@ import com.example.util.simpletimetracker.domain.activitySuggestion.interactor.G
66
import com.example.util.simpletimetracker.domain.record.model.RunningRecord
77
import com.example.util.simpletimetracker.domain.recordType.model.RecordType
88
import com.example.util.simpletimetracker.domain.recordType.model.RecordTypeGoal
9-
import com.example.util.simpletimetracker.feature_base_adapter.ViewHolderType
109
import com.example.util.simpletimetracker.feature_base_adapter.recordTypeSuggestion.RecordTypeSuggestionViewData
1110
import javax.inject.Inject
1211

1312
class ActivitySuggestionViewDataInteractor @Inject constructor(
1413
private val getCurrentActivitySuggestionsInteractor: GetCurrentActivitySuggestionsInteractor,
1514
private val recordTypeViewDataMapper: RecordTypeViewDataMapper,
15+
private val activityFilterViewDataInteractor: ActivityFilterViewDataInteractor,
1616
) {
1717

1818
suspend fun getSuggestionsViewData(
19+
filter: ActivityFilterViewDataInteractor.Filter,
1920
recordTypesMap: Map<Long, RecordType>,
2021
goals: Map<Long, List<RecordTypeGoal>>,
2122
runningRecords: List<RunningRecord>,
2223
allDailyCurrents: Map<Long, GetCurrentRecordsDurationInteractor.Result>,
2324
completeTypeIds: Set<Long>,
2425
numberOfCards: Int,
2526
isDarkTheme: Boolean,
26-
): List<ViewHolderType> {
27+
): List<RecordTypeSuggestionViewData> {
2728
val suggestionTypes = getCurrentActivitySuggestionsInteractor.execute(
2829
recordTypesMap = recordTypesMap,
2930
runningRecords = runningRecords,
30-
)
31+
).let {
32+
activityFilterViewDataInteractor.applyFilter(it, filter)
33+
}
3134

3235
return suggestionTypes.map { recordType ->
3336
recordTypeViewDataMapper.map(
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package com.example.util.simpletimetracker.core.interactor
2+
3+
import com.example.util.simpletimetracker.core.mapper.RecordShortcutViewDataMapper
4+
import com.example.util.simpletimetracker.domain.record.model.RunningRecord
5+
import com.example.util.simpletimetracker.domain.recordShortcut.interactor.RecordShortcutInteractor
6+
import com.example.util.simpletimetracker.domain.recordTag.model.RecordTag
7+
import com.example.util.simpletimetracker.domain.recordType.model.RecordType
8+
import com.example.util.simpletimetracker.feature_base_adapter.recordShortcut.RecordShortcutViewData
9+
import javax.inject.Inject
10+
11+
class RecordsShortcutsViewDataInteractor @Inject constructor(
12+
private val recordShortcutInteractor: RecordShortcutInteractor,
13+
private val recordShortcutViewDataMapper: RecordShortcutViewDataMapper,
14+
private val activityFilterViewDataInteractor: ActivityFilterViewDataInteractor,
15+
) {
16+
17+
suspend fun getShortcutsViewData(
18+
filter: ActivityFilterViewDataInteractor.Filter,
19+
recordTypesMap: Map<Long, RecordType>,
20+
recordTags: List<RecordTag>,
21+
runningRecords: List<RunningRecord>,
22+
isDarkTheme: Boolean,
23+
): List<RecordShortcutViewData> {
24+
val shortcuts = recordShortcutInteractor.getAll()
25+
26+
val runningRecordsProcessed = runningRecords.map { runningRecord ->
27+
runningRecord.copy(tags = runningRecord.tags.sortedBy { it.tagId })
28+
}
29+
30+
return shortcuts.let {
31+
activityFilterViewDataInteractor.applyFilterToShortcuts(it, filter)
32+
}.mapNotNull { shortcut ->
33+
val isRunning = runningRecordsProcessed.any { runningRecord ->
34+
runningRecord.id == shortcut.typeId &&
35+
runningRecord.comment == shortcut.comment &&
36+
runningRecord.tags == shortcut.tags.sortedBy { it.tagId }
37+
}
38+
recordShortcutViewDataMapper.map(
39+
shortcut = shortcut,
40+
recordType = recordTypesMap[shortcut.typeId] ?: return@mapNotNull null,
41+
recordTags = recordTags,
42+
isDarkTheme = isDarkTheme,
43+
isFiltered = isRunning,
44+
)
45+
}
46+
}
47+
}

domain/src/main/java/com/example/util/simpletimetracker/domain/extension/CollectionExtensions.kt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,17 @@ operator fun <T> List<T>.plus(elements: List<T>?): List<T> {
5353

5454
inline fun <T> List<T>.replaceWith(new: T, crossinline filter: (T) -> Boolean): List<T> {
5555
return this.removeIf(filter).toMutableList().apply { add(new) }
56+
}
57+
58+
fun <T> List<T>.addBetweenEach(
59+
spacingProducer: (index: Int) -> T,
60+
): List<T> {
61+
val result = mutableListOf<T>()
62+
this.forEachIndexed { index, item ->
63+
result += item
64+
if (index != this.lastIndex) {
65+
result += spacingProducer(index)
66+
}
67+
}
68+
return result
5669
}

features/feature_base_adapter/src/main/java/com/example/util/simpletimetracker/feature_base_adapter/recordShortcut/RecordShortcutAdapterDelegate.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import com.example.util.simpletimetracker.feature_base_adapter.databinding.ItemR
77
import com.example.util.simpletimetracker.feature_base_adapter.recordShortcut.RecordShortcutViewData as ViewData
88

99
fun createRecordShortcutAdapterDelegate(
10-
onItemClick: ((ViewData) -> Unit) = { _ -> },
11-
onItemLongClick: ((ViewData) -> Unit) = { _ -> },
10+
onItemClick: (ViewData) -> Unit,
11+
onItemLongClick: ((ViewData) -> Unit)? = null,
1212
) = createRecyclerBindingAdapterDelegate<ViewData, Binding>(
1313
Binding::inflate,
1414
) { binding, item, _ ->
@@ -24,6 +24,6 @@ fun createRecordShortcutAdapterDelegate(
2424
item.data.icon?.let(this::itemIcon::set)
2525

2626
setOnClick { onItemClick(item) }
27-
setOnLongClick { onItemLongClick(item) }
27+
onItemLongClick?.let { setOnLongClick { it(item) } }
2828
}
2929
}

features/feature_running_records/src/main/java/com/example/util/simpletimetracker/feature_running_records/interactor/RunningRecordsViewDataInteractor.kt

Lines changed: 26 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ import com.example.util.simpletimetracker.core.interactor.ActivitySuggestionView
55
import com.example.util.simpletimetracker.core.interactor.FilterGoalsByDayOfWeekInteractor
66
import com.example.util.simpletimetracker.core.interactor.GetCurrentRecordsDurationInteractor
77
import com.example.util.simpletimetracker.core.interactor.GetRunningRecordViewDataMediator
8-
import com.example.util.simpletimetracker.core.mapper.RecordShortcutViewDataMapper
8+
import com.example.util.simpletimetracker.core.interactor.RecordsShortcutsViewDataInteractor
99
import com.example.util.simpletimetracker.core.mapper.RecordTypeViewDataMapper
10+
import com.example.util.simpletimetracker.domain.extension.addBetweenEach
1011
import com.example.util.simpletimetracker.domain.extension.plus
1112
import com.example.util.simpletimetracker.domain.prefs.interactor.PrefsInteractor
1213
import com.example.util.simpletimetracker.domain.record.interactor.RecordInteractor
1314
import com.example.util.simpletimetracker.domain.record.interactor.RunningRecordInteractor
1415
import com.example.util.simpletimetracker.domain.record.model.RunningRecord
15-
import com.example.util.simpletimetracker.domain.recordShortcut.interactor.RecordShortcutInteractor
1616
import com.example.util.simpletimetracker.domain.recordTag.interactor.RecordTagInteractor
1717
import com.example.util.simpletimetracker.domain.recordType.interactor.RecordTypeGoalInteractor
1818
import com.example.util.simpletimetracker.domain.recordType.interactor.RecordTypeInteractor
@@ -31,14 +31,13 @@ class RunningRecordsViewDataInteractor @Inject constructor(
3131
private val runningRecordInteractor: RunningRecordInteractor,
3232
private val recordInteractor: RecordInteractor,
3333
private val activityFilterViewDataInteractor: ActivityFilterViewDataInteractor,
34-
private val recordShortcutInteractor: RecordShortcutInteractor,
3534
private val mapper: RunningRecordsViewDataMapper,
3635
private val recordTypeViewDataMapper: RecordTypeViewDataMapper,
37-
private val recordShortcutViewDataMapper: RecordShortcutViewDataMapper,
3836
private val getRunningRecordViewDataMediator: GetRunningRecordViewDataMediator,
3937
private val getCurrentRecordsDurationInteractor: GetCurrentRecordsDurationInteractor,
4038
private val filterGoalsByDayOfWeekInteractor: FilterGoalsByDayOfWeekInteractor,
4139
private val activitySuggestionViewDataInteractor: ActivitySuggestionViewDataInteractor,
40+
private val recordsShortcutsViewDataInteractor: RecordsShortcutsViewDataInteractor,
4241
) {
4342

4443
suspend fun getViewData(
@@ -50,7 +49,6 @@ class RunningRecordsViewDataInteractor @Inject constructor(
5049
val recordTags = recordTagInteractor.getAll()
5150
val runningRecords = runningRecordInteractor.getAll()
5251
val recordTypesRunning = runningRecords.map(RunningRecord::id)
53-
val shortcuts = recordShortcutInteractor.getAll()
5452
val numberOfCards = prefsInteractor.getNumberOfCards()
5553
val isDarkTheme = prefsInteractor.getDarkMode()
5654
val useMilitaryTime = prefsInteractor.getUseMilitaryTimeFormat()
@@ -76,9 +74,6 @@ class RunningRecordsViewDataInteractor @Inject constructor(
7674
// No goals - no need to calculate durations.
7775
emptyMap()
7876
}
79-
val runningRecordsProcessed = runningRecords.map { runningRecord ->
80-
runningRecord.copy(tags = runningRecord.tags.sortedBy { it.tagId })
81-
}
8277

8378
val runningRecordsViewData = when {
8479
showFirstEnterHint -> {
@@ -123,8 +118,6 @@ class RunningRecordsViewDataInteractor @Inject constructor(
123118
mapper.mapToHasRunningRecords(),
124119
)
125120
}
126-
}.let {
127-
it + DividerViewData("running_records_divider".hashCode().toLong())
128121
}
129122

130123
val filter = activityFilterViewDataInteractor.getFilter()
@@ -133,21 +126,18 @@ class RunningRecordsViewDataInteractor @Inject constructor(
133126
isDarkTheme = isDarkTheme,
134127
isFiltersCollapsed = isFiltersCollapsed,
135128
appendAddButton = true,
136-
).let {
137-
if (it.isNotEmpty()) it + DividerViewData("filter_divider".hashCode().toLong()) else it
138-
}
129+
)
139130

140131
val suggestionsViewData = activitySuggestionViewDataInteractor.getSuggestionsViewData(
132+
filter = filter,
141133
recordTypesMap = recordTypesMap,
142134
goals = goals,
143135
runningRecords = runningRecords,
144136
allDailyCurrents = allDailyCurrents,
145137
completeTypeIds = completeTypeIds,
146138
numberOfCards = numberOfCards,
147139
isDarkTheme = isDarkTheme,
148-
).let {
149-
if (it.isNotEmpty()) it + DividerViewData("suggestions_divider".hashCode().toLong()) else it
150-
}
140+
)
151141

152142
val recordTypesViewData = recordTypes
153143
.filterNot {
@@ -199,24 +189,13 @@ class RunningRecordsViewDataInteractor @Inject constructor(
199189
}
200190
}
201191

202-
val shortcutsViewData = shortcuts.mapNotNull { shortcut ->
203-
val isRunning = runningRecordsProcessed.any { runningRecord ->
204-
runningRecord.id == shortcut.typeId &&
205-
runningRecord.comment == shortcut.comment &&
206-
runningRecord.tags == shortcut.tags.sortedBy { it.tagId }
207-
}
208-
recordShortcutViewDataMapper.map(
209-
shortcut = shortcut,
210-
recordType = recordTypesMap[shortcut.typeId] ?: return@mapNotNull null,
211-
recordTags = recordTags,
212-
isDarkTheme = isDarkTheme,
213-
isFiltered = isRunning,
214-
)
215-
}.takeIf {
216-
it.isNotEmpty()
217-
}?.let {
218-
listOf(DividerViewData("shortcuts_divider".hashCode().toLong())) + it
219-
}
192+
val shortcutsViewData = recordsShortcutsViewDataInteractor.getShortcutsViewData(
193+
filter = filter,
194+
recordTypesMap = recordTypesMap,
195+
recordTags = recordTags,
196+
runningRecords = runningRecords,
197+
isDarkTheme = isDarkTheme,
198+
)
220199

221200
// Flexbox layout doesn't fully support clipToPadding = false.
222201
// Because of that bottom padding with nav bar insets are not applied to main recycler.
@@ -231,11 +210,18 @@ class RunningRecordsViewDataInteractor @Inject constructor(
231210
).let(::listOf)
232211
}
233212

234-
return runningRecordsViewData +
235-
filtersViewData +
236-
suggestionsViewData +
237-
recordTypesViewData +
238-
shortcutsViewData +
239-
bottomSpaceForNavBar
213+
return listOf(
214+
runningRecordsViewData,
215+
filtersViewData,
216+
suggestionsViewData,
217+
recordTypesViewData,
218+
shortcutsViewData,
219+
).filter {
220+
it.isNotEmpty()
221+
}.addBetweenEach { index ->
222+
listOf(DividerViewData(index.toLong()))
223+
}.flatten().plus(
224+
bottomSpaceForNavBar,
225+
)
240226
}
241227
}

features/feature_widget/src/main/java/com/example/util/simpletimetracker/feature_widget/universal/view/WidgetUniversalFragment.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import com.example.util.simpletimetracker.feature_base_adapter.empty.createEmpty
2121
import com.example.util.simpletimetracker.feature_base_adapter.emptySpace.createEmptySpaceAdapterDelegate
2222
import com.example.util.simpletimetracker.feature_base_adapter.hint.createHintAdapterDelegate
2323
import com.example.util.simpletimetracker.feature_base_adapter.loader.createLoaderAdapterDelegate
24+
import com.example.util.simpletimetracker.feature_base_adapter.recordShortcut.createRecordShortcutAdapterDelegate
2425
import com.example.util.simpletimetracker.feature_base_adapter.recordType.createRecordTypeAdapterDelegate
2526
import com.example.util.simpletimetracker.feature_base_adapter.recordTypeSpecial.createRunningRecordTypeSpecialAdapterDelegate
2627
import com.example.util.simpletimetracker.feature_base_adapter.recordTypeSuggestion.createRecordTypeSuggestionAdapterDelegate
@@ -52,6 +53,7 @@ class WidgetUniversalFragment :
5253
createRecordTypeAdapterDelegate(viewModel::onRecordTypeClick),
5354
createRecordTypeSuggestionAdapterDelegate(RecordTypeSuggestionType, viewModel::onRecordTypeClick),
5455
createRunningRecordTypeSpecialAdapterDelegate(viewModel::onSpecialRecordTypeClick),
56+
createRecordShortcutAdapterDelegate(viewModel::onShortcutClick),
5557
createButtonAdapterDelegate(viewModel::onButtonClick),
5658
createEmptySpaceAdapterDelegate(),
5759
createDividerAdapterDelegate(),

0 commit comments

Comments
 (0)