Skip to content

Commit 2837f94

Browse files
whyash8adhiamboperes
authored andcommitted
Fix#3146 : Create a generic utility for filtering enums (#5529)
## Explanation Fixes: #3146 This PR introduces a new utility function filterByEnumCondition to standardize filtering of enums across various parts of the oppia-android codebase. This utility function allows filtering of collections based on a condition applied to enum values. This PR introduces a new utility function filterByEnumCondition to standardize filtering of enums across various parts of the oppia-android codebase. This utility function allows filtering of collections based on a condition applied to enum values. **Key Changes**: Added Utility Function: filterByEnumCondition: A generic function to filter a collection based on a condition applied to an enum extracted from each item in the collection. **Updated Existing Code**: Refactored code in getLeastRecentMetricLogIndex, getLeastRecentMediumPriorityEventIndex, and other methods to utilize the new filterByEnumCondition function. Updated the calculation of completedChapterCount and inProgressChapterCount using the new utility function. ## Essential Checklist <!-- Please tick the relevant boxes by putting an "x" in them. --> - [ x] The PR title and explanation each start with "Fix #bugnum: " (If this PR fixes part of an issue, prefix the title with "Fix part of #bugnum: ...".) - [x ] Any changes to [scripts/assets](https://github.com/oppia/oppia-android/tree/develop/scripts/assets) files have their rationale included in the PR explanation. - [x ] The PR follows the [style guide](https://github.com/oppia/oppia-android/wiki/Coding-style-guide). - [x ] The PR does not contain any unnecessary code changes from Android Studio ([reference](https://github.com/oppia/oppia-android/wiki/Guidance-on-submitting-a-PR#undo-unnecessary-changes)). - [ x] The PR is made from a branch that's **not** called "develop" and is up-to-date with "develop". - [x ] The PR is **assigned** to the appropriate reviewers ([reference](https://github.com/oppia/oppia-android/wiki/Guidance-on-submitting-a-PR#clarification-regarding-assignees-and-reviewers-section)). - --------- Co-authored-by: Adhiambo Peres <[email protected]>
1 parent 9d4edf0 commit 2837f94

File tree

9 files changed

+99
-58
lines changed

9 files changed

+99
-58
lines changed

.github/CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@
163163
# Utilities that are primarily used for frontend/UI purposes.
164164
/utility/src/*/java/org/oppia/android/util/accessibility/ @oppia/android-frontend-reviewers
165165
/utility/src/*/java/org/oppia/android/util/statusbar/ @oppia/android-frontend-reviewers
166+
/utility/src/main/java/org/oppia/android/util/enumfilter/ @oppia/android-frontend-reviewers
166167
/utility/src/*/java/org/oppia/android/util/extensions/ @oppia/android-frontend-reviewers
167168
/utility/src/*/java/org/oppia/android/util/parser/html @oppia/android-frontend-reviewers
168169
/utility/src/*/res/**/*.xml @oppia/android-frontend-reviewers

app/src/main/java/org/oppia/android/app/survey/surveyitemviewmodel/MarketFitItemsViewModel.kt

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import org.oppia.android.app.survey.PreviousAnswerHandler
1212
import org.oppia.android.app.survey.SelectedAnswerAvailabilityReceiver
1313
import org.oppia.android.app.survey.SelectedAnswerHandler
1414
import org.oppia.android.app.translation.AppLanguageResourceHandler
15+
import org.oppia.android.util.enumfilter.filterByEnumCondition
1516
import javax.inject.Inject
1617

