Skip to content

Commit

Permalink
refactor: simplify SessionFilter logic (#341)
Browse files Browse the repository at this point in the history
  • Loading branch information
cbeyls authored Mar 1, 2025
1 parent 48b7e34 commit d9b4f65
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 101 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ private fun AgendaPagerOrLoading(
uiStateLce: Lce<AgendaState>,
isRefreshing: Boolean,
onRefresh: () -> Unit,
sessionFilters: List<SessionFilter>,
sessionFilters: Set<SessionFilter>,
onSessionClick: (UISession) -> Unit,
onApplyForAppClinicClick: () -> Unit,
onSessionBookmark: (UISession, Boolean) -> Unit
Expand All @@ -108,7 +108,7 @@ private fun AgendaPagerOrLoading(
isRefreshing = isRefreshing,
onRefresh = onRefresh,
initialPageIndex = days.todayPageIndex(),
filterList = sessionFilters,
sessionFilters = sessionFilters,
onSessionClick = onSessionClick,
onApplyForAppClinicClick = onApplyForAppClinicClick,
onSessionBookmark = onSessionBookmark
Expand All @@ -125,83 +125,68 @@ private fun List<DaySchedule>.todayPageIndex(): Int {
@Composable
private fun AgendaFilterDrawer(
rooms: List<Room>,
sessionFilters: List<SessionFilter>,
onFiltersChanged: (List<SessionFilter>) -> Unit,
sessionFilters: Set<SessionFilter>,
onFiltersChanged: (Set<SessionFilter>) -> Unit,
) {
Column(modifier = Modifier.fillMaxWidth()) {
HeaderItem(stringResource(MR.strings.filter))
FilterItem(
text = stringResource(MR.strings.bookmarked),
imageVector = Icons.Rounded.Bookmark,
checked = sessionFilters.any { it.type == SessionFilter.FilterType.BOOKMARK },
onCheck = { checked ->
val newSessionFilters = sessionFilters.toMutableList().apply {
removeAll { it.type == SessionFilter.FilterType.BOOKMARK }
if (checked) add(SessionFilter(SessionFilter.FilterType.BOOKMARK, ""))
}
onFiltersChanged(newSessionFilters)
}
filter = SessionFilter.Bookmark,
filters = sessionFilters,
text = stringResource(MR.strings.bookmarked),
imageVector = Icons.Rounded.Bookmark,
onFiltersChanged = onFiltersChanged
)

HeaderItem(stringResource(MR.strings.language))
val french = "French"
FilterItem(
text = stringResource(MR.strings.french),
language = french,
checked = sessionFilters.any { it.type == SessionFilter.FilterType.LANGUAGE && it.value == french },
onCheck = { checked ->
val newSessionFilters = sessionFilters.toMutableList().apply {
removeAll { it.type == SessionFilter.FilterType.LANGUAGE && it.value == french }
if (checked) add(SessionFilter(SessionFilter.FilterType.LANGUAGE, french))
}
onFiltersChanged(newSessionFilters)
}
filter = SessionFilter.Language(SessionFilter.Language.FRENCH),
filters = sessionFilters,
text = stringResource(MR.strings.french),
language = SessionFilter.Language.FRENCH,
onFiltersChanged = onFiltersChanged
)
val english = "English"
FilterItem(
text = stringResource(MR.strings.english),
language = english,
checked = sessionFilters.any { it.type == SessionFilter.FilterType.LANGUAGE && it.value == english },
onCheck = { checked ->
val newSessionFilters = sessionFilters.toMutableList().apply {
removeAll { it.type == SessionFilter.FilterType.LANGUAGE && it.value == english }
if (checked) add(SessionFilter(SessionFilter.FilterType.LANGUAGE, english))
}
onFiltersChanged(newSessionFilters)
}
filter = SessionFilter.Language(SessionFilter.Language.ENGLISH),
filters = sessionFilters,
text = stringResource(MR.strings.english),
language = SessionFilter.Language.ENGLISH,
onFiltersChanged = onFiltersChanged
)

HeaderItem(stringResource(MR.strings.rooms))
for (room in rooms) {
FilterItem(
text = room.name,
imageVector = Icons.Rounded.Room,
checked = sessionFilters.any { it.type == SessionFilter.FilterType.ROOM && it.value == room.id },
onCheck = { checked ->
val newSessionFilters = sessionFilters.toMutableList().apply {
removeAll { it.type == SessionFilter.FilterType.ROOM && it.value == room.id }
if (checked) add(SessionFilter(SessionFilter.FilterType.ROOM, room.id))
}
onFiltersChanged(newSessionFilters)
}
filter = SessionFilter.Room(room.id),
filters = sessionFilters,
text = room.name,
imageVector = Icons.Rounded.Room,
onFiltersChanged = onFiltersChanged
)
}
}
}

@Composable
private fun FilterItem(
filter: SessionFilter,
filters: Set<SessionFilter>,
text: String,
imageVector: ImageVector? = null,
language: String? = null,
checked: Boolean,
onCheck: (checked: Boolean) -> Unit,
onFiltersChanged: (Set<SessionFilter>) -> Unit,
) {
val checked = filter in filters
Row(
modifier = Modifier
.fillMaxWidth()
.clickable {
onCheck(!checked)
val newSessionFilters = if (checked) {
filters - filter
} else {
filters + filter
}
onFiltersChanged(newSessionFilters)
},
verticalAlignment = Alignment.CenterVertically,
) {
Expand Down Expand Up @@ -260,9 +245,7 @@ private fun AgendaFilterDrawerPreview() {
Room("", "Room 3"),
Room("", "Room 4")
),
sessionFilters = listOf(
SessionFilter(type = SessionFilter.FilterType.BOOKMARK, value = "")
),
sessionFilters = setOf(SessionFilter.Bookmark),
onFiltersChanged = {}
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ fun AgendaPager(
isRefreshing: Boolean,
onRefresh: () -> Unit,
initialPageIndex: Int,
filterList: List<SessionFilter>,
sessionFilters: Set<SessionFilter>,
onSessionClick: (UISession) -> Unit,
onApplyForAppClinicClick: () -> Unit,
onSessionBookmark: (UISession, Boolean) -> Unit
Expand Down Expand Up @@ -74,7 +74,7 @@ fun AgendaPager(
onRefresh = onRefresh,
state = pullRefreshState
) {
val sessions = days[page].sessions.filter(filterList)
val sessions = days[page].sessions.filter(sessionFilters)
if (sessions.isEmpty()) {
EmptyLayout()
} else {
Expand All @@ -96,46 +96,18 @@ fun AgendaPager(
// the algorithm is inspired by Inverted index
// time complexity is O(n * m) where n is the number of sessions and m is the number of filters
private fun List<UISession>.filter(
filterList: List<SessionFilter>
filters: Collection<SessionFilter>
): List<UISession> {
if (filterList.isEmpty()) {
if (filters.isEmpty()) {
return this
}

val sessionsByFilterType =
mutableMapOf<SessionFilter.FilterType, MutableList<UISession>>()
for (filter in filterList) {
if (!sessionsByFilterType.containsKey(filter.type)) {
sessionsByFilterType[filter.type] = mutableListOf()
}
}
for (session in this) {
for (filter in filterList) {
when (filter.type) {
SessionFilter.FilterType.BOOKMARK -> {
val bookmarked = session.isFavorite
if (bookmarked) {
sessionsByFilterType[filter.type]?.add(session)
}
}
val filtersByType = filters.groupBy { it::class }.values

SessionFilter.FilterType.LANGUAGE -> {
if (filter.value == session.language) {
sessionsByFilterType[filter.type]?.add(session)
}
}

SessionFilter.FilterType.ROOM -> {
if (filter.value == session.roomId) {
sessionsByFilterType[filter.type]?.add(session)
}
}
}
return filter { session ->
// Match if at least one filter of each type matches
filtersByType.all { filter ->
filter.any { it.matches(session) }
}
}

//get union join of all ScheduleSessions
val origin = sessionsByFilterType.values.flatten().toMutableSet()
sessionsByFilterType.values.forEach { origin.retainAll(it) }
return origin.sortedBy { it.startDate }
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import fr.androidmakers.domain.model.Room
import fr.androidmakers.domain.repo.BookmarksRepository
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
Expand All @@ -38,8 +39,8 @@ class AgendaViewModel(
}
}
) {
private val _sessionFilters = MutableStateFlow(emptyList<SessionFilter>())
val sessionFilters = _sessionFilters.asStateFlow()
private val _sessionFilters = MutableStateFlow(emptySet<SessionFilter>())
val sessionFilters: StateFlow<Set<SessionFilter>> = _sessionFilters.asStateFlow()

val rooms: Flow<List<Room>> = values.map { stateLce ->
when (stateLce) {
Expand All @@ -48,7 +49,7 @@ class AgendaViewModel(
}
}.distinctUntilChanged()

fun onFiltersChanged(newSessionFilters: List<SessionFilter>) {
fun onFiltersChanged(newSessionFilters: Set<SessionFilter>) {
_sessionFilters.value = newSessionFilters
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ package com.androidmakers.ui.common
object EmojiUtils {

fun getLanguageInEmoji(language: String?): String? {
return when (language?.lowercase()) {
"english" -> "\uD83C\uDDEC\uD83C\uDDE7"
"french" -> "\uD83C\uDDEB\uD83C\uDDF7"
return when {
language.equals("english", ignoreCase = true) -> "\uD83C\uDDEC\uD83C\uDDE7"
language.equals("french", ignoreCase = true) -> "\uD83C\uDDEB\uD83C\uDDF7"
else -> null
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,25 @@
package com.androidmakers.ui.common

data class SessionFilter(val type: FilterType, val value: Any) {
enum class FilterType {
BOOKMARK,
LANGUAGE,
ROOM
import com.androidmakers.ui.model.UISession

sealed interface SessionFilter {

fun matches(session: UISession): Boolean

data object Bookmark : SessionFilter {
override fun matches(session: UISession) = session.isFavorite
}

data class Language(val value: String) : SessionFilter {
override fun matches(session: UISession) = session.language == value

companion object {
const val FRENCH = "French"
const val ENGLISH = "English"
}
}

data class Room(val id: String) : SessionFilter {
override fun matches(session: UISession): Boolean = session.roomId == id
}
}
2 changes: 1 addition & 1 deletion shared/ui/src/commonMain/moko-resources/base/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<string name="language">Language</string>
<string name="room">Room</string>
<string name="rooms">Rooms</string>
<string name="empty_events">Sorry, there is nothing conference available for currently selected filters.</string>
<string name="empty_events">Sorry, there is no session available for the currently selected filters.</string>

<string name="english">English</string>
<string name="french">French</string>
Expand Down

0 comments on commit d9b4f65

Please sign in to comment.