diff --git a/instantsearch-core/src/commonMain/kotlin/com/algolia/instantsearch/core/subscription/SubscriptionValue.kt b/instantsearch-core/src/commonMain/kotlin/com/algolia/instantsearch/core/subscription/SubscriptionValue.kt index 2f1bfe753..aeb037b2b 100644 --- a/instantsearch-core/src/commonMain/kotlin/com/algolia/instantsearch/core/subscription/SubscriptionValue.kt +++ b/instantsearch-core/src/commonMain/kotlin/com/algolia/instantsearch/core/subscription/SubscriptionValue.kt @@ -1,5 +1,6 @@ package com.algolia.instantsearch.core.subscription +import com.algolia.instantsearch.core.subscription.internal.SubscriptionOnce import kotlin.properties.Delegates public class SubscriptionValue(initialValue: T) : Subscription() { @@ -13,6 +14,10 @@ public class SubscriptionValue(initialValue: T) : Subscription() { subscriptions += subscription } + public fun subscribePastOnce(skipNull: Boolean = true, subscription: (T) -> Unit) { + subscriptions += SubscriptionOnce(this, skipNull, subscription) + } + public fun notifySubscriptions() { notifyAll(value) } diff --git a/instantsearch-core/src/commonMain/kotlin/com/algolia/instantsearch/core/subscription/internal/SubscriptionOnce.kt b/instantsearch-core/src/commonMain/kotlin/com/algolia/instantsearch/core/subscription/internal/SubscriptionOnce.kt new file mode 100644 index 000000000..a9d0bfa25 --- /dev/null +++ b/instantsearch-core/src/commonMain/kotlin/com/algolia/instantsearch/core/subscription/internal/SubscriptionOnce.kt @@ -0,0 +1,20 @@ +package com.algolia.instantsearch.core.subscription.internal + +import com.algolia.instantsearch.core.subscription.Subscription + +internal class SubscriptionOnce( + private val subscription: Subscription, + private val skipNull: Boolean, + private val call: (T) -> Unit +) : (T) -> Unit { + + override fun invoke(value: T) { + if (value == null && skipNull) return + execute(value) + } + + private fun execute(value: T) { + subscription.unsubscribe(this) + call(value) + } +} diff --git a/instantsearch/src/commonMain/kotlin/com/algolia/instantsearch/filter/range/FilterRangeConnector.kt b/instantsearch/src/commonMain/kotlin/com/algolia/instantsearch/filter/range/FilterRangeConnector.kt index 18da8f506..e9f8c90d1 100644 --- a/instantsearch/src/commonMain/kotlin/com/algolia/instantsearch/filter/range/FilterRangeConnector.kt +++ b/instantsearch/src/commonMain/kotlin/com/algolia/instantsearch/filter/range/FilterRangeConnector.kt @@ -26,6 +26,15 @@ public data class FilterRangeConnector( ) : AbstractConnection() where T : Number, T : Comparable { /** + * ``` + * | Bounds/Range | connectSearcher | Behavior | + * |--------------|-----------------|----------------------------------------------------------------------------------------------------------------| + * | Yes | Yes | The bounds retrieved from the first search operation, the range will match the value set using the constructor | + * | No | Yes | The bounds retrieved from the first search operation, the range will match the bounds | + * | Yes | No | The bounds/range from the constructor are used | + * | No | No | Undefined behavior | + * ``` + * * @param filterState the FilterState that will hold your filters * @param attribute the attribute to filter * @param bounds the limits of the acceptable range within which values will be coerced diff --git a/instantsearch/src/commonMain/kotlin/com/algolia/instantsearch/filter/range/internal/FilterRangeConnectionFilterState.kt b/instantsearch/src/commonMain/kotlin/com/algolia/instantsearch/filter/range/internal/FilterRangeConnectionFilterState.kt index e07d20065..f1b9405c7 100644 --- a/instantsearch/src/commonMain/kotlin/com/algolia/instantsearch/filter/range/internal/FilterRangeConnectionFilterState.kt +++ b/instantsearch/src/commonMain/kotlin/com/algolia/instantsearch/filter/range/internal/FilterRangeConnectionFilterState.kt @@ -26,7 +26,9 @@ internal data class FilterRangeConnectionFilterState( .filterIsInstance() .firstOrNull() - viewModel.range.value = if (filter != null) Range(filter.lowerBound as T, filter.upperBound as T) else null + if (filter != null) { // avoid default range override to null + viewModel.range.value = Range(filter.lowerBound as T, filter.upperBound as T) + } } private val updateFilterState: Callback?> = { range -> filterState.notify { diff --git a/instantsearch/src/commonMain/kotlin/com/algolia/instantsearch/filter/range/internal/FilterRangeConnectionSearcherImpl.kt b/instantsearch/src/commonMain/kotlin/com/algolia/instantsearch/filter/range/internal/FilterRangeConnectionSearcherImpl.kt index 27e53e9a7..fa3992869 100644 --- a/instantsearch/src/commonMain/kotlin/com/algolia/instantsearch/filter/range/internal/FilterRangeConnectionSearcherImpl.kt +++ b/instantsearch/src/commonMain/kotlin/com/algolia/instantsearch/filter/range/internal/FilterRangeConnectionSearcherImpl.kt @@ -38,17 +38,19 @@ internal class FilterRangeConnectionSearcherImpl( val max = mapper(it.max) Range(min, max) } + if (range.value == null) { // if no range is specified, match the bounds. + range.value = bounds.value + } } override fun connect() { super.connect() searcher.query.updateQueryFacets(attribute) - searcher.response.subscribePast(responseSubscription) + searcher.response.subscribePastOnce(subscription = responseSubscription) } private fun CommonSearchParameters.updateQueryFacets(attribute: Attribute) { - val current = facets?.toMutableSet() ?: mutableSetOf() - facets = if (!current.contains(attribute)) current + attribute else setOf(attribute) + facets = (facets?.toMutableSet() ?: mutableSetOf()).apply { add(attribute) } } override fun disconnect() {