Skip to content

Commit

Permalink
Allow for comparator to be updated in the SortedParticipantState (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
aleksandar-apostolov authored May 27, 2024
1 parent 168ddbf commit 581e34c
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ public final class io/getstream/video/android/core/CallState {
public final fun updateFromResponse (Lorg/openapitools/client/models/StopLiveResponse;)V
public final fun updateFromResponse (Lorg/openapitools/client/models/UpdateCallResponse;)V
public final fun updateParticipant (Lio/getstream/video/android/core/ParticipantState;)V
public final fun updateParticipantSortingOrder (Ljava/util/Comparator;)V
public final fun updateParticipantVisibility (Ljava/lang/String;Lio/getstream/video/android/core/model/VisibilityOnScreenState;)V
public final fun updateParticipantVisibilityFlow (Lkotlinx/coroutines/flow/Flow;)V
public final fun upsertParticipants (Ljava/util/List;)V
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -293,56 +293,12 @@ public class CallState(
val livestream: StateFlow<ParticipantState.Video?> = livestreamFlow.debounce(1000)
.stateIn(scope, SharingStarted.WhileSubscribed(10000L), null)

internal val sortedParticipantsFlow = channelFlow {
// uses a channel flow to handle concurrency and 3 things updating: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/channel-flow.html

fun emitSorted() {
val participants = participants.value
val pinned = _pinnedParticipants.value
var lastParticipants: List<ParticipantState>? = null
val sorted = participants.sortedWith(
compareBy(
{ pinned.containsKey(it.sessionId) },
{ it.screenSharingEnabled.value },
{ it.dominantSpeaker.value },
{ it.videoEnabled.value },
{ it.lastSpeakingAt.value },
{ it.joinedAt.value },
{ it.userId.value },
),
).reversed()
scope.launch {
if (lastParticipants != sorted) {
send(sorted)
lastParticipants = sorted
}
}
}

scope.launch {
_participants.collect {
emitSorted()
}
}
// Since participant state exposes it's own stateflows this is a little harder to do than usual
// we need to listen to the events and update the flow when it changes

// emit the sorted list
emitSorted()

// TODO: could optimize performance by subscribing only to relevant events
call.subscribe {
emitSorted()
}

scope.launch {
_pinnedParticipants.collect {
emitSorted()
}
}

awaitClose {}
}
private var _sortedParticipantsState = SortedParticipantsState(
scope,
call,
_participants,
_pinnedParticipants,
)

/**
* Sorted participants based on
Expand All @@ -355,12 +311,16 @@ public class CallState(
*
* Debounced 100ms to avoid rapid changes
*/
val sortedParticipants = SortedParticipantsState(
scope,
call,
_participants,
_pinnedParticipants,
).asFlow().debounce(100)
val sortedParticipants = _sortedParticipantsState.asFlow().debounce(100)

/**
* Update participant sorting order
*
* @param comparator a new comparator to be used in [sortedParticipants] flow.
*/
fun updateParticipantSortingOrder(
comparator: Comparator<ParticipantState>,
) = _sortedParticipantsState.updateComparator(comparator)

/** Members contains the list of users who are permanently associated with this call. This includes users who are currently not active in the call
* As an example if you invite "john", "bob" and "jane" to a call and only Jane joins.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,4 +136,11 @@ internal class SortedParticipantsState(
* Get last sorted participants.
*/
fun lastSortOrder() = lastSortOrder

/**
* Update the sorter with a new comparator.
*/
fun updateComparator(comparator: Comparator<ParticipantState>) {
this.comparator = comparator
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,35 @@ class CallStateTest : IntegrationTestBase() {
assertThat(sorted3).isEqualTo(listOf("1", "2", "3", "4", "5", "6"))
}

@Test
fun `Update sorting order`() = runTest {
val call = client.call("default", randomUUID())
val sortedParticipants = call.state.sortedParticipants.stateIn(
this,
SharingStarted.Eagerly,
emptyList(),
)
call.state.updateParticipantSortingOrder(
compareByDescending {
it.sessionId
},
)

call.state.updateParticipant(
ParticipantState("1", call, "1"),
)
call.state.updateParticipant(
ParticipantState("2", call, "2").apply { _screenSharingEnabled.value = true },
)
call.state.updateParticipant(
ParticipantState("3", call, "3").apply { _dominantSpeaker.value = true },
)

delay(1000)
val sorted = sortedParticipants.value.map { it.sessionId }
assertThat(sorted).isEqualTo(listOf("3", "2", "1"))
}

@Test
fun `Querying calls should populate the state`() = runTest {
// val createResult = client.call("default", randomUUID()).create(custom=mapOf("color" to "green"))
Expand Down

0 comments on commit 581e34c

Please sign in to comment.