diff --git a/FloconDesktop/composeApp/schemas/io.github.openflocon.flocondesktop.common.db.AppDatabase/39.json b/FloconDesktop/composeApp/schemas/io.github.openflocon.flocondesktop.common.db.AppDatabase/39.json index 4f9b12ff..645c72e2 100644 --- a/FloconDesktop/composeApp/schemas/io.github.openflocon.flocondesktop.common.db.AppDatabase/39.json +++ b/FloconDesktop/composeApp/schemas/io.github.openflocon.flocondesktop.common.db.AppDatabase/39.json @@ -2,7 +2,7 @@ "formatVersion": 1, "database": { "version": 39, - "identityHash": "121dfc4cfd03bb71ddd3d8af08dd8939", + "identityHash": "2f04f00102ac26b72949768d76f33930", "entities": [ { "tableName": "FloconNetworkCallEntity", @@ -998,8 +998,20 @@ }, { "tableName": "BadQualityConfigEntity", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`deviceId` TEXT NOT NULL, `packageName` TEXT NOT NULL, `isEnabled` INTEGER NOT NULL, `errorProbability` REAL NOT NULL, `errors` TEXT NOT NULL, `triggerProbability` REAL NOT NULL, `minLatencyMs` INTEGER NOT NULL, `maxLatencyMs` INTEGER NOT NULL, PRIMARY KEY(`deviceId`, `packageName`))", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `deviceId` TEXT NOT NULL, `packageName` TEXT NOT NULL, `isEnabled` INTEGER NOT NULL, `errorProbability` REAL NOT NULL, `errors` TEXT NOT NULL, `triggerProbability` REAL NOT NULL, `minLatencyMs` INTEGER NOT NULL, `maxLatencyMs` INTEGER NOT NULL, PRIMARY KEY(`id`))", "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, { "fieldPath": "deviceId", "columnName": "deviceId", @@ -1052,15 +1064,26 @@ "primaryKey": { "autoGenerate": false, "columnNames": [ - "deviceId", - "packageName" + "id" ] - } + }, + "indices": [ + { + "name": "index_BadQualityConfigEntity_deviceId_packageName", + "unique": false, + "columnNames": [ + "deviceId", + "packageName" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_BadQualityConfigEntity_deviceId_packageName` ON `${TABLE_NAME}` (`deviceId`, `packageName`)" + } + ] } ], "setupQueries": [ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '121dfc4cfd03bb71ddd3d8af08dd8939')" + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '2f04f00102ac26b72949768d76f33930')" ] } } \ No newline at end of file diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/common/db/AppDatabase.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/common/db/AppDatabase.kt index 26b30b65..442e9851 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/common/db/AppDatabase.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/common/db/AppDatabase.kt @@ -36,7 +36,7 @@ import io.github.openflocon.flocondesktop.common.db.converters.MapStringsConvert import kotlinx.coroutines.Dispatchers @Database( - version = 39, + version = 41, entities = [ FloconNetworkCallEntity::class, FileEntity::class, diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/BadQualityNetworkViewModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/BadQualityNetworkViewModel.kt deleted file mode 100644 index fdc0d0e8..00000000 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/BadQualityNetworkViewModel.kt +++ /dev/null @@ -1,62 +0,0 @@ -package io.github.openflocon.flocondesktop.features.network - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import io.github.openflocon.domain.common.DispatcherProvider -import io.github.openflocon.domain.feedback.FeedbackDisplayer -import io.github.openflocon.domain.network.usecase.badquality.ObserveNetworkBadQualityUseCase -import io.github.openflocon.domain.network.usecase.badquality.SaveNetworkBadQualityUseCase -import io.github.openflocon.domain.network.usecase.badquality.UpdateNetworkBadQualityIsEnabledUseCase -import io.github.openflocon.flocondesktop.features.network.mapper.toDomain -import io.github.openflocon.flocondesktop.features.network.mapper.toUi -import io.github.openflocon.flocondesktop.features.network.model.badquality.BadQualityConfigUiModel -import kotlinx.coroutines.channels.Channel -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.distinctUntilChanged -import kotlinx.coroutines.flow.flowOn -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.receiveAsFlow -import kotlinx.coroutines.flow.stateIn -import kotlinx.coroutines.launch - -class BadQualityNetworkViewModel( - private val observeNetworkBadQualityUseCase: ObserveNetworkBadQualityUseCase, - private val saveNetworkBadQualityUseCase: SaveNetworkBadQualityUseCase, - private val updateNetworkBadQualityIsEnabledUseCase: UpdateNetworkBadQualityIsEnabledUseCase, - private val dispatcherProvider: DispatcherProvider, - private val feedbackDisplayer: FeedbackDisplayer, -) : ViewModel() { - - enum class Event { - Close - } - - private val _events = Channel() - val events: Flow = _events.receiveAsFlow() - - val viewState = observeNetworkBadQualityUseCase() - .distinctUntilChanged() - .map { toUi(it) } - .flowOn(dispatcherProvider.viewModel) - .stateIn( - scope = viewModelScope, - started = SharingStarted.WhileSubscribed(5_000), - initialValue = null, - ) - - fun changeIsEnabled(enabled: Boolean) { - viewModelScope.launch(dispatcherProvider.viewModel) { - updateNetworkBadQualityIsEnabledUseCase(isEnabled = enabled) - } - } - - fun save(uiModel: BadQualityConfigUiModel) { - viewModelScope.launch(dispatcherProvider.viewModel) { - saveNetworkBadQualityUseCase(toDomain(uiModel)) - // close - _events.send(Event.Close) - feedbackDisplayer.displayMessage("Saved") - } - } -} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/NetworkUiModule.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/NetworkUiModule.kt index e8dc8ec3..76afa8f9 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/NetworkUiModule.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/NetworkUiModule.kt @@ -1,6 +1,8 @@ package io.github.openflocon.flocondesktop.features.network +import io.github.openflocon.flocondesktop.features.network.badquality.BadQualityNetworkViewModel import io.github.openflocon.flocondesktop.features.network.delegate.HeaderDelegate +import io.github.openflocon.flocondesktop.features.network.mock.NetworkMocksViewModel import io.github.openflocon.flocondesktop.messages.ui.MessagesServerDelegate import org.koin.core.module.dsl.factoryOf import org.koin.core.module.dsl.viewModelOf diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/BadQualityNetworkViewModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/BadQualityNetworkViewModel.kt new file mode 100644 index 00000000..112f187b --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/BadQualityNetworkViewModel.kt @@ -0,0 +1,101 @@ +package io.github.openflocon.flocondesktop.features.network.badquality + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import io.github.openflocon.domain.common.DispatcherProvider +import io.github.openflocon.domain.feedback.FeedbackDisplayer +import io.github.openflocon.domain.network.models.BadQualityConfigId +import io.github.openflocon.domain.network.usecase.badquality.DeleteBadQualityUseCase +import io.github.openflocon.domain.network.usecase.badquality.ObserveAllNetworkBadQualitiesUseCase +import io.github.openflocon.domain.network.usecase.badquality.ObserveNetworkBadQualityUseCase +import io.github.openflocon.domain.network.usecase.badquality.SaveNetworkBadQualityUseCase +import io.github.openflocon.domain.network.usecase.badquality.SetNetworkBadQualityEnabledConfigUseCase +import io.github.openflocon.flocondesktop.features.network.badquality.edition.mapper.toDomain +import io.github.openflocon.flocondesktop.features.network.badquality.edition.mapper.toUi +import io.github.openflocon.flocondesktop.features.network.badquality.list.mapper.toLineUi +import io.github.openflocon.flocondesktop.features.network.badquality.edition.model.BadQualityConfigUiModel +import io.github.openflocon.flocondesktop.features.network.badquality.edition.model.SelectedBadQualityUiModel +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.firstOrNull +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.receiveAsFlow +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.launch + +class BadQualityNetworkViewModel( + private val observeAllNetworkBadQualitiesUseCase: ObserveAllNetworkBadQualitiesUseCase, + private val observeNetworkBadQualityUseCase: ObserveNetworkBadQualityUseCase, + private val deleteBadQualityUseCase: DeleteBadQualityUseCase, + private val saveNetworkBadQualityUseCase: SaveNetworkBadQualityUseCase, + private val setNetworkBadQualityEnabledConfigUseCase: SetNetworkBadQualityEnabledConfigUseCase, + private val dispatcherProvider: DispatcherProvider, + private val feedbackDisplayer: FeedbackDisplayer, +) : ViewModel() { + + enum class Event { + Close + } + + private val _events = Channel() + val events: Flow = _events.receiveAsFlow() + + val items = observeAllNetworkBadQualitiesUseCase() + .distinctUntilChanged() + .map { it.map { it.toLineUi() } } + .flowOn(dispatcherProvider.viewModel) + .stateIn( + scope = viewModelScope, + started = SharingStarted.WhileSubscribed(5_000), + initialValue = emptyList(), + ) + + val selectedItem = MutableStateFlow(null) + + fun setEnabledElement(configId: BadQualityConfigId?) { + viewModelScope.launch(dispatcherProvider.viewModel) { + setNetworkBadQualityEnabledConfigUseCase(configId = configId) + } + } + + fun delete(id: String) { + viewModelScope.launch(dispatcherProvider.viewModel) { + deleteBadQualityUseCase(id) + } + } + + fun select(id: String) { + viewModelScope.launch(dispatcherProvider.viewModel) { + // TODO get + val existing = observeNetworkBadQualityUseCase(id).firstOrNull()?.toUi() + selectedItem.value = existing?.let { + SelectedBadQualityUiModel.Edition( + config = existing + ) + } ?: SelectedBadQualityUiModel.Creation + } + } + + fun create() { + selectedItem.value = SelectedBadQualityUiModel.Creation + } + + fun save(uiModel: BadQualityConfigUiModel) { + viewModelScope.launch(dispatcherProvider.viewModel) { + saveNetworkBadQualityUseCase(uiModel.toDomain()) + // close + selectedItem.value = null + feedbackDisplayer.displayMessage("Saved") + } + } + + fun closeEdition() { + selectedItem.value = null + } +} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/edition/mapper/BadQualityMapper.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/edition/mapper/BadQualityMapper.kt new file mode 100644 index 00000000..fd75ecab --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/edition/mapper/BadQualityMapper.kt @@ -0,0 +1,59 @@ +package io.github.openflocon.flocondesktop.features.network.badquality.edition.mapper + +import io.github.openflocon.domain.network.models.BadQualityConfigDomainModel +import io.github.openflocon.flocondesktop.features.network.badquality.edition.model.BadQualityConfigUiModel +import kotlin.time.Instant + + +fun BadQualityConfigDomainModel.toUi() = BadQualityConfigUiModel( + id = id, + name = name, + createdAt = createdAt.toEpochMilliseconds(), + isEnabled = isEnabled, + latency = latency.toUi(), + errorProbability = errorProbability, + errors = errors.map { error -> + error.toUi() + } +) + +private fun BadQualityConfigDomainModel.Error.toUi() = BadQualityConfigUiModel.Error( + weight = weight, + httpCode = httpCode, + body = body, + contentType = contentType, +) + +private fun BadQualityConfigDomainModel.LatencyConfig.toUi() = + BadQualityConfigUiModel.LatencyConfig( + triggerProbability = triggerProbability, + minLatencyMs = minLatencyMs, + maxLatencyMs = maxLatencyMs, + ) + + +fun BadQualityConfigUiModel.toDomain() = BadQualityConfigDomainModel( + id = id, + name = name, + createdAt = Instant.fromEpochMilliseconds(createdAt), + isEnabled = isEnabled, + latency = latency.toDomain(), + errorProbability = errorProbability, + errors = errors.map { error -> + error.toDomain() + } +) + +private fun BadQualityConfigUiModel.Error.toDomain() = BadQualityConfigDomainModel.Error( + weight = weight, + httpCode = httpCode, + body = body, + contentType = contentType, +) + +private fun BadQualityConfigUiModel.LatencyConfig.toDomain() = + BadQualityConfigDomainModel.LatencyConfig( + triggerProbability = triggerProbability, + minLatencyMs = minLatencyMs, + maxLatencyMs = maxLatencyMs, + ) diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/model/badquality/BadQualityConfigUiModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/edition/model/BadQualityConfigUiModel.kt similarity index 83% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/model/badquality/BadQualityConfigUiModel.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/edition/model/BadQualityConfigUiModel.kt index f654e0b0..43130caf 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/model/badquality/BadQualityConfigUiModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/edition/model/BadQualityConfigUiModel.kt @@ -1,8 +1,11 @@ -package io.github.openflocon.flocondesktop.features.network.model.badquality +package io.github.openflocon.flocondesktop.features.network.badquality.edition.model import java.util.UUID data class BadQualityConfigUiModel( + val id: String, + val name: String, + val createdAt: Long, val isEnabled: Boolean, val latency: LatencyConfig, val errorProbability: Double, // chance of triggering an error @@ -23,6 +26,8 @@ data class BadQualityConfigUiModel( } fun previewBadQualityConfigUiModel(errorCount: Int) = BadQualityConfigUiModel( + id = "id", + name = "config_name", isEnabled = true, latency = BadQualityConfigUiModel.LatencyConfig( triggerProbability = 0.1, @@ -30,6 +35,7 @@ fun previewBadQualityConfigUiModel(errorCount: Int) = BadQualityConfigUiModel( maxLatencyMs = 200, ), errorProbability = 0.8, + createdAt = System.currentTimeMillis(), errors = List(errorCount) { BadQualityConfigUiModel.Error( weight = 1f, diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/edition/model/SelectedBadQualityUiModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/edition/model/SelectedBadQualityUiModel.kt new file mode 100644 index 00000000..d01c71c1 --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/edition/model/SelectedBadQualityUiModel.kt @@ -0,0 +1,18 @@ +package io.github.openflocon.flocondesktop.features.network.badquality.edition.model + +import androidx.compose.runtime.Immutable +import io.github.openflocon.flocondesktop.features.network.mock.edition.model.MockNetworkUiModel + +@Immutable +sealed interface SelectedBadQualityUiModel { + + val config: BadQualityConfigUiModel? + + @Immutable + data object Creation : SelectedBadQualityUiModel { + override val config: BadQualityConfigUiModel? = null + } + + @Immutable + data class Edition(override val config: BadQualityConfigUiModel) : SelectedBadQualityUiModel +} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/view/badquality/BadNetworkQualityWindow.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/edition/view/BadQualityEditionWindow.kt similarity index 84% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/view/badquality/BadNetworkQualityWindow.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/edition/view/BadQualityEditionWindow.kt index 21905f01..c0c6afcf 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/view/badquality/BadNetworkQualityWindow.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/edition/view/BadQualityEditionWindow.kt @@ -1,6 +1,6 @@ @file:OptIn(ExperimentalMaterial3Api::class) -package io.github.openflocon.flocondesktop.features.network.view.badquality +package io.github.openflocon.flocondesktop.features.network.badquality.edition.view import androidx.compose.foundation.Image import androidx.compose.foundation.background @@ -25,7 +25,6 @@ import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Switch import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -38,91 +37,68 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import io.github.openflocon.flocondesktop.features.network.BadQualityNetworkViewModel -import io.github.openflocon.flocondesktop.features.network.model.badquality.BadQualityConfigUiModel -import io.github.openflocon.flocondesktop.features.network.model.badquality.previewBadQualityConfigUiModel -import io.github.openflocon.flocondesktop.features.network.view.mocks.NetworkMockFieldView +import io.github.openflocon.flocondesktop.features.network.badquality.edition.model.BadQualityConfigUiModel +import io.github.openflocon.flocondesktop.features.network.badquality.edition.model.SelectedBadQualityUiModel +import io.github.openflocon.flocondesktop.features.network.mock.edition.view.NetworkMockFieldView import io.github.openflocon.library.designsystem.FloconTheme import io.github.openflocon.library.designsystem.components.FloconButton import io.github.openflocon.library.designsystem.components.FloconDialog import io.github.openflocon.library.designsystem.components.FloconDialogButtons import io.github.openflocon.library.designsystem.components.FloconSurface -import org.jetbrains.compose.ui.tooling.preview.Preview -import org.koin.compose.viewmodel.koinViewModel +import java.util.UUID @Composable -fun BadNetworkQualityWindow( +fun BadQualityEditionWindow( onCloseRequest: () -> Unit, + save: (state: BadQualityConfigUiModel) -> Unit, + state: SelectedBadQualityUiModel, ) { - val viewModel: BadQualityNetworkViewModel = koinViewModel() - val state by viewModel.viewState.collectAsStateWithLifecycle() - - val viewModelEvent by viewModel.events.collectAsStateWithLifecycle(null) - LaunchedEffect(viewModelEvent) { - when (viewModelEvent) { - BadQualityNetworkViewModel.Event.Close -> onCloseRequest() - null -> {} - } - } - FloconDialog( onDismissRequest = onCloseRequest ) { - BadNetworkQualityContent( + BadNetworkQualityEditionContent( state = state, - save = viewModel::save, + save = save, close = onCloseRequest, ) } } @Composable -@Preview -private fun BadNetworkQualityContentPreview() { - FloconTheme { - FloconSurface { - BadNetworkQualityContent( - state = previewBadQualityConfigUiModel( - errorCount = 5 - ), - save = {}, - close = {}, - ) - } - } -} - - -@Composable -fun BadNetworkQualityContent( - state: BadQualityConfigUiModel?, +fun BadNetworkQualityEditionContent( + state: SelectedBadQualityUiModel, close: () -> Unit, save: (state: BadQualityConfigUiModel) -> Unit, modifier: Modifier = Modifier, ) { - var isEnabled by remember(state) { mutableStateOf(state?.isEnabled ?: true) } + val config = state.config + + var name by remember(state) { + mutableStateOf( + config?.name ?: "" + ) + } var triggerProbability by remember(state) { mutableStateOf( - state?.latency?.triggerProbability?.let { it * 100.0 }?.toString() ?: "100" + config?.latency?.triggerProbability?.let { it * 100.0 }?.toString() ?: "100" ) } var minLatencyMs by remember(state) { mutableStateOf( - state?.latency?.minLatencyMs?.toString() ?: "0" + config?.latency?.minLatencyMs?.toString() ?: "0" ) } var maxLatencyMs by remember(state) { mutableStateOf( - state?.latency?.maxLatencyMs?.toString() ?: "0" + config?.latency?.maxLatencyMs?.toString() ?: "0" ) } var errorProbability by remember(state) { mutableStateOf( - state?.errorProbability?.let { it * 100.0 }?.toString() ?: "100" + config?.errorProbability?.let { it * 100.0 }?.toString() ?: "100" ) } - var errors by remember(state) { mutableStateOf(state?.errors ?: emptyList()) } + var errors by remember(state) { mutableStateOf(config?.errors ?: emptyList()) } var selectedErrorToEdit by remember { mutableStateOf(null) } Column( @@ -131,20 +107,15 @@ fun BadNetworkQualityContent( .fillMaxSize() .padding(8.dp) ) { - Row( - horizontalArrangement = Arrangement.spacedBy(4.dp), - verticalAlignment = Alignment.CenterVertically - ) { - Switch( - modifier = Modifier.scale(0.6f), - checked = isEnabled, - onCheckedChange = { isEnabled = it } - ) - Text( - text = "Enable", - style = FloconTheme.typography.titleMedium - ) - } + NetworkMockFieldView( + label = "Name", + placeHolder = "", + value = name, + onValueChange = { + name = it + }, + trailingComponent = { } + ) NetworkMockFieldView( label = "Trigger probability", placeHolder = "0", @@ -237,7 +208,10 @@ fun BadNetworkQualityContent( maxLatencyMs.toLong().coerceAtLeast(minLatencyMsValue) save( BadQualityConfigUiModel( - isEnabled = isEnabled, + id = config?.id ?: UUID.randomUUID().toString(), // generate a new one + name = name, + isEnabled = config?.isEnabled ?: false, // disabled by default + createdAt = config?.createdAt ?: System.currentTimeMillis(), // generate a new date latency = BadQualityConfigUiModel.LatencyConfig( triggerProbability = triggerProbability .toDoubleOrNull() diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/list/mapper/BadQualityMapper.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/list/mapper/BadQualityMapper.kt new file mode 100644 index 00000000..44a1c586 --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/list/mapper/BadQualityMapper.kt @@ -0,0 +1,10 @@ +package io.github.openflocon.flocondesktop.features.network.badquality.list.mapper + +import io.github.openflocon.domain.network.models.BadQualityConfigDomainModel +import io.github.openflocon.flocondesktop.features.network.badquality.list.model.NetworkBadQualityLineUiModel + +fun BadQualityConfigDomainModel.toLineUi() = NetworkBadQualityLineUiModel( + id = id, + name = name, + isEnabled = isEnabled, +) diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/list/model/NetworkBadQualityLineUiModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/list/model/NetworkBadQualityLineUiModel.kt new file mode 100644 index 00000000..26ecc9ee --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/list/model/NetworkBadQualityLineUiModel.kt @@ -0,0 +1,16 @@ +package io.github.openflocon.flocondesktop.features.network.badquality.list.model + +import androidx.compose.runtime.Immutable + +@Immutable +data class NetworkBadQualityLineUiModel( + val id: String, + val isEnabled: Boolean, + val name: String, +) + +fun previewNetworkBadQualityLineUiModel() = NetworkBadQualityLineUiModel( + id = "1", + isEnabled = true, + name = "the name" +) diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/list/view/BadNetworkLineView.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/list/view/BadNetworkLineView.kt new file mode 100644 index 00000000..1528ab8d --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/list/view/BadNetworkLineView.kt @@ -0,0 +1,83 @@ +package io.github.openflocon.flocondesktop.features.network.badquality.list.view + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Delete +import androidx.compose.material3.Switch +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.scale +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import io.github.openflocon.flocondesktop.features.network.badquality.list.model.NetworkBadQualityLineUiModel +import io.github.openflocon.flocondesktop.features.network.mock.edition.model.MockNetworkMethodUi +import io.github.openflocon.flocondesktop.features.network.mock.edition.view.MockNetworkMethodView +import io.github.openflocon.flocondesktop.features.network.mock.list.model.MockNetworkLineUiModel +import io.github.openflocon.library.designsystem.FloconTheme +import io.github.openflocon.library.designsystem.components.FloconIconButton +import io.github.openflocon.library.designsystem.components.FloconSurface +import org.jetbrains.compose.ui.tooling.preview.Preview + +@Composable +fun BadNetworkLineView( + item: NetworkBadQualityLineUiModel, + onClicked: (id: String) -> Unit, + onDeleteClicked: (id: String) -> Unit, + enableClicked: (id: String, enabled: Boolean) -> Unit, + modifier: Modifier = Modifier, +) { + Row( + modifier = modifier.padding(vertical = 2.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + Box(modifier = Modifier.height(12.dp)) { + Switch( + modifier = Modifier.scale(0.6f), + checked = item.isEnabled, + onCheckedChange = { + enableClicked(item.id, it) + }, + ) + } + + Row( + modifier = Modifier.fillMaxWidth() + .clickable { + onClicked(item.id) + }, + verticalAlignment = Alignment.CenterVertically, + ) { + Text( + text = item.name, + maxLines = 2, + overflow = TextOverflow.Ellipsis, + style = FloconTheme.typography.bodySmall.copy(fontSize = 11.sp), + color = FloconTheme.colorPalette.onSurface, + modifier = Modifier.weight(2f) + .background( + color = FloconTheme.colorPalette.panel.copy(alpha = 0.8f), + shape = RoundedCornerShape(4.dp), + ) + .padding(horizontal = 8.dp, vertical = 6.dp), + ) + + FloconIconButton( + imageVector = Icons.Filled.Delete, + onClick = { + onDeleteClicked(item.id) + }, + ) + } + } +} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/list/view/BadNetworkQualityWindow.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/list/view/BadNetworkQualityWindow.kt new file mode 100644 index 00000000..ae17dccc --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/list/view/BadNetworkQualityWindow.kt @@ -0,0 +1,70 @@ +@file:OptIn(ExperimentalMaterial3Api::class) + +package io.github.openflocon.flocondesktop.features.network.badquality.list + +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import io.github.openflocon.flocondesktop.features.network.badquality.BadQualityNetworkViewModel +import io.github.openflocon.flocondesktop.features.network.badquality.edition.model.BadQualityConfigUiModel +import io.github.openflocon.flocondesktop.features.network.badquality.edition.model.SelectedBadQualityUiModel +import io.github.openflocon.flocondesktop.features.network.badquality.edition.view.BadNetworkQualityEditionContent +import io.github.openflocon.flocondesktop.features.network.badquality.edition.view.BadQualityEditionWindow +import io.github.openflocon.flocondesktop.features.network.badquality.list.view.NetworkBadQualityContent +import io.github.openflocon.library.designsystem.components.FloconDialog +import org.koin.compose.viewmodel.koinViewModel + +@Composable +fun BadNetworkQualityWindow( + onCloseRequest: () -> Unit, +) { + FloconDialog( + onDismissRequest = onCloseRequest + ) { + BadNetworkQualityContent( + onCloseRequest = onCloseRequest, + ) + } +} + +@Composable +private fun BadNetworkQualityContent( + onCloseRequest: () -> Unit, +) { + val viewModel: BadQualityNetworkViewModel = koinViewModel() + val items by viewModel.items.collectAsStateWithLifecycle() + + val viewModelEvent by viewModel.events.collectAsStateWithLifecycle(null) + LaunchedEffect(viewModelEvent) { + when (viewModelEvent) { + BadQualityNetworkViewModel.Event.Close -> onCloseRequest() + null -> {} + } + } + + NetworkBadQualityContent( + lines = items, + modifier = Modifier.fillMaxSize(), + onItemClicked = viewModel::select, + onAddItemClicked = viewModel::create, + onDeleteClicked = viewModel::delete, + setEnabled = viewModel::setEnabledElement, + ) + + val selectedConfig by viewModel.selectedItem.collectAsStateWithLifecycle() + selectedConfig?.let { + BadQualityEditionWindow( + onCloseRequest = viewModel::closeEdition, + save = viewModel::save, + state = it, + ) + } +} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/list/view/NetworkMocksContent.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/list/view/NetworkMocksContent.kt new file mode 100644 index 00000000..07290311 --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/list/view/NetworkMocksContent.kt @@ -0,0 +1,80 @@ +package io.github.openflocon.flocondesktop.features.network.badquality.list.view + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.unit.dp +import io.github.openflocon.flocondesktop.features.network.badquality.list.model.NetworkBadQualityLineUiModel +import io.github.openflocon.library.designsystem.FloconTheme + +@Composable +fun NetworkBadQualityContent( + lines: List, + onItemClicked: (id: String) -> Unit, + onDeleteClicked: (id: String) -> Unit, + setEnabled: (id: String?) -> Unit, + onAddItemClicked: () -> Unit, + modifier: Modifier = Modifier, +) { + Column(modifier = modifier) { + Box( + Modifier + .fillMaxWidth() + .background(FloconTheme.colorPalette.panel) + .padding(horizontal = 12.dp, vertical = 4.dp), + ) { + Text( + text = "Bad network configs", + modifier = Modifier + .background(FloconTheme.colorPalette.panel) + .padding(all = 12.dp), + style = FloconTheme.typography.titleMedium, + color = FloconTheme.colorPalette.onSurface, + ) + Box( + modifier = Modifier.align(Alignment.CenterEnd) + .clip(RoundedCornerShape(12.dp)) + .background(FloconTheme.colorPalette.onSurface) + .clickable(onClick = onAddItemClicked) + .padding(horizontal = 8.dp, vertical = 4.dp), + ) { + Text( + "Create", + style = FloconTheme.typography.titleSmall, + color = FloconTheme.colorPalette.panel, + ) + } + } + LazyColumn( + modifier = Modifier.fillMaxSize(), + ) { + items(lines) { + BadNetworkLineView( + item = it, + onClicked = onItemClicked, + onDeleteClicked = onDeleteClicked, + enableClicked = { id, enabled -> + if(enabled) { + setEnabled(id) + } else { + setEnabled(null) + } + }, + modifier = Modifier.fillMaxWidth(), + ) + } + } + } +} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mapper/BadQualityMapper.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mapper/BadQualityMapper.kt deleted file mode 100644 index 3c608648..00000000 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mapper/BadQualityMapper.kt +++ /dev/null @@ -1,54 +0,0 @@ -package io.github.openflocon.flocondesktop.features.network.mapper - -import io.github.openflocon.domain.network.models.BadQualityConfigDomainModel -import io.github.openflocon.flocondesktop.features.network.model.badquality.BadQualityConfigUiModel - - -fun toUi(model: BadQualityConfigDomainModel?) = model?.let { - BadQualityConfigUiModel( - isEnabled = it.isEnabled, - latency = toUi(it.latency), - errorProbability = it.errorProbability, - errors = it.errors.map { error -> - toUi(error) - } - ) -} - -private fun toUi(error: BadQualityConfigDomainModel.Error) = BadQualityConfigUiModel.Error( - weight = error.weight, - httpCode = error.httpCode, - body = error.body, - contentType = error.contentType, -) - -private fun toUi(model: BadQualityConfigDomainModel.LatencyConfig) = - BadQualityConfigUiModel.LatencyConfig( - triggerProbability = model.triggerProbability, - minLatencyMs = model.minLatencyMs, - maxLatencyMs = model.maxLatencyMs, - ) - - -fun toDomain(model: BadQualityConfigUiModel) = BadQualityConfigDomainModel( - isEnabled = model.isEnabled, - latency = toDomain(model.latency), - errorProbability = model.errorProbability, - errors = model.errors.map { error -> - toDomain(error) - } -) - -private fun toDomain(error: BadQualityConfigUiModel.Error) = BadQualityConfigDomainModel.Error( - weight = error.weight, - httpCode = error.httpCode, - body = error.body, - contentType = error.contentType, -) - -private fun toDomain(model: BadQualityConfigUiModel.LatencyConfig) = - BadQualityConfigDomainModel.LatencyConfig( - triggerProbability = model.triggerProbability, - minLatencyMs = model.minLatencyMs, - maxLatencyMs = model.maxLatencyMs, - ) diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mapper/MocksMapper.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mapper/MocksMapper.kt deleted file mode 100644 index 2da86336..00000000 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mapper/MocksMapper.kt +++ /dev/null @@ -1,109 +0,0 @@ -package io.github.openflocon.flocondesktop.features.network.mapper - -import io.github.openflocon.domain.common.Either -import io.github.openflocon.domain.common.failure -import io.github.openflocon.domain.common.success -import io.github.openflocon.domain.network.models.MockNetworkDomainModel -import io.github.openflocon.flocondesktop.features.network.model.mocks.EditableMockNetworkUiModel -import io.github.openflocon.flocondesktop.features.network.model.mocks.HeaderUiModel -import io.github.openflocon.flocondesktop.features.network.model.mocks.MockNetworkLineUiModel -import io.github.openflocon.flocondesktop.features.network.model.mocks.MockNetworkMethodUi -import io.github.openflocon.flocondesktop.features.network.model.mocks.MockNetworkUiModel -import io.github.openflocon.flocondesktop.features.network.model.mocks.SelectedMockUiModel -import java.util.UUID - -fun toLineUi(mockDomain: MockNetworkDomainModel): MockNetworkLineUiModel = MockNetworkLineUiModel( - id = mockDomain.id, - isEnabled = mockDomain.isEnabled, - urlPattern = mockDomain.expectation.urlPattern, - method = toMockMethodUi(mockDomain.expectation.method), -) - -fun toDomain(uiModel: MockNetworkUiModel): MockNetworkDomainModel = MockNetworkDomainModel( - id = uiModel.id ?: UUID.randomUUID().toString(), - isEnabled = uiModel.isEnabled, - expectation = MockNetworkDomainModel.Expectation( - urlPattern = uiModel.expectation.urlPattern, - method = uiModel.expectation.method.text, - ), - response = MockNetworkDomainModel.Response( - httpCode = uiModel.response.httpCode, - body = uiModel.response.body, - mediaType = uiModel.response.mediaType, - delay = uiModel.response.delay, - headers = uiModel.response.headers, - ), -) - -fun toMockMethodUi(text: String): MockNetworkMethodUi = when (text.lowercase()) { - "get" -> MockNetworkMethodUi.GET - "post" -> MockNetworkMethodUi.POST - "put" -> MockNetworkMethodUi.PUT - "delete" -> MockNetworkMethodUi.DELETE - "patch" -> MockNetworkMethodUi.PATCH - else -> MockNetworkMethodUi.ALL -} - -fun toUi(domainModel: MockNetworkDomainModel): MockNetworkUiModel = MockNetworkUiModel( - id = domainModel.id, - expectation = MockNetworkUiModel.Expectation( - urlPattern = domainModel.expectation.urlPattern, - method = toMockMethodUi(domainModel.expectation.method), - ), - isEnabled = domainModel.isEnabled, - response = MockNetworkUiModel.Response( - httpCode = domainModel.response.httpCode, - body = domainModel.response.body, - mediaType = domainModel.response.mediaType, - delay = domainModel.response.delay, - headers = domainModel.response.headers, - ), -) - -fun createEditable(initialMock: SelectedMockUiModel): EditableMockNetworkUiModel = when (initialMock) { - is SelectedMockUiModel.Creation -> createEditable(null) - is SelectedMockUiModel.Edition -> createEditable(initialMock.existing) -} - -fun createEditable(initialMock: MockNetworkUiModel?): EditableMockNetworkUiModel = EditableMockNetworkUiModel( - id = initialMock?.id, - isEnabled = initialMock?.isEnabled ?: true, // true by default - expectation = EditableMockNetworkUiModel.Expectation( - urlPattern = initialMock?.expectation?.urlPattern, - method = initialMock?.expectation?.method ?: MockNetworkMethodUi.GET, - ), - response = EditableMockNetworkUiModel.Response( - httpCode = initialMock?.response?.httpCode ?: 200, - body = initialMock?.response?.body ?: "", - mediaType = initialMock?.response?.mediaType ?: "application/json", - delay = initialMock?.response?.delay ?: 0, - headers = initialMock?.response?.headers?.map { - HeaderUiModel( - key = it.key, - value = it.value, - ) - } ?: emptyList(), - ), -) - -fun editableToUi(editable: EditableMockNetworkUiModel): Either = try { - MockNetworkUiModel( - id = editable.id, - expectation = MockNetworkUiModel.Expectation( - urlPattern = editable.expectation.urlPattern!!, - method = editable.expectation.method, - ), - isEnabled = editable.isEnabled, - response = MockNetworkUiModel.Response( - httpCode = editable.response.httpCode, - body = editable.response.body!!, - mediaType = editable.response.mediaType, - delay = editable.response.delay, - headers = editable.response.headers.associate { - it.key to it.value - }.filterNot { it.key.isEmpty() }, - ), - ).success() -} catch (t: Throwable) { - t.failure() -} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/NetworkMocksViewModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/NetworkMocksViewModel.kt similarity index 85% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/NetworkMocksViewModel.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/NetworkMocksViewModel.kt index ce590e5c..fe08ff8b 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/NetworkMocksViewModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/NetworkMocksViewModel.kt @@ -1,8 +1,9 @@ -package io.github.openflocon.flocondesktop.features.network +package io.github.openflocon.flocondesktop.features.network.mock import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import io.github.openflocon.domain.common.DispatcherProvider +import io.github.openflocon.domain.feedback.FeedbackDisplayer import io.github.openflocon.domain.network.models.MockNetworkDomainModel import io.github.openflocon.domain.network.usecase.mocks.AddNetworkMocksUseCase import io.github.openflocon.domain.network.usecase.mocks.DeleteNetworkMocksUseCase @@ -10,13 +11,12 @@ import io.github.openflocon.domain.network.usecase.mocks.GenerateNetworkMockFrom import io.github.openflocon.domain.network.usecase.mocks.GetNetworkMockByIdUseCase import io.github.openflocon.domain.network.usecase.mocks.ObserveNetworkMocksUseCase import io.github.openflocon.domain.network.usecase.mocks.UpdateNetworkMockIsEnabledUseCase -import io.github.openflocon.domain.feedback.FeedbackDisplayer -import io.github.openflocon.flocondesktop.features.network.mapper.toDomain -import io.github.openflocon.flocondesktop.features.network.mapper.toLineUi -import io.github.openflocon.flocondesktop.features.network.mapper.toUi -import io.github.openflocon.flocondesktop.features.network.model.mocks.MockEditionWindowUiModel -import io.github.openflocon.flocondesktop.features.network.model.mocks.MockNetworkUiModel -import io.github.openflocon.flocondesktop.features.network.model.mocks.SelectedMockUiModel +import io.github.openflocon.flocondesktop.features.network.mock.edition.mapper.toDomain +import io.github.openflocon.flocondesktop.features.network.mock.edition.mapper.toUi +import io.github.openflocon.flocondesktop.features.network.mock.edition.model.MockEditionWindowUiModel +import io.github.openflocon.flocondesktop.features.network.mock.edition.model.MockNetworkUiModel +import io.github.openflocon.flocondesktop.features.network.mock.edition.model.SelectedMockUiModel +import io.github.openflocon.flocondesktop.features.network.mock.list.mapper.toLineUi import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.distinctUntilChanged @@ -39,7 +39,7 @@ class NetworkMocksViewModel( val items = observeNetworkMocksUseCase() .distinctUntilChanged() - .map { it.map { toLineUi(it) } } + .map { it.map { it.toLineUi() } } .flowOn(dispatcherProvider.viewModel) .stateIn( scope = viewModelScope, diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/edition/mapper/MocksMapper.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/edition/mapper/MocksMapper.kt new file mode 100644 index 00000000..1304cfd9 --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/edition/mapper/MocksMapper.kt @@ -0,0 +1,96 @@ +package io.github.openflocon.flocondesktop.features.network.mock.edition.mapper + +import io.github.openflocon.domain.common.Either +import io.github.openflocon.domain.common.failure +import io.github.openflocon.domain.common.success +import io.github.openflocon.domain.network.models.MockNetworkDomainModel +import io.github.openflocon.flocondesktop.features.network.mock.edition.model.EditableMockNetworkUiModel +import io.github.openflocon.flocondesktop.features.network.mock.edition.model.HeaderUiModel +import io.github.openflocon.flocondesktop.features.network.mock.edition.model.MockNetworkMethodUi +import io.github.openflocon.flocondesktop.features.network.mock.edition.model.MockNetworkUiModel +import io.github.openflocon.flocondesktop.features.network.mock.edition.model.SelectedMockUiModel +import io.github.openflocon.flocondesktop.features.network.mock.list.mapper.toMockMethodUi +import java.util.UUID + +fun toDomain(uiModel: MockNetworkUiModel): MockNetworkDomainModel = MockNetworkDomainModel( + id = uiModel.id ?: UUID.randomUUID().toString(), + isEnabled = uiModel.isEnabled, + expectation = MockNetworkDomainModel.Expectation( + urlPattern = uiModel.expectation.urlPattern, + method = uiModel.expectation.method.text, + ), + response = MockNetworkDomainModel.Response( + httpCode = uiModel.response.httpCode, + body = uiModel.response.body, + mediaType = uiModel.response.mediaType, + delay = uiModel.response.delay, + headers = uiModel.response.headers, + ), +) + +fun toUi(domainModel: MockNetworkDomainModel): MockNetworkUiModel = MockNetworkUiModel( + id = domainModel.id, + expectation = MockNetworkUiModel.Expectation( + urlPattern = domainModel.expectation.urlPattern, + method = toMockMethodUi(domainModel.expectation.method), + ), + isEnabled = domainModel.isEnabled, + response = MockNetworkUiModel.Response( + httpCode = domainModel.response.httpCode, + body = domainModel.response.body, + mediaType = domainModel.response.mediaType, + delay = domainModel.response.delay, + headers = domainModel.response.headers, + ), +) + +fun createEditable(initialMock: SelectedMockUiModel): EditableMockNetworkUiModel = + when (initialMock) { + is SelectedMockUiModel.Creation -> createEditable(null) + is SelectedMockUiModel.Edition -> createEditable(initialMock.existing) + } + +fun createEditable(initialMock: MockNetworkUiModel?): EditableMockNetworkUiModel = + EditableMockNetworkUiModel( + id = initialMock?.id, + isEnabled = initialMock?.isEnabled ?: true, // true by default + expectation = EditableMockNetworkUiModel.Expectation( + urlPattern = initialMock?.expectation?.urlPattern, + method = initialMock?.expectation?.method ?: MockNetworkMethodUi.GET, + ), + response = EditableMockNetworkUiModel.Response( + httpCode = initialMock?.response?.httpCode ?: 200, + body = initialMock?.response?.body ?: "", + mediaType = initialMock?.response?.mediaType ?: "application/json", + delay = initialMock?.response?.delay ?: 0, + headers = initialMock?.response?.headers?.map { + HeaderUiModel( + key = it.key, + value = it.value, + ) + } ?: emptyList(), + ), + ) + +fun editableToUi(editable: EditableMockNetworkUiModel): Either = + try { + MockNetworkUiModel( + id = editable.id, + expectation = MockNetworkUiModel.Expectation( + urlPattern = editable.expectation.urlPattern!!, + method = editable.expectation.method, + ), + isEnabled = editable.isEnabled, + response = MockNetworkUiModel.Response( + httpCode = editable.response.httpCode, + body = editable.response.body!!, + mediaType = editable.response.mediaType, + delay = editable.response.delay, + headers = editable.response.headers.associate { + it.key to it.value + }.filterNot { it.key.isEmpty() }, + ), + ).success() + } catch (t: Throwable) { + t.failure() + } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/model/mocks/MockNetworkResponseDomainModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/edition/model/EditableMockNetworkUiModel.kt similarity index 93% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/model/mocks/MockNetworkResponseDomainModel.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/edition/model/EditableMockNetworkUiModel.kt index 669e8b88..1d5c7dad 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/model/mocks/MockNetworkResponseDomainModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/edition/model/EditableMockNetworkUiModel.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.features.network.model.mocks +package io.github.openflocon.flocondesktop.features.network.mock.edition.model import java.util.UUID diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/model/mocks/MockEditionWindowUiModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/edition/model/MockEditionWindowUiModel.kt similarity index 79% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/model/mocks/MockEditionWindowUiModel.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/edition/model/MockEditionWindowUiModel.kt index 1270dd27..cd3242ff 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/model/mocks/MockEditionWindowUiModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/edition/model/MockEditionWindowUiModel.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.features.network.model.mocks +package io.github.openflocon.flocondesktop.features.network.mock.edition.model import androidx.compose.runtime.Immutable import kotlin.uuid.ExperimentalUuidApi diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/model/mocks/MockNetworkMethodUi.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/edition/model/MockNetworkMethodUi.kt similarity index 66% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/model/mocks/MockNetworkMethodUi.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/edition/model/MockNetworkMethodUi.kt index 67e938f8..5ba8be90 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/model/mocks/MockNetworkMethodUi.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/edition/model/MockNetworkMethodUi.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.features.network.model.mocks +package io.github.openflocon.flocondesktop.features.network.mock.edition.model enum class MockNetworkMethodUi(val text: String) { GET("GET"), diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/model/mocks/SelectedMockUiModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/edition/model/SelectedMockUiModel.kt similarity index 76% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/model/mocks/SelectedMockUiModel.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/edition/model/SelectedMockUiModel.kt index c7db85ab..c74d2bcf 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/model/mocks/SelectedMockUiModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/edition/model/SelectedMockUiModel.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.features.network.model.mocks +package io.github.openflocon.flocondesktop.features.network.mock.edition.model import androidx.compose.runtime.Immutable diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/view/mocks/MockNetworkLabelView.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/edition/view/MockNetworkLabelView.kt similarity index 88% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/view/mocks/MockNetworkLabelView.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/edition/view/MockNetworkLabelView.kt index a491a160..90aafc69 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/view/mocks/MockNetworkLabelView.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/edition/view/MockNetworkLabelView.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.features.network.view.mocks +package io.github.openflocon.flocondesktop.features.network.mock.edition.view import androidx.compose.foundation.layout.padding import androidx.compose.material3.Text diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/view/mocks/MockNetworkMethodDropdown.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/edition/view/MockNetworkMethodDropdown.kt similarity index 90% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/view/mocks/MockNetworkMethodDropdown.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/edition/view/MockNetworkMethodDropdown.kt index 24cd410b..157855dd 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/view/mocks/MockNetworkMethodDropdown.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/edition/view/MockNetworkMethodDropdown.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.features.network.view.mocks +package io.github.openflocon.flocondesktop.features.network.mock.edition.view import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -12,7 +12,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp -import io.github.openflocon.flocondesktop.features.network.model.mocks.MockNetworkMethodUi +import io.github.openflocon.flocondesktop.features.network.mock.edition.model.MockNetworkMethodUi @Composable fun MockNetworkMethodDropdown( diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/view/mocks/MockNetworkMethodView.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/edition/view/MockNetworkMethodView.kt similarity index 93% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/view/mocks/MockNetworkMethodView.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/edition/view/MockNetworkMethodView.kt index 1ed3d511..fd876476 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/view/mocks/MockNetworkMethodView.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/edition/view/MockNetworkMethodView.kt @@ -1,11 +1,11 @@ -package io.github.openflocon.flocondesktop.features.network.view.mocks +package io.github.openflocon.flocondesktop.features.network.mock.edition.view import androidx.compose.foundation.layout.PaddingValues import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import io.github.openflocon.flocondesktop.features.network.model.mocks.MockNetworkMethodUi +import io.github.openflocon.flocondesktop.features.network.mock.edition.model.MockNetworkMethodUi import io.github.openflocon.flocondesktop.features.network.view.components.NetworkTag import io.github.openflocon.flocondesktop.features.network.view.components.deleteMethodBackground import io.github.openflocon.flocondesktop.features.network.view.components.deleteMethodText diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/view/mocks/NetworkEditionWindow.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/edition/view/NetworkEditionWindow.kt similarity index 96% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/view/mocks/NetworkEditionWindow.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/edition/view/NetworkEditionWindow.kt index 9f8294a0..5fbfb3a8 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/view/mocks/NetworkEditionWindow.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/edition/view/NetworkEditionWindow.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.features.network.view.mocks +package io.github.openflocon.flocondesktop.features.network.mock.edition.view import androidx.compose.foundation.Image import androidx.compose.foundation.background @@ -39,14 +39,13 @@ import androidx.compose.ui.util.fastForEach import io.github.openflocon.flocondesktop.common.ui.window.FloconWindow import io.github.openflocon.flocondesktop.common.ui.window.FloconWindowState import io.github.openflocon.flocondesktop.common.ui.window.createFloconWindowState -import io.github.openflocon.flocondesktop.features.network.mapper.createEditable -import io.github.openflocon.flocondesktop.features.network.mapper.editableToUi -import io.github.openflocon.flocondesktop.features.network.model.mocks.HeaderUiModel -import io.github.openflocon.flocondesktop.features.network.model.mocks.MockNetworkUiModel -import io.github.openflocon.flocondesktop.features.network.model.mocks.SelectedMockUiModel +import io.github.openflocon.flocondesktop.features.network.mock.edition.mapper.createEditable +import io.github.openflocon.flocondesktop.features.network.mock.edition.mapper.editableToUi +import io.github.openflocon.flocondesktop.features.network.mock.edition.model.HeaderUiModel +import io.github.openflocon.flocondesktop.features.network.mock.edition.model.MockNetworkUiModel +import io.github.openflocon.flocondesktop.features.network.mock.edition.model.SelectedMockUiModel import io.github.openflocon.library.designsystem.FloconTheme import io.github.openflocon.library.designsystem.components.FloconSurface -import org.jetbrains.compose.ui.tooling.preview.Preview import kotlin.collections.plus @Composable diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/view/mocks/NetworkMockFieldView.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/edition/view/NetworkMockFieldView.kt similarity index 97% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/view/mocks/NetworkMockFieldView.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/edition/view/NetworkMockFieldView.kt index bfb3f090..d009fd03 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/view/mocks/NetworkMockFieldView.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/edition/view/NetworkMockFieldView.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.features.network.view.mocks +package io.github.openflocon.flocondesktop.features.network.mock.edition.view import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/list/mapper/MocksMapper.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/list/mapper/MocksMapper.kt new file mode 100644 index 00000000..708f14cd --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/list/mapper/MocksMapper.kt @@ -0,0 +1,21 @@ +package io.github.openflocon.flocondesktop.features.network.mock.list.mapper + +import io.github.openflocon.domain.network.models.MockNetworkDomainModel +import io.github.openflocon.flocondesktop.features.network.mock.edition.model.MockNetworkMethodUi +import io.github.openflocon.flocondesktop.features.network.mock.list.model.MockNetworkLineUiModel + +fun MockNetworkDomainModel.toLineUi(): MockNetworkLineUiModel = MockNetworkLineUiModel( + id = id, + isEnabled = isEnabled, + urlPattern = expectation.urlPattern, + method = toMockMethodUi(expectation.method), +) + +fun toMockMethodUi(text: String): MockNetworkMethodUi = when (text.lowercase()) { + "get" -> MockNetworkMethodUi.GET + "post" -> MockNetworkMethodUi.POST + "put" -> MockNetworkMethodUi.PUT + "delete" -> MockNetworkMethodUi.DELETE + "patch" -> MockNetworkMethodUi.PATCH + else -> MockNetworkMethodUi.ALL +} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/model/mocks/MockNetworkLineUiModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/list/model/MockNetworkLineUiModel.kt similarity index 70% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/model/mocks/MockNetworkLineUiModel.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/list/model/MockNetworkLineUiModel.kt index d2801e5e..9fa9ee08 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/model/mocks/MockNetworkLineUiModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/list/model/MockNetworkLineUiModel.kt @@ -1,6 +1,7 @@ -package io.github.openflocon.flocondesktop.features.network.model.mocks +package io.github.openflocon.flocondesktop.features.network.mock.list.model import androidx.compose.runtime.Immutable +import io.github.openflocon.flocondesktop.features.network.mock.edition.model.MockNetworkMethodUi @Immutable data class MockNetworkLineUiModel( diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/view/mocks/MockLineView.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/list/view/MockLineView.kt similarity index 92% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/view/mocks/MockLineView.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/list/view/MockLineView.kt index 4dab4b30..754dff4f 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/view/mocks/MockLineView.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/list/view/MockLineView.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.features.network.view.mocks +package io.github.openflocon.flocondesktop.features.network.mock.list.view import androidx.compose.foundation.background import androidx.compose.foundation.clickable @@ -20,8 +20,9 @@ import androidx.compose.ui.draw.scale import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import io.github.openflocon.flocondesktop.features.network.model.mocks.MockNetworkLineUiModel -import io.github.openflocon.flocondesktop.features.network.model.mocks.MockNetworkMethodUi +import io.github.openflocon.flocondesktop.features.network.mock.edition.model.MockNetworkMethodUi +import io.github.openflocon.flocondesktop.features.network.mock.edition.view.MockNetworkMethodView +import io.github.openflocon.flocondesktop.features.network.mock.list.model.MockNetworkLineUiModel import io.github.openflocon.library.designsystem.FloconTheme import io.github.openflocon.library.designsystem.components.FloconIconButton import io.github.openflocon.library.designsystem.components.FloconSurface diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/view/mocks/NetworkMocksScreen.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/list/view/NetworkMocksScreen.kt similarity index 91% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/view/mocks/NetworkMocksScreen.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/list/view/NetworkMocksScreen.kt index 56daca68..96264e0f 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/view/mocks/NetworkMocksScreen.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/list/view/NetworkMocksScreen.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.features.network.view.mocks +package io.github.openflocon.flocondesktop.features.network.mock.list.view import androidx.compose.foundation.background import androidx.compose.foundation.clickable @@ -22,9 +22,10 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import io.github.openflocon.flocondesktop.features.network.NetworkMocksViewModel -import io.github.openflocon.flocondesktop.features.network.model.mocks.MockNetworkLineUiModel -import io.github.openflocon.flocondesktop.features.network.model.mocks.previewMockNetworkLineUiModel +import io.github.openflocon.flocondesktop.features.network.mock.NetworkMocksViewModel +import io.github.openflocon.flocondesktop.features.network.mock.edition.view.NetworkEditionWindow +import io.github.openflocon.flocondesktop.features.network.mock.list.model.MockNetworkLineUiModel +import io.github.openflocon.flocondesktop.features.network.mock.list.model.previewMockNetworkLineUiModel import io.github.openflocon.library.designsystem.FloconTheme import io.github.openflocon.library.designsystem.components.FloconSurface import org.jetbrains.compose.ui.tooling.preview.Preview diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/view/NetworkScreen.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/view/NetworkScreen.kt index 66401576..ee085187 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/view/NetworkScreen.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/view/NetworkScreen.kt @@ -33,10 +33,10 @@ import io.github.openflocon.flocondesktop.features.network.model.NetworkItemView import io.github.openflocon.flocondesktop.features.network.model.previewGraphQlItemViewState import io.github.openflocon.flocondesktop.features.network.model.previewNetworkItemViewState import io.github.openflocon.flocondesktop.features.network.previewNetworkUiState -import io.github.openflocon.flocondesktop.features.network.view.badquality.BadNetworkQualityWindow +import io.github.openflocon.flocondesktop.features.network.badquality.list.BadNetworkQualityWindow import io.github.openflocon.flocondesktop.features.network.view.header.NetworkFilter import io.github.openflocon.flocondesktop.features.network.view.header.NetworkItemHeaderView -import io.github.openflocon.flocondesktop.features.network.view.mocks.NetworkMocksWindow +import io.github.openflocon.flocondesktop.features.network.mock.list.view.NetworkMocksWindow import io.github.openflocon.library.designsystem.FloconTheme import io.github.openflocon.library.designsystem.components.FloconPanel import io.github.openflocon.library.designsystem.components.FloconSurface diff --git a/FloconDesktop/data/core/src/commonMain/kotlin/io/github/openflocon/data/core/network/datasource/NetworkQualityLocalDataSource.kt b/FloconDesktop/data/core/src/commonMain/kotlin/io/github/openflocon/data/core/network/datasource/NetworkQualityLocalDataSource.kt index 0e1a1547..d25dfc33 100644 --- a/FloconDesktop/data/core/src/commonMain/kotlin/io/github/openflocon/data/core/network/datasource/NetworkQualityLocalDataSource.kt +++ b/FloconDesktop/data/core/src/commonMain/kotlin/io/github/openflocon/data/core/network/datasource/NetworkQualityLocalDataSource.kt @@ -2,6 +2,7 @@ package io.github.openflocon.data.core.network.datasource import io.github.openflocon.domain.device.models.DeviceIdAndPackageNameDomainModel import io.github.openflocon.domain.network.models.BadQualityConfigDomainModel +import io.github.openflocon.domain.network.models.BadQualityConfigId import kotlinx.coroutines.flow.Flow interface NetworkQualityLocalDataSource { @@ -10,15 +11,32 @@ interface NetworkQualityLocalDataSource { config: BadQualityConfigDomainModel ) - suspend fun getNetworkQuality(deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel) : BadQualityConfigDomainModel? + suspend fun getNetworkQuality( + deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel, + configId: BadQualityConfigId, + ) : BadQualityConfigDomainModel? fun observe( deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel, + configId: BadQualityConfigId, ): Flow - suspend fun updateIsEnabled( + suspend fun delete( deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel, - isEnabled: Boolean, + configId: BadQualityConfigId, ) + fun observeAll( + deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel, + ): Flow> + + suspend fun setEnabledConfig( + deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel, + configId: BadQualityConfigId?, + ) + + suspend fun getTheOnlyEnabledNetworkQuality( + deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel + ): BadQualityConfigDomainModel? + } diff --git a/FloconDesktop/data/core/src/commonMain/kotlin/io/github/openflocon/data/core/network/repository/NetworkRepositoryImpl.kt b/FloconDesktop/data/core/src/commonMain/kotlin/io/github/openflocon/data/core/network/repository/NetworkRepositoryImpl.kt index 377985ff..a9292b79 100644 --- a/FloconDesktop/data/core/src/commonMain/kotlin/io/github/openflocon/data/core/network/repository/NetworkRepositoryImpl.kt +++ b/FloconDesktop/data/core/src/commonMain/kotlin/io/github/openflocon/data/core/network/repository/NetworkRepositoryImpl.kt @@ -10,8 +10,8 @@ import io.github.openflocon.domain.device.models.DeviceIdAndPackageNameDomainMod import io.github.openflocon.domain.messages.models.FloconIncomingMessageDomainModel import io.github.openflocon.domain.messages.repository.MessagesReceiverRepository import io.github.openflocon.domain.network.models.BadQualityConfigDomainModel +import io.github.openflocon.domain.network.models.BadQualityConfigId import io.github.openflocon.domain.network.models.FloconNetworkCallDomainModel -import io.github.openflocon.domain.network.models.FloconNetworkResponseDomainModel import io.github.openflocon.domain.network.models.FloconNetworkResponseOnlyDomainModel import io.github.openflocon.domain.network.models.MockNetworkDomainModel import io.github.openflocon.domain.network.repository.NetworkBadQualityRepository @@ -295,30 +295,62 @@ class NetworkRepositoryImpl( } } - override suspend fun getNetworkQuality(deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel): BadQualityConfigDomainModel? { + override suspend fun getNetworkQuality( + deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel, + configId: BadQualityConfigId, + ): BadQualityConfigDomainModel? { return withContext(dispatcherProvider.data) { networkQualityLocalDataSource.getNetworkQuality( deviceIdAndPackageName = deviceIdAndPackageName, + configId = configId, + ) + } + } + + override suspend fun getTheOnlyEnabledNetworkQuality(deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel): BadQualityConfigDomainModel? { + return withContext(dispatcherProvider.data) { + networkQualityLocalDataSource.getTheOnlyEnabledNetworkQuality( + deviceIdAndPackageName = deviceIdAndPackageName, + ) + } + } + + override suspend fun deleteNetworkQuality( + deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel, + configId: BadQualityConfigId, + ) { + return withContext(dispatcherProvider.data) { + networkQualityLocalDataSource.delete( + deviceIdAndPackageName = deviceIdAndPackageName, + configId = configId, ) } } override fun observeNetworkQuality( deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel, + configId: BadQualityConfigId, ): Flow { return networkQualityLocalDataSource.observe( deviceIdAndPackageName = deviceIdAndPackageName, - ) + configId = configId, + ).flowOn(dispatcherProvider.data) } - override suspend fun setNetworkQualityIsEnabled( + override fun observeAllNetworkQualities(deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel): Flow> { + return networkQualityLocalDataSource.observeAll( + deviceIdAndPackageName = deviceIdAndPackageName, + ).flowOn(dispatcherProvider.data) + } + + override suspend fun setEnabledConfig( deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel, - isEnabled: Boolean, + configId: BadQualityConfigId?, ) { withContext(dispatcherProvider.data) { - networkQualityLocalDataSource.updateIsEnabled( + networkQualityLocalDataSource.setEnabledConfig( deviceIdAndPackageName = deviceIdAndPackageName, - isEnabled = isEnabled, + configId = configId, ) } } diff --git a/FloconDesktop/data/local/src/commonMain/kotlin/io/github/openflocon/data/local/network/dao/NetworkBadQualityConfigDao.kt b/FloconDesktop/data/local/src/commonMain/kotlin/io/github/openflocon/data/local/network/dao/NetworkBadQualityConfigDao.kt index b52e1989..0f1ea445 100644 --- a/FloconDesktop/data/local/src/commonMain/kotlin/io/github/openflocon/data/local/network/dao/NetworkBadQualityConfigDao.kt +++ b/FloconDesktop/data/local/src/commonMain/kotlin/io/github/openflocon/data/local/network/dao/NetworkBadQualityConfigDao.kt @@ -5,6 +5,7 @@ import androidx.room.Insert import androidx.room.OnConflictStrategy import androidx.room.Query import io.github.openflocon.data.local.network.models.badquality.BadQualityConfigEntity +import io.github.openflocon.domain.device.models.DeviceId import kotlinx.coroutines.flow.Flow @Dao @@ -16,24 +17,57 @@ interface NetworkBadQualityConfigDao { SELECT * FROM BadQualityConfigEntity WHERE deviceId = :deviceId AND packageName = :packageName + AND id = :configId LIMIT 1 """) - suspend fun get(deviceId: String, packageName: String): BadQualityConfigEntity? - + suspend fun get(deviceId: String, packageName: String, configId: String): BadQualityConfigEntity? @Query(""" SELECT * FROM BadQualityConfigEntity WHERE deviceId = :deviceId AND packageName = :packageName + AND isEnabled = 1 LIMIT 1 """) - fun observe(deviceId: String, packageName: String): Flow + suspend fun getTheOnlyEnabledNetworkQuality(deviceId: DeviceId, packageName: String) : BadQualityConfigEntity? + + @Query(""" + SELECT * + FROM BadQualityConfigEntity + WHERE deviceId = :deviceId AND packageName = :packageName + AND id = :configId + LIMIT 1 + """) + fun observe(deviceId: String, packageName: String, configId: String): Flow + + @Query(""" + SELECT * + FROM BadQualityConfigEntity + WHERE deviceId = :deviceId AND packageName = :packageName + ORDER BY createdAt + """) + fun observeAll(deviceId: String, packageName: String): Flow> @Query(""" UPDATE BadQualityConfigEntity - SET isEnabled = :isEnabled + SET isEnabled = CASE + WHEN id = :configId THEN 1 + ELSE 0 + END WHERE deviceId = :deviceId AND packageName = :packageName """) - suspend fun updateIsEnabled(deviceId: String, packageName: String, isEnabled: Boolean) + suspend fun setEnabledConfig( + deviceId: String, + packageName: String, + configId: String?, + ) + + @Query(""" + DELETE FROM BadQualityConfigEntity + WHERE deviceId = :deviceId AND packageName = :packageName + AND id = :configId + """ + ) + suspend fun delete(deviceId: DeviceId, packageName: String, configId: String) } diff --git a/FloconDesktop/data/local/src/commonMain/kotlin/io/github/openflocon/data/local/network/datasource/BadQualityConfigLocalDataSourceImpl.kt b/FloconDesktop/data/local/src/commonMain/kotlin/io/github/openflocon/data/local/network/datasource/BadQualityConfigLocalDataSourceImpl.kt index a33066a6..52c1d370 100644 --- a/FloconDesktop/data/local/src/commonMain/kotlin/io/github/openflocon/data/local/network/datasource/BadQualityConfigLocalDataSourceImpl.kt +++ b/FloconDesktop/data/local/src/commonMain/kotlin/io/github/openflocon/data/local/network/datasource/BadQualityConfigLocalDataSourceImpl.kt @@ -6,6 +6,7 @@ import io.github.openflocon.data.local.network.mapper.toDomain import io.github.openflocon.data.local.network.mapper.toEntity import io.github.openflocon.domain.device.models.DeviceIdAndPackageNameDomainModel import io.github.openflocon.domain.network.models.BadQualityConfigDomainModel +import io.github.openflocon.domain.network.models.BadQualityConfigId import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.map @@ -29,10 +30,14 @@ class BadQualityConfigLocalDataSourceImpl( ) } - override suspend fun getNetworkQuality(deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel): BadQualityConfigDomainModel? { + override suspend fun getNetworkQuality( + deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel, + configId: BadQualityConfigId, + ): BadQualityConfigDomainModel? { return networkBadQualityConfigDao.get( deviceId = deviceIdAndPackageName.deviceId, - packageName = deviceIdAndPackageName.packageName + packageName = deviceIdAndPackageName.packageName, + configId = configId )?.let { toDomain( json = json, @@ -42,11 +47,13 @@ class BadQualityConfigLocalDataSourceImpl( } override fun observe( - deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel + deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel, + configId: BadQualityConfigId, ): Flow { return networkBadQualityConfigDao.observe( deviceId = deviceIdAndPackageName.deviceId, - packageName = deviceIdAndPackageName.packageName + packageName = deviceIdAndPackageName.packageName, + configId = configId, ).map { it?.let { toDomain( @@ -57,14 +64,56 @@ class BadQualityConfigLocalDataSourceImpl( }.distinctUntilChanged() } - override suspend fun updateIsEnabled( + + override fun observeAll( deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel, - isEnabled: Boolean, - ) { - networkBadQualityConfigDao.updateIsEnabled( + ): Flow> { + return networkBadQualityConfigDao.observeAll( deviceId = deviceIdAndPackageName.deviceId, packageName = deviceIdAndPackageName.packageName, - isEnabled = isEnabled + ).map { list -> + list.map { + toDomain( + json = json, + entity = it + ) + } + }.distinctUntilChanged() + } + + override suspend fun setEnabledConfig( + deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel, + configId: BadQualityConfigId?, + ) { + networkBadQualityConfigDao.setEnabledConfig( + deviceId = deviceIdAndPackageName.deviceId, + packageName = deviceIdAndPackageName.packageName, + configId = configId, + ) + } + + override suspend fun getTheOnlyEnabledNetworkQuality( + deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel, + ): BadQualityConfigDomainModel? { + return networkBadQualityConfigDao.getTheOnlyEnabledNetworkQuality( + deviceId = deviceIdAndPackageName.deviceId, + packageName = deviceIdAndPackageName.packageName, + )?.let { + toDomain( + json = json, + entity = it + ) + } + } + + override suspend fun delete( + deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel, + configId: BadQualityConfigId + ) { + networkBadQualityConfigDao.delete( + deviceId = deviceIdAndPackageName.deviceId, + packageName = deviceIdAndPackageName.packageName, + configId = configId ) } } diff --git a/FloconDesktop/data/local/src/commonMain/kotlin/io/github/openflocon/data/local/network/mapper/BadQualityMapper.kt b/FloconDesktop/data/local/src/commonMain/kotlin/io/github/openflocon/data/local/network/mapper/BadQualityMapper.kt index a04eca6f..86102705 100644 --- a/FloconDesktop/data/local/src/commonMain/kotlin/io/github/openflocon/data/local/network/mapper/BadQualityMapper.kt +++ b/FloconDesktop/data/local/src/commonMain/kotlin/io/github/openflocon/data/local/network/mapper/BadQualityMapper.kt @@ -6,6 +6,7 @@ import io.github.openflocon.data.local.network.models.badquality.LatencyConfigEm import io.github.openflocon.domain.device.models.DeviceIdAndPackageNameDomainModel import io.github.openflocon.domain.network.models.BadQualityConfigDomainModel import kotlinx.serialization.json.Json +import kotlin.time.Instant fun toDomain(json: Json, entity: BadQualityConfigEntity): BadQualityConfigDomainModel { val errors = try { @@ -16,6 +17,9 @@ fun toDomain(json: Json, entity: BadQualityConfigEntity): BadQualityConfigDomain emptyList() } return BadQualityConfigDomainModel( + id = entity.id, + name = entity.name, + createdAt = Instant.fromEpochMilliseconds(entity.createdAt), isEnabled = entity.isEnabled, latency = BadQualityConfigDomainModel.LatencyConfig( triggerProbability = entity.latency.triggerProbability, @@ -52,6 +56,9 @@ fun toEntity( "[]" } return BadQualityConfigEntity( + id = config.id, + name = config.name, + createdAt = config.createdAt.toEpochMilliseconds(), deviceId = deviceIdAndPackageName.deviceId, packageName = deviceIdAndPackageName.packageName, isEnabled = config.isEnabled, diff --git a/FloconDesktop/data/local/src/commonMain/kotlin/io/github/openflocon/data/local/network/models/badquality/BadQualityConfigEntity.kt b/FloconDesktop/data/local/src/commonMain/kotlin/io/github/openflocon/data/local/network/models/badquality/BadQualityConfigEntity.kt index 83b9e938..0fc3da88 100644 --- a/FloconDesktop/data/local/src/commonMain/kotlin/io/github/openflocon/data/local/network/models/badquality/BadQualityConfigEntity.kt +++ b/FloconDesktop/data/local/src/commonMain/kotlin/io/github/openflocon/data/local/network/models/badquality/BadQualityConfigEntity.kt @@ -2,10 +2,19 @@ package io.github.openflocon.data.local.network.models.badquality import androidx.room.Embedded import androidx.room.Entity +import androidx.room.Index +import androidx.room.PrimaryKey -@Entity(primaryKeys = ["deviceId", "packageName"]) +@Entity( + indices = [ + Index(value = ["deviceId", "packageName"]), + ], +) data class BadQualityConfigEntity( + @PrimaryKey val id: String, + val name: String, val deviceId: String, + val createdAt: Long, val packageName: String, val isEnabled: Boolean, @Embedded val latency: LatencyConfigEmbedded, diff --git a/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/DI.kt b/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/DI.kt index f955ff93..705d7906 100644 --- a/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/DI.kt +++ b/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/DI.kt @@ -9,10 +9,12 @@ import io.github.openflocon.domain.network.usecase.RemoveHttpRequestUseCase import io.github.openflocon.domain.network.usecase.RemoveHttpRequestsBeforeUseCase import io.github.openflocon.domain.network.usecase.ResetCurrentDeviceHttpRequestsUseCase import io.github.openflocon.domain.network.usecase.UpdateNetworkFilterUseCase +import io.github.openflocon.domain.network.usecase.badquality.DeleteBadQualityUseCase +import io.github.openflocon.domain.network.usecase.badquality.ObserveAllNetworkBadQualitiesUseCase import io.github.openflocon.domain.network.usecase.badquality.ObserveNetworkBadQualityUseCase import io.github.openflocon.domain.network.usecase.badquality.SaveNetworkBadQualityUseCase import io.github.openflocon.domain.network.usecase.badquality.SetupNetworkBadQualityUseCase -import io.github.openflocon.domain.network.usecase.badquality.UpdateNetworkBadQualityIsEnabledUseCase +import io.github.openflocon.domain.network.usecase.badquality.SetNetworkBadQualityEnabledConfigUseCase import io.github.openflocon.domain.network.usecase.mocks.AddNetworkMocksUseCase import io.github.openflocon.domain.network.usecase.mocks.DeleteNetworkMocksUseCase import io.github.openflocon.domain.network.usecase.mocks.GenerateNetworkMockFromNetworkCallUseCase @@ -45,6 +47,8 @@ internal val networkModule = module { // bad quality factoryOf(::ObserveNetworkBadQualityUseCase) factoryOf(::SaveNetworkBadQualityUseCase) + factoryOf(::DeleteBadQualityUseCase) factoryOf(::SetupNetworkBadQualityUseCase) - factoryOf(::UpdateNetworkBadQualityIsEnabledUseCase) + factoryOf(::SetNetworkBadQualityEnabledConfigUseCase) + factoryOf(::ObserveAllNetworkBadQualitiesUseCase) } diff --git a/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/models/BadQualityConfigDomainModel.kt b/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/models/BadQualityConfigDomainModel.kt index 0ac66ab2..b0c6a89c 100644 --- a/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/models/BadQualityConfigDomainModel.kt +++ b/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/models/BadQualityConfigDomainModel.kt @@ -1,7 +1,14 @@ package io.github.openflocon.domain.network.models +import kotlin.time.Instant + +typealias BadQualityConfigId = String + data class BadQualityConfigDomainModel( + val id: BadQualityConfigId, val isEnabled: Boolean, + val name: String, + val createdAt: Instant, val latency: LatencyConfig, val errorProbability: Double, // chance of triggering an error val errors: List, // list of errors diff --git a/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/repository/NetworkBadQualityRepository.kt b/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/repository/NetworkBadQualityRepository.kt index 6d570e39..b045a612 100644 --- a/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/repository/NetworkBadQualityRepository.kt +++ b/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/repository/NetworkBadQualityRepository.kt @@ -2,6 +2,7 @@ package io.github.openflocon.domain.network.repository import io.github.openflocon.domain.device.models.DeviceIdAndPackageNameDomainModel import io.github.openflocon.domain.network.models.BadQualityConfigDomainModel +import io.github.openflocon.domain.network.models.BadQualityConfigId import kotlinx.coroutines.flow.Flow interface NetworkBadQualityRepository { @@ -19,14 +20,29 @@ interface NetworkBadQualityRepository { suspend fun getNetworkQuality( deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel, + configId: BadQualityConfigId, ) : BadQualityConfigDomainModel? + suspend fun getTheOnlyEnabledNetworkQuality( + deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel, + ) : BadQualityConfigDomainModel? + + suspend fun deleteNetworkQuality( + deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel, + configId: BadQualityConfigId, + ) + fun observeNetworkQuality( deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel, + configId: BadQualityConfigId, ) : Flow - suspend fun setNetworkQualityIsEnabled( + fun observeAllNetworkQualities( deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel, - isEnabled: Boolean, + ) : Flow> + + suspend fun setEnabledConfig( + deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel, + configId: BadQualityConfigId?, ) } diff --git a/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/usecase/badquality/UpdateNetworkBadQualityIsEnabledUseCase.kt b/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/usecase/badquality/DeleteBadQualityUseCase.kt similarity index 77% rename from FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/usecase/badquality/UpdateNetworkBadQualityIsEnabledUseCase.kt rename to FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/usecase/badquality/DeleteBadQualityUseCase.kt index 294b4d2f..550c86a4 100644 --- a/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/usecase/badquality/UpdateNetworkBadQualityIsEnabledUseCase.kt +++ b/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/usecase/badquality/DeleteBadQualityUseCase.kt @@ -2,18 +2,19 @@ package io.github.openflocon.domain.network.usecase.badquality import io.github.openflocon.domain.device.usecase.GetCurrentDeviceIdAndPackageNameUseCase import io.github.openflocon.domain.network.models.BadQualityConfigDomainModel +import io.github.openflocon.domain.network.models.BadQualityConfigId import io.github.openflocon.domain.network.repository.NetworkBadQualityRepository import io.github.openflocon.domain.network.repository.NetworkMocksRepository -class UpdateNetworkBadQualityIsEnabledUseCase( +class DeleteBadQualityUseCase( private val getCurrentDeviceIdAndPackageNameUseCase: GetCurrentDeviceIdAndPackageNameUseCase, private val networkBadQualityRepository: NetworkBadQualityRepository, private val setupNetworkBadQualityUseCase: SetupNetworkBadQualityUseCase, ) { - suspend operator fun invoke(isEnabled: Boolean) { + suspend operator fun invoke(configId: BadQualityConfigId) { getCurrentDeviceIdAndPackageNameUseCase()?.let { deviceIdAndPackageName -> - networkBadQualityRepository.setNetworkQualityIsEnabled( - isEnabled = isEnabled, + networkBadQualityRepository.deleteNetworkQuality( + configId = configId, deviceIdAndPackageName = deviceIdAndPackageName, ) // then send to device diff --git a/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/usecase/badquality/ObserveAllNetworkBadQualitiesUseCase.kt b/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/usecase/badquality/ObserveAllNetworkBadQualitiesUseCase.kt new file mode 100644 index 00000000..aa9f9cb6 --- /dev/null +++ b/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/usecase/badquality/ObserveAllNetworkBadQualitiesUseCase.kt @@ -0,0 +1,27 @@ +package io.github.openflocon.domain.network.usecase.badquality + +import io.github.openflocon.domain.device.usecase.ObserveCurrentDeviceIdAndPackageNameUseCase +import io.github.openflocon.domain.network.models.BadQualityConfigDomainModel +import io.github.openflocon.domain.network.repository.NetworkBadQualityRepository +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flowOf + +class ObserveAllNetworkBadQualitiesUseCase( + private val networkBadQualityRepository: NetworkBadQualityRepository, + private val observeCurrentDeviceIdAndPackageNameUseCase: ObserveCurrentDeviceIdAndPackageNameUseCase, +) { + operator fun invoke(): Flow> = + observeCurrentDeviceIdAndPackageNameUseCase() + .flatMapLatest { current -> + if (current == null) { + flowOf(emptyList()) + } else { + networkBadQualityRepository.observeAllNetworkQualities( + deviceIdAndPackageName = current, + ) + } + } + .distinctUntilChanged() +} diff --git a/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/usecase/badquality/ObserveNetworkBadQualityUseCase.kt b/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/usecase/badquality/ObserveNetworkBadQualityUseCase.kt index 71aac617..c42c4bdc 100644 --- a/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/usecase/badquality/ObserveNetworkBadQualityUseCase.kt +++ b/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/usecase/badquality/ObserveNetworkBadQualityUseCase.kt @@ -2,6 +2,7 @@ package io.github.openflocon.domain.network.usecase.badquality import io.github.openflocon.domain.device.usecase.ObserveCurrentDeviceIdAndPackageNameUseCase import io.github.openflocon.domain.network.models.BadQualityConfigDomainModel +import io.github.openflocon.domain.network.models.BadQualityConfigId import io.github.openflocon.domain.network.models.MockNetworkDomainModel import io.github.openflocon.domain.network.repository.NetworkBadQualityRepository import io.github.openflocon.domain.network.repository.NetworkMocksRepository @@ -14,13 +15,18 @@ class ObserveNetworkBadQualityUseCase( private val networkBadQualityRepository: NetworkBadQualityRepository, private val observeCurrentDeviceIdAndPackageNameUseCase: ObserveCurrentDeviceIdAndPackageNameUseCase, ) { - operator fun invoke(): Flow = + operator fun invoke( + configId: BadQualityConfigId, + ): Flow = observeCurrentDeviceIdAndPackageNameUseCase() .flatMapLatest { current -> if (current == null) { flowOf(null) } else { - networkBadQualityRepository.observeNetworkQuality(deviceIdAndPackageName = current) + networkBadQualityRepository.observeNetworkQuality( + deviceIdAndPackageName = current, + configId = configId, + ) } } .distinctUntilChanged() diff --git a/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/usecase/badquality/SetNetworkBadQualityEnabledConfigUseCase.kt b/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/usecase/badquality/SetNetworkBadQualityEnabledConfigUseCase.kt new file mode 100644 index 00000000..f71835d6 --- /dev/null +++ b/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/usecase/badquality/SetNetworkBadQualityEnabledConfigUseCase.kt @@ -0,0 +1,24 @@ +package io.github.openflocon.domain.network.usecase.badquality + +import io.github.openflocon.domain.device.usecase.GetCurrentDeviceIdAndPackageNameUseCase +import io.github.openflocon.domain.network.models.BadQualityConfigId +import io.github.openflocon.domain.network.repository.NetworkBadQualityRepository + +class SetNetworkBadQualityEnabledConfigUseCase( + private val getCurrentDeviceIdAndPackageNameUseCase: GetCurrentDeviceIdAndPackageNameUseCase, + private val networkBadQualityRepository: NetworkBadQualityRepository, + private val setupNetworkBadQualityUseCase: SetupNetworkBadQualityUseCase, +) { + suspend operator fun invoke( + configId: BadQualityConfigId?, // null to enable none + ) { + getCurrentDeviceIdAndPackageNameUseCase()?.let { deviceIdAndPackageName -> + networkBadQualityRepository.setEnabledConfig( + configId = configId, + deviceIdAndPackageName = deviceIdAndPackageName, + ) + // then send to device + setupNetworkBadQualityUseCase() + } + } +} diff --git a/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/usecase/badquality/SetupNetworkBadQualityUseCase.kt b/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/usecase/badquality/SetupNetworkBadQualityUseCase.kt index 690ccd99..828fe88a 100644 --- a/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/usecase/badquality/SetupNetworkBadQualityUseCase.kt +++ b/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/usecase/badquality/SetupNetworkBadQualityUseCase.kt @@ -11,7 +11,9 @@ class SetupNetworkBadQualityUseCase( suspend operator fun invoke() { getCurrentDeviceIdAndPackageNameUseCase()?.let { deviceIdAndPackageName -> networkBadQualityRepository.setupBadNetworkQuality( - config = networkBadQualityRepository.getNetworkQuality(deviceIdAndPackageName), + config = networkBadQualityRepository.getTheOnlyEnabledNetworkQuality( + deviceIdAndPackageName = deviceIdAndPackageName, + ), deviceIdAndPackageName = deviceIdAndPackageName, ) }