Skip to content

Commit 70110b8

Browse files
committed
review: review fixes
1 parent 20b0e27 commit 70110b8

3 files changed

Lines changed: 63 additions & 42 deletions

File tree

plugins/plugin-konfeature/src/main/kotlin/com/redmadrobot/debug/plugin/konfeature/ui/KonfeatureScreen.kt

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import androidx.compose.foundation.layout.Column
77
import androidx.compose.foundation.layout.Row
88
import androidx.compose.foundation.layout.Spacer
99
import androidx.compose.foundation.layout.fillMaxWidth
10-
import androidx.compose.foundation.layout.height
1110
import androidx.compose.foundation.layout.padding
1211
import androidx.compose.foundation.lazy.LazyColumn
1312
import androidx.compose.material.Button
@@ -141,13 +140,11 @@ private fun KonfeatureHeader(
141140
.background(colorResource(id = CoreR.color.super_light_gray))
142141
.padding(horizontal = 16.dp)
143142
) {
144-
Spacer(modifier = Modifier.height(8.dp))
145143
KonfeatureSearchBar(
146144
query = searchQuery,
147145
onQueryChange = onSearchQueryChange,
148-
modifier = Modifier
146+
modifier = Modifier.padding(vertical = 8.dp)
149147
)
150-
Spacer(modifier = Modifier.height(8.dp))
151148
Row {
152149
Button(onClick = onRefreshClick) {
153150
Text(text = stringResource(id = R.string.konfeature_plugin_refresh))

plugins/plugin-konfeature/src/main/kotlin/com/redmadrobot/debug/plugin/konfeature/ui/KonfeatureViewModel.kt

Lines changed: 60 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@ import com.redmadrobot.konfeature.FeatureValueSpec
1212
import com.redmadrobot.konfeature.Konfeature
1313
import com.redmadrobot.konfeature.source.FeatureValueSource
1414
import kotlinx.coroutines.Dispatchers
15+
import kotlinx.coroutines.FlowPreview
1516
import kotlinx.coroutines.flow.Flow
1617
import kotlinx.coroutines.flow.MutableStateFlow
1718
import kotlinx.coroutines.flow.asStateFlow
19+
import kotlinx.coroutines.flow.debounce
1820
import kotlinx.coroutines.flow.launchIn
1921
import kotlinx.coroutines.flow.onEach
2022
import kotlinx.coroutines.flow.update
@@ -26,14 +28,13 @@ internal class KonfeatureViewModel(
2628
private val debugPanelInterceptor: KonfeatureDebugPanelInterceptor,
2729
) : PluginViewModel() {
2830
private val _state = MutableStateFlow(KonfeatureViewState())
31+
private val _searchQueryFlow = MutableStateFlow("")
2932

3033
val state: Flow<KonfeatureViewState> = _state.asStateFlow()
3134

3235
init {
33-
debugPanelInterceptor
34-
.valuesFlow
35-
.onEach { updateItems() }
36-
.launchIn(viewModelScope)
36+
observeKonfeatureValues()
37+
observeSearchQuery()
3738
}
3839

3940
fun onValueChanged(key: String, value: Any) {
@@ -70,14 +71,7 @@ internal class KonfeatureViewModel(
7071
}
7172

7273
fun onCollapseAllClick() {
73-
_state.update { state ->
74-
val collapsedConfigs = state.items
75-
.asSequence()
76-
.filterIsInstance(KonfeatureItem.Config::class.java)
77-
.map { it.name }
78-
.toSet()
79-
state.copy(collapsedConfigs = collapsedConfigs)
80-
}
74+
_state.update { state -> state.copy(collapsedConfigs = state.configs.keys) }
8175
}
8276

8377
fun onEditClick(key: String, value: Any, isDebugSource: Boolean) {
@@ -89,33 +83,57 @@ internal class KonfeatureViewModel(
8983
}
9084

9185
fun onSearchQueryChanged(query: String) {
92-
_state.update { state ->
93-
val filteredItems = filterItems(state.items, query)
94-
state.copy(searchQuery = query, filteredItems = filteredItems)
95-
}
86+
_state.update { state -> state.copy(searchQuery = query) }
87+
_searchQueryFlow.value = query
88+
}
89+
90+
private fun observeKonfeatureValues() {
91+
debugPanelInterceptor.valuesFlow
92+
.onEach { updateItems() }
93+
.launchIn(viewModelScope)
94+
}
95+
96+
@OptIn(FlowPreview::class)
97+
private fun observeSearchQuery() {
98+
_searchQueryFlow
99+
.debounce(timeoutMillis = 500L)
100+
.onEach { query ->
101+
val values = _state.value.values
102+
val configs = _state.value.configs
103+
val filteredItems = filterItems(configs, values, query)
104+
_state.update { state -> state.copy(filteredItems = filteredItems) }
105+
}
106+
.launchIn(viewModelScope)
96107
}
97108

98109
private suspend fun updateItems() {
99-
val items = withContext(Dispatchers.IO) { getItems(konfeature) }
110+
val (configs, values) = withContext(Dispatchers.IO) { getItems(konfeature) }
111+
val searchQuery = _searchQueryFlow.value
112+
val filteredItems = filterItems(configs, values, searchQuery)
113+
100114
_state.update { state ->
101-
val filteredItems = filterItems(items, state.searchQuery)
102-
state.copy(items = items, filteredItems = filteredItems)
115+
state.copy(configs = configs, values = values, filteredItems = filteredItems)
103116
}
104117
}
105118

106-
private fun getItems(konfeature: Konfeature): List<KonfeatureItem> {
107-
return konfeature.spec.fold(mutableListOf<KonfeatureItem>()) { acc, configSpec ->
119+
private fun getItems(konfeature: Konfeature): Pair<Map<String, KonfeatureItem.Config>, List<KonfeatureItem.Value>> {
120+
val configs = mutableMapOf<String, KonfeatureItem.Config>()
121+
val values = mutableListOf<KonfeatureItem.Value>()
122+
123+
konfeature.spec.fold(configs to values) { acc, configSpec ->
108124
acc.apply {
109-
add(createConfigItem(configSpec))
110-
addAll(configSpec.values.map { valueSpec ->
125+
configs[configSpec.name] = createConfigItem(configSpec)
126+
configSpec.values.mapTo(values) { valueSpec ->
111127
createConfigValueItem(
112128
configName = configSpec.name,
113129
valueSpec = valueSpec,
114130
konfeature = konfeature
115131
)
116-
})
132+
}
117133
}
118134
}
135+
136+
return configs to values
119137
}
120138

121139
private fun createConfigItem(config: FeatureConfigSpec): KonfeatureItem.Config {
@@ -162,19 +180,24 @@ internal class KonfeatureViewModel(
162180
}
163181
}
164182

165-
private fun filterItems(items: List<KonfeatureItem>, query: String): List<KonfeatureItem> {
166-
if (query.isBlank()) return items
167-
168-
val formattedQuery = query.lowercase()
169-
val matchingItems = items
170-
.filterIsInstance<KonfeatureItem.Value>()
171-
.filter { it.key.lowercase().contains(formattedQuery) }
172-
val matchingConfigNames = matchingItems.map { it.configName }.toSet()
173-
174-
return items.filter { item ->
175-
when (item) {
176-
is KonfeatureItem.Config -> item.name in matchingConfigNames
177-
is KonfeatureItem.Value -> item.key.lowercase().contains(formattedQuery)
183+
private suspend fun filterItems(
184+
configs: Map<String, KonfeatureItem.Config>,
185+
values: List<KonfeatureItem.Value>,
186+
query: String
187+
): List<KonfeatureItem> {
188+
return withContext(Dispatchers.Default) {
189+
buildList {
190+
var previousValue: KonfeatureItem.Value? = null
191+
192+
for (value in values) {
193+
if (value.key.contains(query, ignoreCase = true)) {
194+
if (previousValue?.configName != value.configName) {
195+
configs[value.configName]?.let { config -> add(config) }
196+
}
197+
add(value)
198+
previousValue = value
199+
}
200+
}
178201
}
179202
}
180203
}

plugins/plugin-konfeature/src/main/kotlin/com/redmadrobot/debug/plugin/konfeature/ui/data/KonfeatureViewState.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ package com.redmadrobot.debug.plugin.konfeature.ui.data
33
internal data class KonfeatureViewState(
44
val searchQuery: String = "",
55
val collapsedConfigs: Set<String> = emptySet(),
6-
val items: List<KonfeatureItem> = emptyList(),
6+
val configs: Map<String, KonfeatureItem.Config> = emptyMap(),
7+
val values: List<KonfeatureItem.Value> = emptyList(),
78
val filteredItems: List<KonfeatureItem> = emptyList(),
89
val editDialogState: EditDialogState? = null
910
) {

0 commit comments

Comments
 (0)