Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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
20 changes: 20 additions & 0 deletions stream-chat-android-compose/api/stream-chat-android-compose.api
Original file line number Diff line number Diff line change
Expand Up @@ -7015,6 +7015,14 @@ public final class io/getstream/chat/android/compose/viewmodel/channels/ChannelL
public fun <init> (Lio/getstream/chat/android/client/ChatClient;Lio/getstream/chat/android/models/querysort/QuerySorter;Lio/getstream/chat/android/models/FilterObject;ILjava/lang/Integer;Ljava/lang/Integer;Lio/getstream/chat/android/client/api/event/ChatEventHandlerFactory;Z)V
public fun <init> (Lio/getstream/chat/android/client/ChatClient;Lio/getstream/chat/android/models/querysort/QuerySorter;Lio/getstream/chat/android/models/FilterObject;ILjava/lang/Integer;Ljava/lang/Integer;Lio/getstream/chat/android/client/api/event/ChatEventHandlerFactory;ZLio/getstream/chat/android/models/querysort/QuerySorter;)V
public synthetic fun <init> (Lio/getstream/chat/android/client/ChatClient;Lio/getstream/chat/android/models/querysort/QuerySorter;Lio/getstream/chat/android/models/FilterObject;ILjava/lang/Integer;Ljava/lang/Integer;Lio/getstream/chat/android/client/api/event/ChatEventHandlerFactory;ZLio/getstream/chat/android/models/querysort/QuerySorter;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (Lio/getstream/chat/android/client/ChatClient;Lio/getstream/chat/android/models/querysort/QuerySorter;Lkotlin/jvm/functions/Function1;)V
public fun <init> (Lio/getstream/chat/android/client/ChatClient;Lio/getstream/chat/android/models/querysort/QuerySorter;Lkotlin/jvm/functions/Function1;I)V
public fun <init> (Lio/getstream/chat/android/client/ChatClient;Lio/getstream/chat/android/models/querysort/QuerySorter;Lkotlin/jvm/functions/Function1;ILjava/lang/Integer;)V
public fun <init> (Lio/getstream/chat/android/client/ChatClient;Lio/getstream/chat/android/models/querysort/QuerySorter;Lkotlin/jvm/functions/Function1;ILjava/lang/Integer;Ljava/lang/Integer;)V
public fun <init> (Lio/getstream/chat/android/client/ChatClient;Lio/getstream/chat/android/models/querysort/QuerySorter;Lkotlin/jvm/functions/Function1;ILjava/lang/Integer;Ljava/lang/Integer;Lio/getstream/chat/android/client/api/event/ChatEventHandlerFactory;)V
public fun <init> (Lio/getstream/chat/android/client/ChatClient;Lio/getstream/chat/android/models/querysort/QuerySorter;Lkotlin/jvm/functions/Function1;ILjava/lang/Integer;Ljava/lang/Integer;Lio/getstream/chat/android/client/api/event/ChatEventHandlerFactory;Z)V
public fun <init> (Lio/getstream/chat/android/client/ChatClient;Lio/getstream/chat/android/models/querysort/QuerySorter;Lkotlin/jvm/functions/Function1;ILjava/lang/Integer;Ljava/lang/Integer;Lio/getstream/chat/android/client/api/event/ChatEventHandlerFactory;ZLio/getstream/chat/android/models/querysort/QuerySorter;)V
public synthetic fun <init> (Lio/getstream/chat/android/client/ChatClient;Lio/getstream/chat/android/models/querysort/QuerySorter;Lkotlin/jvm/functions/Function1;ILjava/lang/Integer;Ljava/lang/Integer;Lio/getstream/chat/android/client/api/event/ChatEventHandlerFactory;ZLio/getstream/chat/android/models/querysort/QuerySorter;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (Lio/getstream/chat/android/client/ChatClient;Ljava/lang/String;)V
public fun <init> (Lio/getstream/chat/android/client/ChatClient;Ljava/lang/String;Ljava/util/Map;)V
public fun <init> (Lio/getstream/chat/android/client/ChatClient;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;)V
Expand All @@ -7025,9 +7033,21 @@ public final class io/getstream/chat/android/compose/viewmodel/channels/ChannelL
public fun <init> (Lio/getstream/chat/android/client/ChatClient;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;ILjava/lang/Integer;Ljava/lang/Integer;Lio/getstream/chat/android/client/api/event/ChatEventHandlerFactory;Z)V
public fun <init> (Lio/getstream/chat/android/client/ChatClient;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;ILjava/lang/Integer;Ljava/lang/Integer;Lio/getstream/chat/android/client/api/event/ChatEventHandlerFactory;ZLio/getstream/chat/android/models/querysort/QuerySorter;)V
public synthetic fun <init> (Lio/getstream/chat/android/client/ChatClient;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;ILjava/lang/Integer;Ljava/lang/Integer;Lio/getstream/chat/android/client/api/event/ChatEventHandlerFactory;ZLio/getstream/chat/android/models/querysort/QuerySorter;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (Lio/getstream/chat/android/client/ChatClient;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V
public fun <init> (Lio/getstream/chat/android/client/ChatClient;Ljava/lang/String;Lkotlin/jvm/functions/Function1;Ljava/util/Map;)V
public fun <init> (Lio/getstream/chat/android/client/ChatClient;Ljava/lang/String;Lkotlin/jvm/functions/Function1;Ljava/util/Map;I)V
public fun <init> (Lio/getstream/chat/android/client/ChatClient;Ljava/lang/String;Lkotlin/jvm/functions/Function1;Ljava/util/Map;ILjava/lang/Integer;)V
public fun <init> (Lio/getstream/chat/android/client/ChatClient;Ljava/lang/String;Lkotlin/jvm/functions/Function1;Ljava/util/Map;ILjava/lang/Integer;Ljava/lang/Integer;)V
public fun <init> (Lio/getstream/chat/android/client/ChatClient;Ljava/lang/String;Lkotlin/jvm/functions/Function1;Ljava/util/Map;ILjava/lang/Integer;Ljava/lang/Integer;Lio/getstream/chat/android/client/api/event/ChatEventHandlerFactory;)V
public fun <init> (Lio/getstream/chat/android/client/ChatClient;Ljava/lang/String;Lkotlin/jvm/functions/Function1;Ljava/util/Map;ILjava/lang/Integer;Ljava/lang/Integer;Lio/getstream/chat/android/client/api/event/ChatEventHandlerFactory;Z)V
public fun <init> (Lio/getstream/chat/android/client/ChatClient;Ljava/lang/String;Lkotlin/jvm/functions/Function1;Ljava/util/Map;ILjava/lang/Integer;Ljava/lang/Integer;Lio/getstream/chat/android/client/api/event/ChatEventHandlerFactory;ZLio/getstream/chat/android/models/querysort/QuerySorter;)V
public synthetic fun <init> (Lio/getstream/chat/android/client/ChatClient;Ljava/lang/String;Lkotlin/jvm/functions/Function1;Ljava/util/Map;ILjava/lang/Integer;Ljava/lang/Integer;Lio/getstream/chat/android/client/api/event/ChatEventHandlerFactory;ZLio/getstream/chat/android/models/querysort/QuerySorter;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (Lio/getstream/chat/android/client/ChatClient;Lkotlin/jvm/functions/Function1;)V
public fun <init> (Ljava/lang/String;)V
public fun <init> (Ljava/lang/String;Lio/getstream/chat/android/client/ChatClient;ZLio/getstream/chat/android/models/querysort/QuerySorter;)V
public synthetic fun <init> (Ljava/lang/String;Lio/getstream/chat/android/client/ChatClient;ZLio/getstream/chat/android/models/querysort/QuerySorter;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V
public fun <init> (Lkotlin/jvm/functions/Function1;)V
public fun create (Ljava/lang/Class;)Landroidx/lifecycle/ViewModel;
public fun create (Ljava/lang/Class;Landroidx/lifecycle/viewmodel/CreationExtras;)Landroidx/lifecycle/ViewModel;
public fun create (Lkotlin/reflect/KClass;Landroidx/lifecycle/viewmodel/CreationExtras;)Landroidx/lifecycle/ViewModel;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,12 +125,14 @@ public class ChannelListViewModel internal constructor(
data class Standard(
val initialFilter: FilterObject?,
val initialSort: QuerySorter<Channel>,
val filterForUser: ((User) -> FilterObject)? = null,
) : QueryMode

data class Predefined(
val name: String,
val filterValues: Map<String, Any>?,
val sortValues: Map<String, Any>?,
val filterValuesForUser: ((User) -> Map<String, Any>)? = null,
) : QueryMode

data class Grouped(val groupKey: String) : QueryMode
Expand Down Expand Up @@ -425,6 +427,13 @@ public class ChannelListViewModel internal constructor(
*/
private var isFilterSetByApp = false

/**
* Builds the filter for the connected user: the app's, or the default one when no filter was given.
*/
private val userFilter: ((User) -> FilterObject)? = (mode as? QueryMode.Standard)?.let { standard ->
standard.filterForUser ?: DEFAULT_USER_FILTER.takeIf { standard.initialFilter == null }
}

/**
* Emits the effective query input to react to. Standard mode reacts to filter/sort changes
* (via [queryConfigFlow]) in addition to search and refresh; Predefined and Grouped modes
Expand All @@ -443,10 +452,10 @@ public class ChannelListViewModel internal constructor(
* Combines the latest search query and filter to fetch channels and emit them to the UI.
*/
init {
if (mode is QueryMode.Standard && mode.initialFilter == null) {
userFilter?.let { buildFilter ->
viewModelScope.launch {
val filter = defaultChannelsFilter().first()
if (!isFilterSetByApp) this@ChannelListViewModel.filterFlow.value = filter
val user = chatClient.clientState.user.filterNotNull().first()
if (!isFilterSetByApp) this@ChannelListViewModel.filterFlow.value = buildFilter(user)
}
}

Expand All @@ -459,9 +468,8 @@ public class ChannelListViewModel internal constructor(
clearUserState()
// Reload once the next user is ready; their queries and searches are built from scratch.
chatClient.clientState.initializationState.first { it == InitializationState.COMPLETE }
if (followsDefaultFilter()) {
// The default filter is built from the current user.
filterFlow.value = defaultChannelsFilter().first()
userFilter.takeUnless { isFilterSetByApp }?.let { buildFilter ->
chatClient.clientState.user.value?.let { filterFlow.value = buildFilter(it) }
}
refresh()
}
Expand Down Expand Up @@ -955,12 +963,6 @@ public class ChannelListViewModel internal constructor(
)
}

/**
* Whether the filter is the default one, built from the current user, rather than one the app provided.
*/
private fun followsDefaultFilter(): Boolean =
mode is QueryMode.Standard && mode.initialFilter == null && !isFilterSetByApp

/**
* Drops the channels, search results and selection loaded for the previous user, and stops their queries.
*/
Expand Down Expand Up @@ -1040,9 +1042,9 @@ public class ChannelListViewModel internal constructor(
}

/**
* Builds a [QueryChannelsRequest] for the current [mode] and [searchQuery]. Returns `null` in Standard
* mode when the filter has not yet been resolved (e.g. before [buildDefaultFilter] completes); in that
* case the caller should skip the request — the next emission of [filterFlow] will re-trigger.
* Builds a [QueryChannelsRequest] for the current [mode] and [searchQuery]. Returns `null` when the filter
* or filter values depend on a user and none is connected yet; in that case the caller should skip the
* request — the next emission of [filterFlow], or the reload once a user connects, will re-trigger.
*
* In Predefined mode with an active channel search, falls back to a Standard request whose filter is
* just [searchChannelFilter] (the predefined filter is server-owned and cannot be combined locally).
Expand All @@ -1066,9 +1068,13 @@ public class ChannelListViewModel internal constructor(
memberLimit = memberLimit,
)
} else {
val filterValues = when (val buildFilterValues = mode.filterValuesForUser) {
null -> mode.filterValues
else -> buildFilterValues(user.value ?: return null)
}
QueryChannelsRequest(
predefinedFilter = mode.name,
filterValues = mode.filterValues,
filterValues = filterValues,
sortValues = mode.sortValues,
limit = channelLimit,
messageLimit = messageLimit,
Expand Down Expand Up @@ -1262,12 +1268,6 @@ public class ChannelListViewModel internal constructor(
members.any { it.user.id != currentUser?.id && it.user.id in mutedUserIds }
}

/**
* Builds the default channel filter, which represents "messaging" channels that the current user is a part of.
*/
private fun defaultChannelsFilter(): Flow<FilterObject> =
chatClient.clientState.user.map(Filters::defaultChannelListFilter).filterNotNull()

@Deprecated(
message = "Avoid using this search query as `member.user.name` is an expensive operation. " +
"In the future, we should migrate to use optimizedChannelSearchFilter.",
Expand Down Expand Up @@ -1299,6 +1299,10 @@ public class ChannelListViewModel internal constructor(
}

internal companion object {
private val DEFAULT_USER_FILTER: (User) -> FilterObject = { user ->
checkNotNull(Filters.defaultChannelListFilter(user))
}

/**
* Default value of number of channels to return when querying channels.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import io.getstream.chat.android.compose.viewmodel.channels.ChannelListViewModel
import io.getstream.chat.android.models.Channel
import io.getstream.chat.android.models.FilterObject
import io.getstream.chat.android.models.Message
import io.getstream.chat.android.models.User
import io.getstream.chat.android.models.querysort.QuerySortByField
import io.getstream.chat.android.models.querysort.QuerySorter

Expand All @@ -35,9 +36,9 @@ import io.getstream.chat.android.models.querysort.QuerySorter
* It currently provides the [ChannelListViewModel] using those dependencies.
*
* A [ChannelListViewModel] serves one user at a time: when the user disconnects or another user connects, it drops
* the loaded channels and reloads once the next user is connected. The default filter follows the connected user,
* but filters and filter values that contain a user id don't, so a different user needs a new factory and view model,
* for example keyed by the user id.
* the loaded channels and reloads once the next user is connected. The default filter, and filters or filter values
* built from the user, follow the connected user. A fixed filter or filter values that contain a user id apply to
* that user only.
*
* @param chatClient The client used to fetch data.
* @param channelLimit How many channels we fetch per page.
Expand Down Expand Up @@ -90,6 +91,35 @@ public class ChannelListViewModelFactory internal constructor(
messageSearchSort = messageSearchSort,
)

/**
* Builds a factory for a [ChannelListViewModel] that queries channels by a filter built from the connected user.
*
* @param querySort The sorting order for channels.
* @param filters Builds the filter for the connected user, on the main thread. It's called again when another
* user connects.
*/
@JvmOverloads
public constructor(
chatClient: ChatClient = ChatClient.instance(),
querySort: QuerySorter<Channel> = QuerySortByField.descByName("last_updated"),
filters: (User) -> FilterObject,
channelLimit: Int = ChannelListViewModel.DEFAULT_CHANNEL_LIMIT,
memberLimit: Int? = null,
messageLimit: Int? = null,
chatEventHandlerFactory: ChatEventHandlerFactory = ChatEventHandlerFactory(chatClient.clientState),
draftMessagesEnabled: Boolean = true,
messageSearchSort: QuerySorter<Message>? = null,
) : this(
chatClient = chatClient,
mode = QueryMode.Standard(initialFilter = null, initialSort = querySort, filterForUser = filters),
channelLimit = channelLimit,
memberLimit = memberLimit,
messageLimit = messageLimit,
chatEventHandlerFactory = chatEventHandlerFactory,
draftMessagesEnabled = draftMessagesEnabled,
messageSearchSort = messageSearchSort,
)

/**
* Builds a factory for a [ChannelListViewModel] that queries channels using a predefined filter
* resolved by the server.
Expand Down Expand Up @@ -125,6 +155,43 @@ public class ChannelListViewModelFactory internal constructor(
messageSearchSort = messageSearchSort,
)

/**
* Builds a factory for a [ChannelListViewModel] that queries channels using a predefined filter
* resolved by the server, with filter values built from the connected user.
*
* @param predefinedFilterName The name of the predefined filter registered on the backend.
* @param filterValues Builds the values interpolated into the predefined filter template for the connected
* user, on the main thread. It's called for every request, so another user gets their own values.
* @param sortValues Optional values interpolated into the predefined sort template.
*/
@JvmOverloads
public constructor(
chatClient: ChatClient = ChatClient.instance(),
predefinedFilterName: String,
filterValues: (User) -> Map<String, Any>,
sortValues: Map<String, Any>? = null,
channelLimit: Int = ChannelListViewModel.DEFAULT_CHANNEL_LIMIT,
memberLimit: Int? = null,
messageLimit: Int? = null,
chatEventHandlerFactory: ChatEventHandlerFactory = ChatEventHandlerFactory(chatClient.clientState),
draftMessagesEnabled: Boolean = true,
messageSearchSort: QuerySorter<Message>? = null,
) : this(
chatClient = chatClient,
mode = QueryMode.Predefined(
name = predefinedFilterName,
filterValues = null,
sortValues = sortValues,
filterValuesForUser = filterValues,
),
channelLimit = channelLimit,
memberLimit = memberLimit,
messageLimit = messageLimit,
chatEventHandlerFactory = chatEventHandlerFactory,
draftMessagesEnabled = draftMessagesEnabled,
messageSearchSort = messageSearchSort,
)

/**
* Grouped [ChannelListViewModel] factory. Wires the ViewModel to the state identified by
* [groupKey] without firing a remote call; `queryGroupedChannels` responses populate it.
Expand Down
Loading
Loading