Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ fun SearchBar(
searchQuery: String = "",
collapsable: Boolean = true,
@DrawableRes hintIcon: Int? = null,
collapseOnSearch: Boolean = false
collapseOnSearch: Boolean = false,
onQueryChange: ((String) -> Unit)? = null
) {
Row(
modifier = modifier
Expand Down Expand Up @@ -103,7 +104,10 @@ fun SearchBar(
.focusRequester(focusRequester),
placeholder = { Text(placeholder) },
value = query,
onValueChange = { query = it },
onValueChange = {
query = it
onQueryChange?.invoke(it)
},
singleLine = true,
keyboardOptions = KeyboardOptions.Default.copy(
imeAction = ImeAction.Search
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ import com.instructure.pandautils.compose.composables.ErrorContent
import com.instructure.pandautils.compose.composables.FullScreenDialog
import com.instructure.pandautils.compose.composables.GroupHeader
import com.instructure.pandautils.compose.composables.Loading
import com.instructure.pandautils.compose.composables.SearchBar
import com.instructure.pandautils.compose.composables.SubmissionState
import com.instructure.pandautils.features.grades.gradepreferences.GradePreferencesScreen
import com.instructure.pandautils.utils.DisplayGrade
Expand Down Expand Up @@ -296,6 +297,26 @@ private fun GradesScreenContent(
)
}

if (uiState.isSearchExpanded) {
SearchBar(
icon = R.drawable.ic_search_white_24dp,
searchQuery = uiState.searchQuery,
tintColor = colorResource(R.color.textDarkest),
placeholder = stringResource(R.string.search),
collapsable = false,
onSearch = {
actionHandler(GradesAction.SearchQueryChanged(it))
},
onClear = {
actionHandler(GradesAction.SearchQueryChanged(""))
},
onQueryChange = {
actionHandler(GradesAction.SearchQueryChanged(it))
},
modifier = Modifier.testTag("searchField")
)
}

if (uiState.items.isEmpty()) {
EmptyContent()
}
Expand Down Expand Up @@ -422,6 +443,27 @@ private fun GradesCard(
modifier = Modifier.size(24.dp)
)
}
Box(
modifier = Modifier
.size(48.dp)
.clip(CircleShape)
.clickable {
actionHandler(GradesAction.ToggleSearch)
}
.semantics {
role = Role.Button
},
contentAlignment = Alignment.Center
) {
Icon(
painter = painterResource(id = R.drawable.ic_search_white_24dp),
contentDescription = stringResource(id = R.string.search),
tint = Color(userColor),
modifier = Modifier
.size(24.dp)
.testTag("searchIcon")
)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ data class GradesUiState(
val onlyGradedAssignmentsSwitchEnabled: Boolean = true,
val gradeText: String = "",
val isGradeLocked: Boolean = false,
val snackbarMessage: String? = null
val snackbarMessage: String? = null,
val searchQuery: String = "",
val isSearchExpanded: Boolean = false
)

data class AssignmentGroupUiState(
Expand Down Expand Up @@ -97,6 +99,8 @@ sealed class GradesAction {
data class AssignmentClick(val id: Long) : GradesAction()
data object SnackbarDismissed : GradesAction()
data class ToggleCheckpointsExpanded(val assignmentId: Long) : GradesAction()
data object ToggleSearch : GradesAction()
data class SearchQueryChanged(val query: String) : GradesAction()
}

sealed class GradesViewModelAction {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ class GradesViewModel @Inject constructor(
private var courseGrade: CourseGrade? = null

private var customStatuses = listOf<CustomGradeStatusesQuery.Node>()
private var allItems = emptyList<AssignmentGroupUiState>()

init {
loadGrades(
Expand Down Expand Up @@ -121,16 +122,18 @@ class GradesViewModel @Inject constructor(

courseGrade = repository.getCourseGrade(course, repository.studentId, enrollments, selectedGradingPeriod?.id)

val items = when (sortBy) {
allItems = when (sortBy) {
SortBy.GROUP -> groupByAssignmentGroup(assignmentGroups)
SortBy.DUE_DATE -> groupByDueDate(assignmentGroups)
}.filter {
it.assignments.isNotEmpty()
}

val filteredItems = filterItems(allItems, _uiState.value.searchQuery)

_uiState.update {
it.copy(
items = items,
items = filteredItems,
isLoading = false,
isRefreshing = false,
gradePreferencesUiState = it.gradePreferencesUiState.copy(
Expand Down Expand Up @@ -280,6 +283,21 @@ class GradesViewModel @Inject constructor(
context.getString(R.string.due, "$dateText $timeText")
} ?: context.getString(R.string.gradesNoDueDate)

private fun filterItems(items: List<AssignmentGroupUiState>, query: String): List<AssignmentGroupUiState> {
if (query.length < 3) return items

return items.mapNotNull { group ->
val filteredAssignments = group.assignments.filter { assignment ->
assignment.name.contains(query, ignoreCase = true)
}
if (filteredAssignments.isEmpty()) {
null
} else {
group.copy(assignments = filteredAssignments)
}
}
}

fun handleAction(action: GradesAction) {
when (action) {
is GradesAction.Refresh -> {
Expand Down Expand Up @@ -351,6 +369,27 @@ class GradesViewModel @Inject constructor(
}
_uiState.update { it.copy(items = items) }
}

is GradesAction.ToggleSearch -> {
val isExpanding = !uiState.value.isSearchExpanded
_uiState.update {
it.copy(
isSearchExpanded = isExpanding,
searchQuery = if (!isExpanding) "" else it.searchQuery,
items = if (!isExpanding) allItems else it.items
)
}
}

is GradesAction.SearchQueryChanged -> {
val filteredItems = filterItems(allItems, action.query)
_uiState.update {
it.copy(
searchQuery = action.query,
items = filteredItems
)
}
}
}
}
}
Loading