1718
/** [SurveyAnswerItemViewModel] for the market fit question options. */
@@ -98,8 +99,12 @@ class MarketFitItemsViewModel @Inject constructor(
9899
private fun getMarketFitOptions(): ObservableList<MultipleChoiceOptionContentViewModel> {
99100
val appName = resourceHandler.getStringInLocale(R.string.app_name)
100101
val observableList = ObservableArrayList<MultipleChoiceOptionContentViewModel>()
101-
observableList += MarketFitAnswer.values()
102-
.filter { it.isValid() }
102+
val filteredmarketFitAnswer = filterByEnumCondition(
103+
MarketFitAnswer.values().toList(),
104+
{ marketFitAnswer -> marketFitAnswer },
105+
{ marketFitAnswer -> marketFitAnswer.isValid() }
106+
)
107+
observableList += filteredmarketFitAnswer
103108
.mapIndexed { index, marketFitAnswer ->
104109
when (marketFitAnswer) {
105110
MarketFitAnswer.VERY_DISAPPOINTED -> MultipleChoiceOptionContentViewModel(

app/src/main/java/org/oppia/android/app/survey/surveyitemviewmodel/UserTypeItemsViewModel.kt

Lines changed: 30 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import org.oppia.android.app.survey.SelectedAnswerAvailabilityReceiver
1212
import org.oppia.android.app.survey.SelectedAnswerHandler
1313
import org.oppia.android.app.translation.AppLanguageResourceHandler
1414
import org.oppia.android.app.viewmodel.ObservableArrayList
15+
import org.oppia.android.util.enumfilter.filterByEnumCondition
1516
import javax.inject.Inject
1617

1718
/** [SurveyAnswerItemViewModel] for providing the type of user question options. */
@@ -97,46 +98,36 @@ class UserTypeItemsViewModel @Inject constructor(
9798

9899
private fun getUserTypeOptions(): ObservableArrayList<MultipleChoiceOptionContentViewModel> {
99100
val observableList = ObservableArrayList<MultipleChoiceOptionContentViewModel>()
100-
observableList += UserTypeAnswer.values()
101-
.filter { it.isValid() }
102-
.mapIndexed { index, userTypeOption ->
103-
when (userTypeOption) {
104-
UserTypeAnswer.LEARNER ->
105-
MultipleChoiceOptionContentViewModel(
106-
resourceHandler.getStringInLocale(
107-
R.string.user_type_answer_learner
108-
),
109-
index,
110-
this
111-
)
112-
UserTypeAnswer.TEACHER -> MultipleChoiceOptionContentViewModel(
113-
resourceHandler.getStringInLocale(
114-
R.string.user_type_answer_teacher
115-
),
116-
index,
117-
this
118-
)
119-
120-
UserTypeAnswer.PARENT ->
121-
MultipleChoiceOptionContentViewModel(
122-
resourceHandler.getStringInLocale(
123-
R.string.user_type_answer_parent
124-
),
125-
index,
126-
this
127-
)
128-
129-
UserTypeAnswer.OTHER ->
130-
MultipleChoiceOptionContentViewModel(
131-
resourceHandler.getStringInLocale(
132-
R.string.user_type_answer_other
133-
),
134-
index,
135-
this
136-
)
137-
else -> throw IllegalStateException("Invalid UserTypeAnswer")
138-
}
101+
val filteredUserTypes = filterByEnumCondition(
102+
UserTypeAnswer.values().toList(),
103+
{ userTypeAnswer -> userTypeAnswer },
104+
{ userTypeAnswer -> userTypeAnswer.isValid() }
105+
)
106+
observableList += filteredUserTypes.mapIndexed { index, userTypeOption ->
107+
when (userTypeOption) {
108+
UserTypeAnswer.LEARNER -> MultipleChoiceOptionContentViewModel(
109+
resourceHandler.getStringInLocale(R.string.user_type_answer_learner),
110+
index,
111+
this
112+
)
113+
UserTypeAnswer.TEACHER -> MultipleChoiceOptionContentViewModel(
114+
resourceHandler.getStringInLocale(R.string.user_type_answer_teacher),
115+
index,
116+
this
117+
)
118+
UserTypeAnswer.PARENT -> MultipleChoiceOptionContentViewModel(
119+
resourceHandler.getStringInLocale(R.string.user_type_answer_parent),
120+
index,
121+
this
122+
)
123+
UserTypeAnswer.OTHER -> MultipleChoiceOptionContentViewModel(
124+
resourceHandler.getStringInLocale(R.string.user_type_answer_other),
125+
index,
126+
this
127+
)
128+
else -> throw IllegalStateException("Invalid UserTypeAnswer")
139129
}
130+
}
140131
return observableList
141132
}
142133

app/src/main/java/org/oppia/android/app/topic/lessons/TopicLessonsFragmentPresenter.kt

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import org.oppia.android.domain.oppialogger.OppiaLogger
3030
import org.oppia.android.util.accessibility.AccessibilityService
3131
import org.oppia.android.util.data.AsyncResult
3232
import org.oppia.android.util.data.DataProviders.Companion.toLiveData
33+
import org.oppia.android.util.enumfilter.filterByEnumCondition
3334
import javax.inject.Inject
3435

3536
/** The presenter for [TopicLessonsFragment]. */
@@ -161,18 +162,18 @@ class TopicLessonsFragmentPresenter @Inject constructor(
161162

162163
val chapterSummaries = storySummaryViewModel
163164
.storySummary.chapterList
164-
val completedChapterCount =
165-
chapterSummaries.map(ChapterSummary::getChapterPlayState)
166-
.filter {
167-
it == ChapterPlayState.COMPLETED
168-
}
169-
.size
165+
val completedChapterCount = filterByEnumCondition(
166+
chapterSummaries.map(ChapterSummary::getChapterPlayState),
167+
{ it },
168+
{ it == ChapterPlayState.COMPLETED }
169+
).size
170+
170171
val inProgressChapterCount =
171-
chapterSummaries.map(ChapterSummary::getChapterPlayState)
172-
.filter {
173-
it == ChapterPlayState.IN_PROGRESS_SAVED
174-
}
175-
.size
172+
filterByEnumCondition(
173+
chapterSummaries.map(ChapterSummary::getChapterPlayState),
174+
{ it },
175+
{ it == ChapterPlayState.IN_PROGRESS_SAVED }
176+
).size
176177

177178
val storyPercentage: Int =
178179
(completedChapterCount * 100) / storySummaryViewModel.storySummary.chapterCount

domain/src/main/java/org/oppia/android/domain/oppialogger/analytics/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ kt_android_library(
4949
"//domain/src/main/java/org/oppia/android/domain/oppialogger:prod_module",
5050
"//model/src/main/proto:performance_metrics_event_logger_java_proto_lite",
5151
"//utility/src/main/java/org/oppia/android/util/data:data_provider",
52+
"//utility/src/main/java/org/oppia/android/util/enumfilter:enum_filter_util",
5253
"//utility/src/main/java/org/oppia/android/util/logging:console_logger",
5354
"//utility/src/main/java/org/oppia/android/util/logging:exception_logger",
5455
"//utility/src/main/java/org/oppia/android/util/logging/performancemetrics:performance_metrics_assessor",

domain/src/main/java/org/oppia/android/domain/oppialogger/analytics/PerformanceMetricsController.kt

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import org.oppia.android.app.model.ScreenName
77
import org.oppia.android.data.persistence.PersistentCacheStore
88
import org.oppia.android.domain.oppialogger.PerformanceMetricsLogStorageCacheSize
99
import org.oppia.android.util.data.DataProvider
10+
import org.oppia.android.util.enumfilter.filterByEnumCondition
1011
import org.oppia.android.util.logging.ConsoleLogger
1112
import org.oppia.android.util.logging.ExceptionLogger
1213
import org.oppia.android.util.logging.performancemetrics.PerformanceMetricsAssessor
@@ -128,9 +129,11 @@ class PerformanceMetricsController @Inject constructor(
128129
* priority is returned.
129130
*/
130131
private fun getLeastRecentMetricLogIndex(oppiaMetricLogs: OppiaMetricLogs): Int? =
131-
oppiaMetricLogs.oppiaMetricLogList.withIndex()
132-
.filter { it.value.priority == Priority.LOW_PRIORITY }
133-
.minByOrNull { it.value.timestampMillis }?.index
132+
filterByEnumCondition(
133+
oppiaMetricLogs.oppiaMetricLogList.withIndex().toList(),
134+
{ it.value.priority },
135+
{ it == Priority.LOW_PRIORITY }
136+
).minByOrNull { it.value.timestampMillis }?.index
134137
?: getLeastRecentMediumPriorityEventIndex(oppiaMetricLogs)
135138

136139
/**
@@ -142,9 +145,11 @@ class PerformanceMetricsController @Inject constructor(
142145
* priority is returned.
143146
*/
144147
private fun getLeastRecentMediumPriorityEventIndex(oppiaMetricLogs: OppiaMetricLogs): Int? =
145-
oppiaMetricLogs.oppiaMetricLogList.withIndex()
146-
.filter { it.value.priority == Priority.MEDIUM_PRIORITY }
147-
.minByOrNull { it.value.timestampMillis }?.index
148+
filterByEnumCondition(
149+
oppiaMetricLogs.oppiaMetricLogList.withIndex().toList(),
150+
{ it.value.priority },
151+
{ it == Priority.MEDIUM_PRIORITY }
152+
).minByOrNull { it.value.timestampMillis }?.index
148153
?: getLeastRecentGeneralEventIndex(oppiaMetricLogs)
149154

150155
/** Returns the index of the least recent event regardless of their priority. */

scripts/assets/test_file_exemptions.textproto

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4310,6 +4310,10 @@ test_file_exemption {
43104310
exempted_file_path: "utility/src/main/java/org/oppia/android/util/extensions/ContextExtensions.kt"
43114311
test_file_not_required: true
43124312
}
4313+
test_file_exemption {
4314+
exempted_file_path: "utility/src/main/java/org/oppia/android/util/enumfilter/EnumFilterUtil.kt"
4315+
test_file_not_required: true
4316+
}
43134317
test_file_exemption {
43144318
exempted_file_path: "utility/src/main/java/org/oppia/android/util/extensions/StringExtensions.kt"
43154319
source_file_is_incompatible_with_code_coverage: true
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
"""
2+
General purpose utility for filtering enums.
3+
"""
4+
5+
load("@io_bazel_rules_kotlin//kotlin:android.bzl", "kt_android_library")
6+
7+
kt_android_library(
8+
name = "enum_filter_util",
9+
srcs = [
10+
"EnumFilterUtil.kt",
11+
],
12+
visibility = ["//:oppia_api_visibility"],
13+
)
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package org.oppia.android.util.enumfilter
2+
3+
/**
4+
* Filters a collection based on a condition applied to an enum property of each element.
5+
*
6+
* @param E the type of enum values.
7+
* @param T the type of elements in the collection.
8+
* @param collection the collection of elements to filter.
9+
* @param enumExtractor a function that extracts the enum value from each element.
10+
* @param condition a predicate function that determines if an enum value should be included in the result.
11+
* @return a list of elements from the collection that satisfy the condition when their enum property is evaluated.
12+
*/
13+
14+
inline fun <E : Enum<E>, T> filterByEnumCondition(
15+
collection: Collection<T>,
16+
enumExtractor: (T) -> E,
17+
condition: (E) -> Boolean
18+
): List<T> {
19+
return collection.filter { condition(enumExtractor(it)) }
20+
}

0 commit comments

Comments
 (0)