mirror of
https://github.com/openflocon/Flocon.git
synced 2026-06-24 00:49:11 +00:00
refact: [NETWORK] filter from data (#297)
Co-authored-by: Florent Champigny <florent@bere.al>
This commit is contained in:
parent
ce19c49d95
commit
57cc3e9711
14 changed files with 133 additions and 175 deletions
|
|
@ -13,6 +13,8 @@ import io.github.openflocon.domain.network.models.BadQualityConfigDomainModel
|
|||
import io.github.openflocon.domain.network.models.FloconNetworkCallDomainModel
|
||||
import io.github.openflocon.domain.network.models.MockNetworkDomainModel
|
||||
import io.github.openflocon.domain.network.models.NetworkFilterDomainModel
|
||||
import io.github.openflocon.domain.network.models.NetworkFilterDomainModel.Filters
|
||||
import io.github.openflocon.domain.network.models.NetworkSortDomainModel
|
||||
import io.github.openflocon.domain.network.models.NetworkTextFilterColumns
|
||||
import io.github.openflocon.domain.network.usecase.DecodeJwtTokenUseCase
|
||||
import io.github.openflocon.domain.network.usecase.ExportNetworkCallsToCsvUseCase
|
||||
|
|
@ -118,17 +120,20 @@ class NetworkViewModel(
|
|||
.flowOn(dispatcherProvider.viewModel)
|
||||
.stateIn(viewModelScope, started = SharingStarted.WhileSubscribed(5_000), null)
|
||||
|
||||
private val filter = combines(
|
||||
snapshotFlow { _filterText.value }.map { it.takeIf { it.isNotBlank() } },
|
||||
headerDelegate.textFiltersState.map { it.toDomain() }
|
||||
).map { (textFilters, filterOnAllColumns) ->
|
||||
NetworkFilterDomainModel(
|
||||
filterOnAllColumns = textFilters,
|
||||
filters = filterOnAllColumns,
|
||||
)
|
||||
}
|
||||
|
||||
private val sortAndFilter = combines(
|
||||
headerDelegate.sorted.map { it?.toDomain() }.distinctUntilChanged(),
|
||||
snapshotFlow { _filterText.value }
|
||||
.map { it.takeIf { it.isNotBlank() } }
|
||||
.map {
|
||||
NetworkFilterDomainModel(
|
||||
filterOnAllColumns = it
|
||||
)
|
||||
}
|
||||
.distinctUntilChanged()
|
||||
)
|
||||
filter,
|
||||
).distinctUntilChanged()
|
||||
|
||||
private val networkItems: Flow<List<FloconNetworkCallDomainModel>> =
|
||||
sortAndFilter.flatMapLatest { (sorted, filter) ->
|
||||
|
|
@ -171,14 +176,11 @@ class NetworkViewModel(
|
|||
|
||||
private val filteredItems: Flow<List<NetworkItemViewState>> = combine(
|
||||
items,
|
||||
contentState,
|
||||
filterConfig,
|
||||
) { items, content, config ->
|
||||
) { items, config ->
|
||||
filterNetworkItemsProcessor(
|
||||
items = items,
|
||||
filterState = config.filterState,
|
||||
allowedMethods = config.allowedMethods,
|
||||
textFilters = config.textFilters,
|
||||
)
|
||||
}
|
||||
.flowOn(dispatcherProvider.viewModel.limitedParallelism(1))
|
||||
|
|
@ -438,3 +440,35 @@ class NetworkViewModel(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Map<NetworkTextFilterColumns, TextFilterStateUiModel>.toDomain(): List<Filters>? {
|
||||
return buildList {
|
||||
this@toDomain.forEach { (column, filter) ->
|
||||
if (filter.isEnabled) {
|
||||
val includedFilters = filter.includedFilters.mapNotNull {
|
||||
it.toDomain()
|
||||
}
|
||||
val excludedFilters = filter.excludedFilters.mapNotNull {
|
||||
it.toDomain()
|
||||
}
|
||||
if (includedFilters.isNotEmpty() || excludedFilters.isNotEmpty()) {
|
||||
add(
|
||||
Filters(
|
||||
column = column,
|
||||
includedFilters = includedFilters,
|
||||
excludedFilters = excludedFilters,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun TextFilterStateUiModel.FilterItem.toDomain(): NetworkFilterDomainModel.Filters.FilterItem? {
|
||||
return if(isActive) {
|
||||
NetworkFilterDomainModel.Filters.FilterItem(
|
||||
text = text,
|
||||
)
|
||||
} else null
|
||||
}
|
||||
|
|
|
|||
|
|
@ -206,7 +206,6 @@ private fun TextFilterStateUiModel.performAction(
|
|||
text = action.text,
|
||||
isActive = true,
|
||||
isExcluded = true,
|
||||
isRegex = action.isRegex,
|
||||
)
|
||||
val exists = excludedFilters.any { it.text == newItem.text }
|
||||
if (exists) {
|
||||
|
|
@ -227,7 +226,6 @@ private fun TextFilterStateUiModel.performAction(
|
|||
text = action.text,
|
||||
isActive = true,
|
||||
isExcluded = false,
|
||||
isRegex = action.isRegex,
|
||||
)
|
||||
val exists = includedFilters.any { it.text == newItem.text }
|
||||
if (exists) {
|
||||
|
|
|
|||
|
|
@ -22,14 +22,12 @@ fun itemToDomain(item: TextFilterStateUiModel.FilterItem): TextFilterStateDomain
|
|||
text = item.text,
|
||||
isActive = item.isActive,
|
||||
isExcluded = item.isExcluded,
|
||||
isRegex = item.isRegex,
|
||||
)
|
||||
|
||||
fun itemToUI(item: TextFilterStateDomainModel.FilterItem): TextFilterStateUiModel.FilterItem = TextFilterStateUiModel.FilterItem(
|
||||
text = item.text,
|
||||
isActive = item.isActive,
|
||||
isExcluded = item.isExcluded,
|
||||
isRegex = item.isRegex,
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ package io.github.openflocon.flocondesktop.features.network.list.model.header
|
|||
import io.github.openflocon.flocondesktop.features.network.list.model.header.columns.base.filter.TextFilterStateUiModel
|
||||
|
||||
sealed interface TextFilterAction {
|
||||
data class Include(val text: String, val isRegex: Boolean) : TextFilterAction
|
||||
data class Exclude(val text: String, val isRegex: Boolean) : TextFilterAction
|
||||
data class Include(val text: String) : TextFilterAction
|
||||
data class Exclude(val text: String) : TextFilterAction
|
||||
data class SetIsActive(val item: TextFilterStateUiModel.FilterItem, val isActive: Boolean) : TextFilterAction
|
||||
data class Delete(val item: TextFilterStateUiModel.FilterItem) : TextFilterAction
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ data class TextFilterStateUiModel(
|
|||
val text: String,
|
||||
val isActive: Boolean,
|
||||
val isExcluded: Boolean,
|
||||
val isRegex: Boolean,
|
||||
)
|
||||
|
||||
override val isActive: Boolean = allFilters.isNotEmpty() && isEnabled && allFilters.any { it.isActive }
|
||||
|
|
@ -34,11 +33,11 @@ data class TextFilterStateUiModel(
|
|||
fun previewTextFilterState() = TextFilterStateUiModel(
|
||||
isEnabled = true,
|
||||
includedFilters = listOf(
|
||||
FilterItem(text = "toInclude", isExcluded = false, isActive = true, isRegex = false),
|
||||
FilterItem(text = "toInclude2", isExcluded = false, isActive = true, isRegex = true),
|
||||
FilterItem(text = "toInclude", isExcluded = false, isActive = true),
|
||||
FilterItem(text = "toInclude2", isExcluded = false, isActive = true),
|
||||
),
|
||||
excludedFilters = listOf(
|
||||
FilterItem(text = "toExclude", isExcluded = true, isActive = true, isRegex = false),
|
||||
FilterItem(text = "toExclude2", isExcluded = true, isActive = false, isRegex = true),
|
||||
FilterItem(text = "toExclude", isExcluded = true, isActive = true),
|
||||
FilterItem(text = "toExclude2", isExcluded = true, isActive = false),
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,104 +1,17 @@
|
|||
package io.github.openflocon.flocondesktop.features.network.list.processor
|
||||
|
||||
import io.github.openflocon.domain.network.models.FloconNetworkCallDomainModel
|
||||
import io.github.openflocon.domain.network.models.NetworkTextFilterColumns
|
||||
import io.github.openflocon.flocondesktop.features.network.list.model.TopBarUiState
|
||||
import io.github.openflocon.flocondesktop.features.network.list.model.NetworkItemViewState
|
||||
import io.github.openflocon.flocondesktop.features.network.list.model.NetworkMethodUi
|
||||
import io.github.openflocon.flocondesktop.features.network.list.model.header.columns.base.filter.TextFilterStateUiModel
|
||||
|
||||
class FilterNetworkItemsProcessor {
|
||||
operator fun invoke(
|
||||
items: List<Pair<FloconNetworkCallDomainModel, NetworkItemViewState>>,
|
||||
filterState: TopBarUiState,
|
||||
allowedMethods: List<NetworkMethodUi>,
|
||||
textFilters: Map<NetworkTextFilterColumns, TextFilterStateUiModel>,
|
||||
): List<NetworkItemViewState> = items.asSequence()
|
||||
.filter { item ->
|
||||
item.second.method in allowedMethods
|
||||
}
|
||||
.filter { item ->
|
||||
val filters = textFilters.filter { it.value.isActive }
|
||||
if(filters.isEmpty()) true
|
||||
else {
|
||||
filters.any { (column, textFilter) ->
|
||||
textFilter.filter(column, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
.map { it.second }
|
||||
.toList()
|
||||
}
|
||||
|
||||
private fun TextFilterStateUiModel.filter(
|
||||
column: NetworkTextFilterColumns,
|
||||
item: Pair<FloconNetworkCallDomainModel, NetworkItemViewState>,
|
||||
): Boolean {
|
||||
val text = when (column) {
|
||||
NetworkTextFilterColumns.RequestTime -> item.second.dateFormatted
|
||||
NetworkTextFilterColumns.Domain -> item.second.domain
|
||||
NetworkTextFilterColumns.Query -> item.second.type.text
|
||||
NetworkTextFilterColumns.Status -> item.second.status.text
|
||||
NetworkTextFilterColumns.Time -> item.second.timeFormatted
|
||||
}
|
||||
return filterByText(text)
|
||||
}
|
||||
|
||||
private fun TextFilterStateUiModel.filterByText(text: String?): Boolean {
|
||||
// 1. If text is null, it always passes the filter (default behavior).
|
||||
if (text == null) {
|
||||
return true
|
||||
}
|
||||
|
||||
val activeFilters = this.allFilters.filter { it.isActive }
|
||||
|
||||
// 2. If there are no active filters, it always passes.
|
||||
if (activeFilters.isEmpty()) {
|
||||
return true
|
||||
}
|
||||
|
||||
val (excludedFilters, includedFilters) = activeFilters.partition { it.isExcluded }
|
||||
|
||||
// --- Step 1: Exclusion Check ---
|
||||
|
||||
// 4. Check if the text matches ANY exclusion filter.
|
||||
// If ANY active 'isExcluded' filter matches, the item MUST be rejected (return false).
|
||||
val isExcluded = excludedFilters.any { it.matches(text) }
|
||||
|
||||
if (isExcluded) {
|
||||
return false // Excluded, so it fails the filter immediately.
|
||||
}
|
||||
|
||||
// --- Step 2: Inclusion Check ---
|
||||
|
||||
// 5. If there are no inclusion filters, the item passes (as it wasn't excluded).
|
||||
if (includedFilters.isEmpty()) {
|
||||
return true
|
||||
}
|
||||
|
||||
// 6. If not excluded, check if the text matches AT LEAST ONE inclusion filter.
|
||||
// If ANY non-excluded filter matches, the item is kept (return true).
|
||||
return includedFilters.any { it.matches(text) }
|
||||
}
|
||||
|
||||
private fun TextFilterStateUiModel.FilterItem.matches(text: String): Boolean {
|
||||
return if (this.isRegex) {
|
||||
Regex(this.text, setOf(RegexOption.IGNORE_CASE)).containsMatchIn(text)
|
||||
} else {
|
||||
text.contains(this.text, ignoreCase = true)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* lookup if the request or response body contains the text
|
||||
*/
|
||||
private fun FloconNetworkCallDomainModel.contains(text: String) : Boolean {
|
||||
return request.body?.contains(text, ignoreCase = true) == true || response?.contains(text) == true
|
||||
}
|
||||
|
||||
private fun FloconNetworkCallDomainModel.Response.contains(text: String) : Boolean {
|
||||
return when(this) {
|
||||
is FloconNetworkCallDomainModel.Response.Failure -> issue.contains(text, ignoreCase = true)
|
||||
is FloconNetworkCallDomainModel.Response.Success -> body?.contains(text, ignoreCase = true) == true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@ private fun contextualActions(
|
|||
NetworkAction.HeaderAction.FilterAction(
|
||||
OnFilterAction.TextFilter(
|
||||
column = NetworkTextFilterColumns.Domain,
|
||||
action = TextFilterAction.Include(text = state.domain, isRegex = false)
|
||||
action = TextFilterAction.Include(text = state.domain)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
@ -185,7 +185,7 @@ private fun contextualActions(
|
|||
NetworkAction.HeaderAction.FilterAction(
|
||||
OnFilterAction.TextFilter(
|
||||
column = NetworkTextFilterColumns.Query,
|
||||
action = TextFilterAction.Include(text = state.type.query, isRegex = false)
|
||||
action = TextFilterAction.Include(text = state.type.query)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
@ -197,7 +197,7 @@ private fun contextualActions(
|
|||
NetworkAction.HeaderAction.FilterAction(
|
||||
OnFilterAction.TextFilter(
|
||||
column = NetworkTextFilterColumns.Domain,
|
||||
action = TextFilterAction.Exclude(text = state.domain, isRegex = false)
|
||||
action = TextFilterAction.Exclude(text = state.domain)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
@ -207,7 +207,7 @@ private fun contextualActions(
|
|||
NetworkAction.HeaderAction.FilterAction(
|
||||
OnFilterAction.TextFilter(
|
||||
column = NetworkTextFilterColumns.Query,
|
||||
action = TextFilterAction.Exclude(text = state.type.query, isRegex = false)
|
||||
action = TextFilterAction.Exclude(text = state.type.query)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -58,11 +58,11 @@ fun TextFilterDropdownContent(
|
|||
modifier = modifier.fillMaxWidth()
|
||||
) {
|
||||
TextFilterFieldView(
|
||||
submitTextField = { text, toInclude, isRegex ->
|
||||
submitTextField = { text, toInclude ->
|
||||
if (toInclude) {
|
||||
textFilterAction.invoke(TextFilterAction.Include(text, isRegex = isRegex))
|
||||
textFilterAction.invoke(TextFilterAction.Include(text))
|
||||
} else {
|
||||
textFilterAction.invoke(TextFilterAction.Exclude(text, isRegex = isRegex))
|
||||
textFilterAction.invoke(TextFilterAction.Exclude(text))
|
||||
}
|
||||
},
|
||||
modifier = Modifier
|
||||
|
|
@ -196,11 +196,10 @@ private fun FilterItemView(
|
|||
|
||||
@Composable
|
||||
private fun TextFilterFieldView(
|
||||
submitTextField: (value: String, toInclude: Boolean, isRegex: Boolean) -> Unit,
|
||||
submitTextField: (value: String, toInclude: Boolean) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
var value by remember { mutableStateOf("") }
|
||||
var isRegex by remember { mutableStateOf(false) }
|
||||
|
||||
Row(
|
||||
modifier = modifier,
|
||||
|
|
@ -213,7 +212,7 @@ private fun TextFilterFieldView(
|
|||
keyboardActions = KeyboardActions(
|
||||
onDone = {
|
||||
// default action -> add as "include filter"
|
||||
submitTextField(value, true, isRegex)
|
||||
submitTextField(value, true)
|
||||
value = "" // reset
|
||||
},
|
||||
),
|
||||
|
|
@ -221,15 +220,6 @@ private fun TextFilterFieldView(
|
|||
textStyle = FloconTheme.typography.bodySmall.copy(
|
||||
color = FloconTheme.colorPalette.onSecondary,
|
||||
),
|
||||
trailingComponent = {
|
||||
RegexFilterButton(
|
||||
modifier = Modifier.size(24.dp),
|
||||
isRegex = isRegex,
|
||||
onClick = {
|
||||
isRegex = !isRegex
|
||||
},
|
||||
)
|
||||
},
|
||||
containerColor = FloconTheme.colorPalette.secondary,
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
|
|
@ -238,7 +228,7 @@ private fun TextFilterFieldView(
|
|||
FloconSmallIconButton(
|
||||
enabled = value.isNotEmpty(),
|
||||
onClick = {
|
||||
submitTextField(value, true, isRegex)
|
||||
submitTextField(value, true)
|
||||
value = "" // reset
|
||||
}
|
||||
) {
|
||||
|
|
@ -247,7 +237,7 @@ private fun TextFilterFieldView(
|
|||
FloconSmallIconButton(
|
||||
enabled = value.isNotEmpty(),
|
||||
onClick = {
|
||||
submitTextField(value, false, isRegex)
|
||||
submitTextField(value, false)
|
||||
value = "" // reset
|
||||
}
|
||||
) {
|
||||
|
|
@ -281,30 +271,6 @@ private fun TextFilterButton(
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
private fun RegexFilterButton(
|
||||
onClick: () -> Unit,
|
||||
isRegex: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.size(20.dp)
|
||||
.clip(RoundedCornerShape(6.dp))
|
||||
.graphicsLayer { alpha = if (isRegex) 1f else 0.5f }
|
||||
.background(Color.White)
|
||||
.clickable(onClick = onClick),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Text(
|
||||
".*",
|
||||
fontSize = 11.sp,
|
||||
color = FloconTheme.colorPalette.surface,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun TextFilterDropdownContentPreview() {
|
||||
|
|
|
|||
|
|
@ -4,16 +4,16 @@ import io.github.openflocon.data.core.network.datasource.NetworkFilterLocalDataS
|
|||
import io.github.openflocon.data.local.network.dao.NetworkFilterDao
|
||||
import io.github.openflocon.data.local.network.mapper.textFilterToDomain
|
||||
import io.github.openflocon.data.local.network.mapper.textFilterToEntity
|
||||
import io.github.openflocon.domain.device.models.AppPackageName
|
||||
import io.github.openflocon.domain.device.models.DeviceId
|
||||
import io.github.openflocon.domain.device.models.DeviceIdAndPackageNameDomainModel
|
||||
import io.github.openflocon.domain.models.TextFilterStateDomainModel
|
||||
import io.github.openflocon.domain.network.models.NetworkTextFilterColumns
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
class NetworkFilterLocalDataSourceRoom(
|
||||
private val networkFilterDao: NetworkFilterDao,
|
||||
private val json: Json,
|
||||
) : NetworkFilterLocalDataSource {
|
||||
|
||||
override suspend fun get(
|
||||
|
|
@ -23,9 +23,9 @@ class NetworkFilterLocalDataSourceRoom(
|
|||
deviceId = deviceAndApp.deviceId,
|
||||
packageName = deviceAndApp.packageName,
|
||||
column = column,
|
||||
)?.let {
|
||||
textFilterToDomain(it)
|
||||
}
|
||||
)?.textFilterToDomain(
|
||||
json = json,
|
||||
)
|
||||
|
||||
override fun observe(
|
||||
deviceAndApp: DeviceIdAndPackageNameDomainModel,
|
||||
|
|
@ -34,7 +34,9 @@ class NetworkFilterLocalDataSourceRoom(
|
|||
packageName = deviceAndApp.packageName,
|
||||
).map {
|
||||
it.associate {
|
||||
it.columnName to textFilterToDomain(it)
|
||||
it.columnName to it.textFilterToDomain(
|
||||
json = json,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -49,6 +51,7 @@ class NetworkFilterLocalDataSourceRoom(
|
|||
packageName = deviceAndApp.packageName,
|
||||
column = column,
|
||||
domain = newValue,
|
||||
json = json,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import io.github.openflocon.domain.device.models.DeviceIdAndPackageNameDomainMod
|
|||
import io.github.openflocon.domain.network.models.FloconNetworkCallDomainModel
|
||||
import io.github.openflocon.domain.network.models.NetworkFilterDomainModel
|
||||
import io.github.openflocon.domain.network.models.NetworkSortDomainModel
|
||||
import io.github.openflocon.domain.network.models.NetworkTextFilterColumns
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
|
|
@ -63,24 +64,54 @@ class NetworkLocalDataSourceRoom(
|
|||
columns.forEachIndexed { index, column ->
|
||||
appendLine("$column LIKE ? COLLATE NOCASE")
|
||||
args.add("%$filterText%")
|
||||
if(index != columns.lastIndex) {
|
||||
if (index != columns.lastIndex) {
|
||||
appendLine("OR")
|
||||
}
|
||||
}
|
||||
appendLine(")")
|
||||
}
|
||||
|
||||
filter.filters?.forEach { filter ->
|
||||
filter.includedFilters.takeIf { it.isNotEmpty() }?.let { included ->
|
||||
appendLine("AND (")
|
||||
included.forEachIndexed { includedFilterIndex, filterItem ->
|
||||
appendLine("\t${filter.column.roomColumnName()} LIKE ? COLLATE NOCASE")
|
||||
args.add("%${filterItem.text}%")
|
||||
|
||||
if (includedFilterIndex != included.lastIndex) {
|
||||
appendLine("\tOR")
|
||||
}
|
||||
}
|
||||
appendLine(")")
|
||||
}
|
||||
filter.excludedFilters.takeIf { it.isNotEmpty() }?.let { excluded ->
|
||||
appendLine("AND (")
|
||||
excluded.forEachIndexed { excludedFilterIndex, filterItem ->
|
||||
appendLine("\t${filter.column.roomColumnName()} NOT LIKE ? COLLATE NOCASE")
|
||||
args.add("%${filterItem.text}%")
|
||||
|
||||
if (excludedFilterIndex != excluded.lastIndex) {
|
||||
appendLine("\tAND")
|
||||
}
|
||||
}
|
||||
appendLine(")")
|
||||
}
|
||||
}
|
||||
|
||||
appendLine("ORDER BY $safeColumnName $sortOrder")
|
||||
}.trimIndent()
|
||||
|
||||
val roomQuery = RoomRawQuery(sqlQuery, onBindStatement = {
|
||||
args.forEachIndexed { index, item ->
|
||||
when(item) {
|
||||
when (item) {
|
||||
is String -> {
|
||||
it.bindText(index + 1, item)
|
||||
}
|
||||
|
||||
is Int -> {
|
||||
it.bindInt(index + 1, item)
|
||||
}
|
||||
|
||||
is Long -> {
|
||||
it.bindLong(index + 1, item)
|
||||
}
|
||||
|
|
@ -115,7 +146,7 @@ class NetworkLocalDataSourceRoom(
|
|||
override suspend fun getCall(
|
||||
deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel,
|
||||
callId: String,
|
||||
): FloconNetworkCallDomainModel? {
|
||||
): FloconNetworkCallDomainModel? {
|
||||
return floconNetworkDao
|
||||
.getCallById(
|
||||
deviceId = deviceIdAndPackageName.deviceId,
|
||||
|
|
@ -182,6 +213,14 @@ class NetworkLocalDataSourceRoom(
|
|||
}
|
||||
}
|
||||
|
||||
// TODO maybe merge with NetworkSortDomainModel.Column
|
||||
private fun NetworkTextFilterColumns.roomColumnName(): String = when (this) {
|
||||
NetworkTextFilterColumns.RequestTime -> "request_startTimeFormatted"
|
||||
NetworkTextFilterColumns.Domain -> "request_domainFormatted"
|
||||
NetworkTextFilterColumns.Query -> "request_queryFormatted"
|
||||
NetworkTextFilterColumns.Status -> "response_statusFormatted"
|
||||
NetworkTextFilterColumns.Time -> "response_durationMs"
|
||||
}
|
||||
|
||||
private fun NetworkSortDomainModel.Column.roomColumnName(): String = when (this) {
|
||||
NetworkSortDomainModel.Column.RequestStartTimeFormatted -> "request_startTimeFormatted"
|
||||
|
|
|
|||
|
|
@ -12,17 +12,16 @@ fun textFilterItemToEntity(item: TextFilterStateDomainModel.FilterItem): FilterI
|
|||
text = item.text,
|
||||
isActive = item.isActive,
|
||||
isExcluded = item.isExcluded,
|
||||
isRegex = item.isRegex,
|
||||
)
|
||||
|
||||
fun textFilterItemToDomain(item: FilterItemSavedEntity): TextFilterStateDomainModel.FilterItem = TextFilterStateDomainModel.FilterItem(
|
||||
text = item.text,
|
||||
isActive = item.isActive,
|
||||
isExcluded = item.isExcluded,
|
||||
isRegex = item.isRegex,
|
||||
)
|
||||
|
||||
fun textFilterToEntity(
|
||||
json: Json,
|
||||
deviceId: DeviceId,
|
||||
packageName: AppPackageName,
|
||||
column: NetworkTextFilterColumns,
|
||||
|
|
@ -36,16 +35,16 @@ fun textFilterToEntity(
|
|||
packageName = packageName,
|
||||
columnName = column,
|
||||
isEnabled = domain.isEnabled,
|
||||
itemsAsJson = Json.encodeToString(itemsEntity),
|
||||
itemsAsJson = json.encodeToString(itemsEntity),
|
||||
)
|
||||
}
|
||||
|
||||
fun textFilterToDomain(
|
||||
entity: NetworkFilterEntity,
|
||||
fun NetworkFilterEntity.textFilterToDomain(
|
||||
json: Json,
|
||||
): TextFilterStateDomainModel {
|
||||
val itemsEntity = Json.decodeFromString<List<FilterItemSavedEntity>>(entity.itemsAsJson)
|
||||
val itemsEntity = json.decodeFromString<List<FilterItemSavedEntity>>(itemsAsJson)
|
||||
return TextFilterStateDomainModel(
|
||||
isEnabled = entity.isEnabled,
|
||||
isEnabled = isEnabled,
|
||||
items = itemsEntity.map {
|
||||
textFilterItemToDomain(it)
|
||||
},
|
||||
|
|
|
|||
|
|
@ -7,5 +7,4 @@ data class FilterItemSavedEntity(
|
|||
val text: String,
|
||||
val isActive: Boolean,
|
||||
val isExcluded: Boolean,
|
||||
val isRegex: Boolean,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -8,6 +8,5 @@ data class TextFilterStateDomainModel(
|
|||
val text: String,
|
||||
val isActive: Boolean,
|
||||
val isExcluded: Boolean,
|
||||
val isRegex: Boolean,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,4 +2,15 @@ package io.github.openflocon.domain.network.models
|
|||
|
||||
data class NetworkFilterDomainModel(
|
||||
val filterOnAllColumns: String?,
|
||||
)
|
||||
val filters: List<Filters>?,
|
||||
) {
|
||||
data class Filters(
|
||||
val column: NetworkTextFilterColumns,
|
||||
val includedFilters: List<FilterItem>,
|
||||
val excludedFilters: List<FilterItem>,
|
||||
) {
|
||||
data class FilterItem(
|
||||
val text: String,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue