diff --git a/FloconDesktop/composeApp/src/androidMain/kotlin/io/github/openflocon/flocondesktop/common/ui/window/FloconWindow.android.kt b/FloconDesktop/composeApp/src/androidMain/kotlin/io/github/openflocon/flocondesktop/common/ui/window/FloconWindow.android.kt index 37c28c7a..fbfd676f 100644 --- a/FloconDesktop/composeApp/src/androidMain/kotlin/io/github/openflocon/flocondesktop/common/ui/window/FloconWindow.android.kt +++ b/FloconDesktop/composeApp/src/androidMain/kotlin/io/github/openflocon/flocondesktop/common/ui/window/FloconWindow.android.kt @@ -1,8 +1,11 @@ package io.github.openflocon.flocondesktop.common.ui.window import androidx.compose.runtime.Composable +import androidx.compose.ui.unit.DpSize -actual fun createFloconWindowState(): FloconWindowState { +actual fun createFloconWindowState( + size: DpSize?, +): FloconWindowState { TODO("Not yet implemented") } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/common/ui/window/FloconWindow.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/common/ui/window/FloconWindow.kt index 03d3d156..567fd291 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/common/ui/window/FloconWindow.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/common/ui/window/FloconWindow.kt @@ -1,10 +1,16 @@ package io.github.openflocon.flocondesktop.common.ui.window import androidx.compose.runtime.Composable +import androidx.compose.ui.unit.DpSize +import androidx.compose.ui.unit.dp interface FloconWindowState -expect fun createFloconWindowState(): FloconWindowState +val defaultWindowSize = DpSize(800.dp, 600.dp) + +expect fun createFloconWindowState( + size: DpSize? = null, +): FloconWindowState @Composable expect fun FloconWindow( diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/edition/view/BadQuaityErrorExceptionEditor.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/edition/view/BadQuaityErrorExceptionEditor.kt index 9703c92f..f9ee4b2b 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/edition/view/BadQuaityErrorExceptionEditor.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/edition/view/BadQuaityErrorExceptionEditor.kt @@ -1,72 +1,91 @@ package io.github.openflocon.flocondesktop.features.network.badquality.edition.view -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp -import androidx.compose.ui.util.fastForEach import io.github.openflocon.flocondesktop.features.network.badquality.edition.model.BadQualityConfigUiModel -import io.github.openflocon.flocondesktop.features.network.badquality.edition.model.possibleExceptions import io.github.openflocon.library.designsystem.FloconTheme +import io.github.openflocon.library.designsystem.components.DefaultLabel +import io.github.openflocon.library.designsystem.components.FloconDialogButtons +import io.github.openflocon.library.designsystem.components.FloconDialogHeader +import io.github.openflocon.library.designsystem.components.FloconTextField +import io.github.openflocon.library.designsystem.components.defaultLabel +import io.github.openflocon.library.designsystem.components.defaultPlaceHolder @Composable fun BadQuaityErrorExceptionEditor( error: BadQualityConfigUiModel.Error, errorException: BadQualityConfigUiModel.Error.Type.Exception, - onErrorsChange: (BadQualityConfigUiModel.Error) -> Unit, + save: (BadQualityConfigUiModel.Error) -> Unit, + cancel: () -> Unit, ) { + var weight by remember(error) { mutableStateOf(error.weight.toString()) } + var errorClassPath by remember(error) { mutableStateOf(errorException.classPath) } + Column( - modifier = Modifier.padding(all = 8.dp), - verticalArrangement = Arrangement.spacedBy(4.dp) + modifier = Modifier.fillMaxWidth() ) { - possibleExceptions.fastForEach { exception -> - val (backgroundColor, textColor) = if (exception.classPath == errorException.classPath) { - FloconTheme.colorPalette.onSurface to FloconTheme.colorPalette.panel - } else { - FloconTheme.colorPalette.panel to FloconTheme.colorPalette.onSurface - } + FloconDialogHeader( + title = "Exception", + modifier = Modifier.fillMaxWidth(), + ) + Column( + modifier = Modifier.padding(all = 8.dp), + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + + FloconTextField( + label = defaultLabel("Weight"), + placeholder = defaultPlaceHolder("eg: 1.0"), + value = weight, + onValueChange = { + if (it.isEmpty() || it.toFloatOrNull() != null) { + weight = it + } + }, + containerColor = FloconTheme.colorPalette.panel + ) + + DefaultLabel("Select the exception") + Column( - modifier = Modifier - .clip(RoundedCornerShape(8.dp)) - .background( - color = backgroundColor, - ) - .then( - Modifier.clickable( - onClick = { - onErrorsChange( - error.copy( - weight = 1f, - type = errorException.copy( - classPath = exception.classPath - ) - ) - ) - }, - ) - ).padding(all = 8.dp) + modifier = Modifier.fillMaxWidth(), + verticalArrangement = Arrangement.spacedBy(4.dp) ) { - Text( - text = exception.description, - style = FloconTheme.typography.bodySmall, - color = textColor, - ) - Text( - text = exception.classPath, - style = FloconTheme.typography.bodyMedium.copy( - fontWeight = FontWeight.Bold, - ), - color = textColor, + NetworkExceptionSelector( + selected = errorClassPath, + onSelected = { + errorClassPath = it + } ) } + + FloconDialogButtons( + onCancel = cancel, + onValidate = { + save( + error.copy( + weight = weight.toFloatOrNull() ?: error.weight, + type = errorException.copy( + classPath = errorClassPath + ) + ) + ) + }, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 4.dp), + ) } } } + + diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/edition/view/BadQualityEditionWindow.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/edition/view/BadQualityEditionWindow.kt index 97d21966..d6254132 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/edition/view/BadQualityEditionWindow.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/edition/view/BadQualityEditionWindow.kt @@ -5,8 +5,6 @@ package io.github.openflocon.flocondesktop.features.network.badquality.edition.v import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.material3.ExperimentalMaterial3Api @@ -23,6 +21,7 @@ import io.github.openflocon.flocondesktop.features.network.badquality.edition.mo import io.github.openflocon.library.designsystem.FloconTheme import io.github.openflocon.library.designsystem.components.FloconDialog import io.github.openflocon.library.designsystem.components.FloconDialogButtons +import io.github.openflocon.library.designsystem.components.FloconDialogHeader import io.github.openflocon.library.designsystem.components.FloconSurface import io.github.openflocon.library.designsystem.components.FloconTextField import io.github.openflocon.library.designsystem.components.defaultLabel @@ -46,6 +45,13 @@ fun BadQualityEditionWindow( } } +fun SelectedBadQualityUiModel.title(): String { + return when (this) { + SelectedBadQualityUiModel.Creation -> "Creation" + is SelectedBadQualityUiModel.Edition -> "Edition" + } +} + @Composable fun BadNetworkQualityEditionContent( state: SelectedBadQualityUiModel, @@ -86,13 +92,18 @@ fun BadNetworkQualityEditionContent( Column( verticalArrangement = Arrangement.spacedBy(8.dp), modifier = modifier - .fillMaxSize(), + .fillMaxWidth(), ) { + FloconDialogHeader( + title = state.title(), + modifier = Modifier.fillMaxWidth(), + ) + Column( verticalArrangement = Arrangement.spacedBy(8.dp), - modifier = modifier + modifier = Modifier .fillMaxWidth() - .padding(12.dp), + .padding(horizontal = 12.dp), ) { FloconTextField( label = defaultLabel("Name"), @@ -156,7 +167,8 @@ fun BadNetworkQualityEditionContent( ) } BadQualityErrorsListView( - modifier = Modifier.weight(1f).padding(top = 16.dp), + modifier = Modifier + .padding(top = 16.dp), errors = errors, onErrorslicked = { error -> selectedErrorToEdit = error @@ -174,10 +186,13 @@ fun BadNetworkQualityEditionContent( FloconSurface { when (val t = selectedError.type) { is BadQualityConfigUiModel.Error.Type.Body -> { - BadQualityErrorsEditor( + BadQualityHttpErrorEditor( error = selectedError, httpType = t, - onErrorsChange = { error -> + cancel = { + selectedErrorToEdit = null + }, + save = { error -> errors = if (errors.any { it.uuid == selectedError.uuid }) { errors.map { if (it.uuid == selectedError.uuid) { @@ -196,7 +211,10 @@ fun BadNetworkQualityEditionContent( BadQuaityErrorExceptionEditor( error = selectedError, errorException = t, - onErrorsChange = { error -> + cancel = { + selectedErrorToEdit = null + }, + save = { error -> errors = if (errors.any { it.uuid == selectedError.uuid }) { errors.map { if (it.uuid == selectedError.uuid) { @@ -223,7 +241,7 @@ fun BadNetworkQualityEditionContent( save( BadQualityConfigUiModel( id = config?.id ?: UUID.randomUUID().toString(), // generate a new one - name = name, + name = name.takeIf { it.isNotBlank() } ?: UUID.randomUUID().toString(), // generate if empty, TODO : fail isEnabled = config?.isEnabled ?: false, // disabled by default createdAt = config?.createdAt ?: System.currentTimeMillis(), // generate a new date diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/edition/view/BadQualityErrorsListView.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/edition/view/BadQualityErrorsListView.kt index 5ce357a5..58c4cb78 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/edition/view/BadQualityErrorsListView.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/edition/view/BadQualityErrorsListView.kt @@ -12,6 +12,7 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width @@ -63,7 +64,7 @@ fun BadQualityErrorsListView( weight = 1f, type = BadQualityConfigUiModel.Error.Type.Body( httpCode = 500, - body = "{\"error\":\"...\"}", + body = "", contentType = "application/json", ), ), @@ -93,54 +94,58 @@ fun BadQualityErrorsListView( } } - val lazyListState = rememberLazyListState() - val scrollAdapter = rememberFloconScrollbarAdapter(lazyListState) - Box(modifier = Modifier.fillMaxSize()) { - val contentPadding = PaddingValues(horizontal = 12.dp) - LazyColumn( - state = lazyListState, - modifier = Modifier.fillMaxSize(), - contentPadding = PaddingValues(vertical = 12.dp), - verticalArrangement = Arrangement.spacedBy(4.dp), - ) { - if(errors.isNotEmpty()) { - item { - Row( - modifier = Modifier.fillMaxWidth() - .padding(horizontal = 6.dp) - ) { - Text( - "Weight", - style = FloconTheme.typography.bodySmall.copy( - fontWeight = FontWeight.Thin, - fontSize = 10.sp, - ), - ) - Spacer(modifier = Modifier.width(28.dp)) - Text( - "Type", - style = FloconTheme.typography.bodySmall.copy( - fontWeight = FontWeight.Thin, - fontSize = 10.sp, - ), - ) + if (errors.isNotEmpty()) { + val lazyListState = rememberLazyListState() + val scrollAdapter = rememberFloconScrollbarAdapter(lazyListState) + Box(modifier = Modifier.height(160.dp)) { + val contentPadding = PaddingValues(horizontal = 12.dp) + LazyColumn( + state = lazyListState, + modifier = Modifier.fillMaxSize(), + contentPadding = PaddingValues(vertical = 12.dp), + verticalArrangement = Arrangement.spacedBy(4.dp), + ) { + if (errors.isNotEmpty()) { + item { + Row( + modifier = Modifier.fillMaxWidth() + .padding(horizontal = 6.dp) + ) { + Text( + "Weight", + style = FloconTheme.typography.bodySmall.copy( + fontWeight = FontWeight.Thin, + fontSize = 10.sp, + ), + ) + Spacer(modifier = Modifier.width(28.dp)) + Text( + "Type", + style = FloconTheme.typography.bodySmall.copy( + fontWeight = FontWeight.Thin, + fontSize = 10.sp, + ), + ) + } } } + items(errors) { error -> + BadQualityErrorItemView( + modifier = Modifier, + error = error, + deleteError = deleteError, + clickedError = onErrorslicked, + contentPadding = contentPadding, + ) + } } - items(errors) { error -> - BadQualityErrorItemView( - modifier = Modifier.fillMaxWidth(), - error = error, - deleteError = deleteError, - clickedError = onErrorslicked, - contentPadding = contentPadding, - ) - } + FloconVerticalScrollbar( + adapter = scrollAdapter, + modifier = Modifier + .align(Alignment.CenterEnd) + .fillMaxHeight(), + ) } - FloconVerticalScrollbar( - adapter = scrollAdapter, - modifier = Modifier.fillMaxHeight(), - ) } } } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/edition/view/exception/NetworkExceptionSelector.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/edition/view/exception/NetworkExceptionSelector.kt new file mode 100644 index 00000000..b6ff672e --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/edition/view/exception/NetworkExceptionSelector.kt @@ -0,0 +1,66 @@ +package io.github.openflocon.flocondesktop.features.network.badquality.edition.view + + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.util.fastForEach +import io.github.openflocon.flocondesktop.features.network.badquality.edition.model.possibleExceptions +import io.github.openflocon.library.designsystem.FloconTheme + +@Composable +fun NetworkExceptionSelector( + selected: String, + onSelected: (errorClassPath: String) -> Unit, + modifier: Modifier = Modifier, +) { + Column( + modifier = modifier.padding(horizontal = 4.dp), + verticalArrangement = Arrangement.spacedBy(4.dp) + ) { + possibleExceptions.fastForEach { exception -> + val (backgroundColor, textColor) = if (exception.classPath == selected) { + FloconTheme.colorPalette.onSurface to FloconTheme.colorPalette.panel + } else { + FloconTheme.colorPalette.panel to FloconTheme.colorPalette.onSurface + } + Column( + modifier = Modifier + .clip(RoundedCornerShape(8.dp)) + .background( + color = backgroundColor, + ) + .then( + Modifier.clickable( + onClick = { + onSelected(exception.classPath) + }, + ) + ) + .padding(horizontal = 10.dp, vertical = 4.dp) + ) { + Text( + text = exception.description, + style = FloconTheme.typography.bodySmall, + color = textColor, + ) + Text( + text = exception.classPath, + style = FloconTheme.typography.bodySmall.copy( + fontWeight = FontWeight.Bold, + ), + color = textColor, + ) + } + } + } +} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/edition/view/BadQualityErrorsEditor.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/edition/view/http/BadQualityHttpErrorEditor.kt similarity index 60% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/edition/view/BadQualityErrorsEditor.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/edition/view/http/BadQualityHttpErrorEditor.kt index 34f63dbf..a95e7663 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/edition/view/BadQualityErrorsEditor.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/edition/view/http/BadQualityHttpErrorEditor.kt @@ -1,70 +1,47 @@ package io.github.openflocon.flocondesktop.features.network.badquality.edition.view -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import io.github.openflocon.flocondesktop.features.network.badquality.edition.model.BadQualityConfigUiModel import io.github.openflocon.library.designsystem.FloconTheme +import io.github.openflocon.library.designsystem.components.FloconDialogButtons +import io.github.openflocon.library.designsystem.components.FloconDialogHeader import io.github.openflocon.library.designsystem.components.FloconTextField import io.github.openflocon.library.designsystem.components.defaultLabel import io.github.openflocon.library.designsystem.components.defaultPlaceHolder @Composable -internal fun BadQualityErrorsEditor( +internal fun BadQualityHttpErrorEditor( error: BadQualityConfigUiModel.Error, httpType: BadQualityConfigUiModel.Error.Type.Body, - onErrorsChange: (BadQualityConfigUiModel.Error) -> Unit, + cancel: () -> Unit, + save: (BadQualityConfigUiModel.Error) -> Unit, ) { var weight by remember(error) { mutableStateOf(error.weight.toString()) } var httpCode by remember(error) { mutableStateOf(httpType.httpCode.toString()) } var contentType by remember { mutableStateOf(httpType.contentType) } var body by remember(error) { mutableStateOf(httpType.body) } - Column(verticalArrangement = Arrangement.spacedBy(8.dp)) { - // bouton ajouter - Box( - modifier = Modifier - .clip(RoundedCornerShape(12.dp)) - .background(FloconTheme.colorPalette.onSurface) - .clickable { - onErrorsChange( - error.copy( - weight = weight.toFloatOrNull() ?: error.weight, - type = httpType.copy( - httpCode = httpCode.toIntOrNull() ?: httpType.httpCode, - contentType = contentType, - body = body, - ) - ), - ) - } - .padding(horizontal = 8.dp, vertical = 4.dp), - ) { - Text( - "Save", - style = FloconTheme.typography.titleSmall, - color = FloconTheme.colorPalette.panel, - ) - } + Column( + modifier = Modifier.fillMaxWidth(), + ) { + FloconDialogHeader( + title = "Http error", + modifier = Modifier.fillMaxWidth(), + ) Column( modifier = Modifier - .clip(RoundedCornerShape(8.dp)) - .background(Color(0xFFEFEFEF).copy(alpha = 0.2f)) - .padding(8.dp), + .padding(vertical = 8.dp, horizontal = 12.dp), + verticalArrangement = Arrangement.spacedBy(8.dp), ) { FloconTextField( label = defaultLabel("Weight"), @@ -75,6 +52,7 @@ internal fun BadQualityErrorsEditor( weight = it } }, + containerColor = FloconTheme.colorPalette.panel ) FloconTextField( @@ -86,21 +64,44 @@ internal fun BadQualityErrorsEditor( httpCode = it } }, + containerColor = FloconTheme.colorPalette.panel ) FloconTextField( label = defaultLabel("Content-Type"), placeholder = defaultPlaceHolder("application/json"), value = contentType, - onValueChange = { contentType = it } + onValueChange = { contentType = it }, + containerColor = FloconTheme.colorPalette.panel ) FloconTextField( label = defaultLabel("Body"), - placeholder = defaultPlaceHolder("{\"error\":\"...\"}"), + placeholder = defaultPlaceHolder("{\n\t\"error\" : \"...\"\n}"), value = body, + minLines = 5, onValueChange = { body = it }, + containerColor = FloconTheme.colorPalette.panel ) } + + FloconDialogButtons( + onCancel = cancel, + onValidate = { + save( + error.copy( + weight = weight.toFloatOrNull() ?: error.weight, + type = httpType.copy( + httpCode = httpCode.toIntOrNull() ?: httpType.httpCode, + contentType = contentType, + body = body, + ) + ), + ) + }, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 4.dp), + ) } } 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 index 5118b7f7..3d217951 100644 --- 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 @@ -3,6 +3,7 @@ package io.github.openflocon.flocondesktop.features.network.badquality.list.view import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -44,7 +45,7 @@ private fun BadNetworkQualityContent( NetworkBadQualityContent( lines = items, - modifier = Modifier.fillMaxSize(), + modifier = Modifier.fillMaxWidth(), onItemClicked = viewModel::select, onAddItemClicked = viewModel::create, onDeleteClicked = viewModel::delete, 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/NetworkBadQualityContent.kt similarity index 50% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/list/view/NetworkMocksContent.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/list/view/NetworkBadQualityContent.kt index f5c07d81..37f8ba0b 100644 --- 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/NetworkBadQualityContent.kt @@ -1,23 +1,18 @@ 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.height 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 +import io.github.openflocon.library.designsystem.components.FloconButton +import io.github.openflocon.library.designsystem.components.FloconDialogHeader @Composable fun NetworkBadQualityContent( @@ -29,36 +24,21 @@ fun NetworkBadQualityContent( 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, + FloconDialogHeader( + title = "Network bad quality", + modifier = Modifier.fillMaxWidth(), + trailingContent = { + FloconButton( + onClick = onAddItemClicked, + content = { + Text("Create") + } ) - } - } + }, + ) LazyColumn( - modifier = Modifier.fillMaxSize(), + modifier = Modifier.fillMaxWidth() + .height(400.dp), ) { items(lines) { BadNetworkLineView( diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/edition/view/NetworkEditionWindow.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/edition/view/NetworkEditionWindow.kt index e653c5eb..dad8195b 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/edition/view/NetworkEditionWindow.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/edition/view/NetworkEditionWindow.kt @@ -34,12 +34,15 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp 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.badquality.edition.model.BadQualityConfigUiModel import io.github.openflocon.flocondesktop.features.network.badquality.edition.model.possibleExceptions +import io.github.openflocon.flocondesktop.features.network.badquality.edition.view.NetworkExceptionSelector 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.EditableMockNetworkUiModel @@ -47,10 +50,13 @@ import io.github.openflocon.flocondesktop.features.network.mock.edition.model.He 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.FloconDialogButtons +import io.github.openflocon.library.designsystem.components.FloconDialogHeader import io.github.openflocon.library.designsystem.components.FloconSurface import io.github.openflocon.library.designsystem.components.FloconTextField import io.github.openflocon.library.designsystem.components.defaultLabel import io.github.openflocon.library.designsystem.components.defaultPlaceHolder +import java.util.UUID @Composable fun NetworkEditionWindow( @@ -61,7 +67,9 @@ fun NetworkEditionWindow( onSave: (MockNetworkUiModel) -> Unit, ) { val windowState: FloconWindowState = remember(instanceId) { - createFloconWindowState() + createFloconWindowState( + size = DpSize(900.dp, 700.dp) + ) } key(windowState, instanceId) { FloconWindow( @@ -109,49 +117,11 @@ fun MockEditorScreen( modifier = Modifier.fillMaxSize(), verticalArrangement = Arrangement.spacedBy(8.dp), ) { - Box( - Modifier - .fillMaxWidth() - .background(FloconTheme.colorPalette.panel) - .padding(horizontal = 12.dp, vertical = 8.dp), - ) { - Box( - modifier = Modifier.align(Alignment.CenterStart) - .clip(RoundedCornerShape(12.dp)) - .background(FloconTheme.colorPalette.onSurface) - .clickable(onClick = onCancel) - .padding(horizontal = 8.dp, vertical = 4.dp), - ) { - Text( - "Cancel", - style = FloconTheme.typography.titleSmall, - color = FloconTheme.colorPalette.panel, - ) - } - Box( - modifier = Modifier.align(Alignment.CenterEnd) - .clip(RoundedCornerShape(12.dp)) - .background(FloconTheme.colorPalette.onSurface) - .clickable(onClick = { - editableToUi(mock).fold( - doOnFailure = { - error = "Some fields are required" - }, - doOnSuccess = { - onSave(it) - error = null - }, - ) - }) - .padding(horizontal = 8.dp, vertical = 4.dp), - ) { - Text( - "Save", - style = FloconTheme.typography.titleSmall, - color = FloconTheme.colorPalette.panel, - ) - } - } + FloconDialogHeader( + modifier = Modifier + .fillMaxWidth(), + title = "Mock Edition" + ) error?.let { Text( @@ -161,7 +131,8 @@ fun MockEditorScreen( } Row( - modifier = Modifier.fillMaxSize() + modifier = Modifier.fillMaxWidth() + .weight(1f) .verticalScroll(scrollState), ) { Column( @@ -251,9 +222,9 @@ fun MockEditorScreen( } when (mock.responseType) { EditableMockNetworkUiModel.ResponseType.EXCEPTION -> { - MockNetworkErrorSelection( + NetworkExceptionSelector( selected = mock.exceptionResponse.classPath, - onChanged = { new -> + onSelected = { new -> mock = mock.copy( exceptionResponse = mock.exceptionResponse.copy( classPath = new, @@ -409,53 +380,23 @@ fun MockEditorScreen( } } } - } -} - -@Composable -private fun MockNetworkErrorSelection( - selected: String, - onChanged: (String) -> Unit, - modifier: Modifier = Modifier, -) { - Column( - modifier = modifier, - verticalArrangement = Arrangement.spacedBy(4.dp) - ) { - possibleExceptions.fastForEach { exception -> - val (backgroundColor, textColor) = if (exception.classPath == selected) { - FloconTheme.colorPalette.onSurface to FloconTheme.colorPalette.panel - } else { - FloconTheme.colorPalette.panel to FloconTheme.colorPalette.onSurface - } - Column( - modifier = Modifier - .clip(RoundedCornerShape(8.dp)) - .background( - color = backgroundColor, - ) - .then( - Modifier.clickable( - onClick = { - onChanged(exception.classPath) - }, - ) - ).padding(all = 8.dp) - ) { - Text( - text = exception.description, - style = FloconTheme.typography.bodySmall, - color = textColor, + FloconDialogButtons( + onCancel = onCancel, + onValidate = { + editableToUi(mock).fold( + doOnFailure = { + error = "Some fields are required" + }, + doOnSuccess = { + onSave(it) + error = null + }, ) - Text( - text = exception.classPath, - style = FloconTheme.typography.bodyMedium.copy( - fontWeight = FontWeight.Bold, - ), - color = textColor, - ) - } - } + }, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 4.dp), + ) } } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/list/view/NetworkMocksScreen.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/list/view/NetworkMocksScreen.kt index 9be3536c..8bc13fa3 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/list/view/NetworkMocksScreen.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/list/view/NetworkMocksScreen.kt @@ -6,6 +6,7 @@ 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.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items @@ -26,8 +27,9 @@ import io.github.openflocon.flocondesktop.features.network.mock.edition.view.Net 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.FloconButton import io.github.openflocon.library.designsystem.components.FloconDialog -import io.github.openflocon.library.designsystem.components.FloconSurface +import io.github.openflocon.library.designsystem.components.FloconDialogHeader import org.jetbrains.compose.ui.tooling.preview.Preview import org.koin.compose.viewmodel.koinViewModel @@ -50,7 +52,7 @@ fun NetworkMocksWindow( ) { NetworkMocksContent( mocks = mocks, - modifier = Modifier.fillMaxSize(), + modifier = Modifier.fillMaxWidth(), onItemClicked = viewModel::clickOnMock, onAddItemClicked = viewModel::createNewMock, onDeleteClicked = viewModel::deleteMock, @@ -79,50 +81,30 @@ private fun NetworkMocksContent( onAddItemClicked: () -> Unit, modifier: Modifier = Modifier, ) { - FloconSurface( - modifier = modifier, - ) { - Column(modifier = Modifier.fillMaxSize()) { - Box( - Modifier - .fillMaxWidth() - .background(FloconTheme.colorPalette.panel) - .padding(horizontal = 12.dp, vertical = 4.dp), - ) { - Text( - text = "Mocks", - 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), + + Column(modifier = modifier) { + FloconDialogHeader( + title = "Mocks", + modifier = Modifier.fillMaxWidth(), + trailingContent = { + FloconButton( + onClick = onAddItemClicked, ) { - Text( - "Create", - style = FloconTheme.typography.titleSmall, - color = FloconTheme.colorPalette.panel, - ) + Text("Create",) } } - LazyColumn( - modifier = Modifier.fillMaxSize(), - ) { - items(mocks) { - MockLineView( - item = it, - onClicked = onItemClicked, - onDeleteClicked = onDeleteClicked, - changeIsEnabled = changeIsEnabled, - modifier = Modifier.fillMaxWidth(), - ) - } + ) + LazyColumn( + modifier = Modifier.fillMaxWidth().height(400.dp), + ) { + items(mocks) { + MockLineView( + item = it, + onClicked = onItemClicked, + onDeleteClicked = onDeleteClicked, + changeIsEnabled = changeIsEnabled, + modifier = Modifier.fillMaxWidth(), + ) } } } diff --git a/FloconDesktop/composeApp/src/desktopMain/java/io/github/openflocon/flocondesktop/common/ui/window/FloconWindow.desktop.kt b/FloconDesktop/composeApp/src/desktopMain/java/io/github/openflocon/flocondesktop/common/ui/window/FloconWindow.desktop.kt index 2c225287..a214949e 100644 --- a/FloconDesktop/composeApp/src/desktopMain/java/io/github/openflocon/flocondesktop/common/ui/window/FloconWindow.desktop.kt +++ b/FloconDesktop/composeApp/src/desktopMain/java/io/github/openflocon/flocondesktop/common/ui/window/FloconWindow.desktop.kt @@ -2,6 +2,8 @@ package io.github.openflocon.flocondesktop.common.ui.window import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment +import androidx.compose.ui.unit.DpSize +import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Window import androidx.compose.ui.window.WindowPlacement import androidx.compose.ui.window.WindowPosition @@ -14,12 +16,15 @@ data class FloconWindowStateDesktop( val windowState: WindowState, ) : FloconWindowState -actual fun createFloconWindowState(): FloconWindowState = FloconWindowStateDesktop( - WindowState( - placement = WindowPlacement.Floating, - position = WindowPosition(Alignment.Center), - ), -) +actual fun createFloconWindowState(size: DpSize?): FloconWindowState { + return FloconWindowStateDesktop( + WindowState( + placement = WindowPlacement.Floating, + position = WindowPosition(Alignment.Center), + size = size ?: defaultWindowSize + ) + ) +} @Composable actual fun FloconWindow( 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 52b78750..8ab4c66a 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 @@ -129,12 +129,13 @@ class BadQualityConfigLocalDataSourceImpl( private fun defaultConfig(deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel): List { // to be sure we don't have doubles val idPrefix = deviceIdAndPackageName.deviceId + deviceIdAndPackageName.packageName + val now = System.currentTimeMillis() return listOf( BadQualityConfigDomainModel( id = idPrefix + "low_latency", isEnabled = false, name = "Low latency", - createdAt = Instant.fromEpochMilliseconds(System.currentTimeMillis()), + createdAt = Instant.fromEpochMilliseconds(now + 1) , latency = BadQualityConfigDomainModel.LatencyConfig( minLatencyMs = 100, maxLatencyMs = 400, @@ -147,7 +148,7 @@ class BadQualityConfigLocalDataSourceImpl( id = idPrefix + "medium_latency", isEnabled = false, name = "Medium latency", - createdAt = Instant.fromEpochMilliseconds(System.currentTimeMillis()), + createdAt = Instant.fromEpochMilliseconds(now + 2), latency = BadQualityConfigDomainModel.LatencyConfig( minLatencyMs = 2000, maxLatencyMs = 4000, @@ -160,7 +161,7 @@ class BadQualityConfigLocalDataSourceImpl( id = idPrefix + "high_latency", isEnabled = false, name = "High latency", - createdAt = Instant.fromEpochMilliseconds(System.currentTimeMillis()), + createdAt = Instant.fromEpochMilliseconds(now + 3), latency = BadQualityConfigDomainModel.LatencyConfig( minLatencyMs = 10_000, maxLatencyMs = 30_000, @@ -173,7 +174,7 @@ class BadQualityConfigLocalDataSourceImpl( id = idPrefix + "timeout", isEnabled = false, name = "100% Timeout", - createdAt = Instant.fromEpochMilliseconds(System.currentTimeMillis()), + createdAt = Instant.fromEpochMilliseconds(now + 4), latency = BadQualityConfigDomainModel.LatencyConfig( minLatencyMs = 0, maxLatencyMs = 0, @@ -193,7 +194,7 @@ class BadQualityConfigLocalDataSourceImpl( id = idPrefix + "server_down", isEnabled = false, name = "Server Down", - createdAt = Instant.fromEpochMilliseconds(System.currentTimeMillis()), + createdAt = Instant.fromEpochMilliseconds(now + 5), latency = BadQualityConfigDomainModel.LatencyConfig( minLatencyMs = 0, maxLatencyMs = 0, diff --git a/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconDialog.kt b/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconDialog.kt index 9071eaf6..92607cad 100644 --- a/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconDialog.kt +++ b/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconDialog.kt @@ -2,19 +2,27 @@ package io.github.openflocon.library.designsystem.components +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.ExperimentalMaterial3Api 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 androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties +import io.github.openflocon.library.designsystem.FloconTheme @Composable fun FloconDialog( @@ -30,13 +38,42 @@ fun FloconDialog( shape = RoundedCornerShape(10.dp), modifier = modifier .fillMaxWidth() - .height(500.dp) + .wrapContentHeight() ) { content() } } } +@Composable +fun FloconDialogHeader( + title: String, + modifier: Modifier = Modifier, + trailingContent: @Composable RowScope.() -> Unit = {}, +) { + Row( + modifier + .background(FloconTheme.colorPalette.panel) + .padding(horizontal = 12.dp, vertical = 4.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + Text( + text = title, + modifier = Modifier + .padding(vertical = 12.dp) + .padding(start = 4.dp) + .weight(1f), + style = FloconTheme.typography.titleMedium, + color = FloconTheme.colorPalette.onSurface, + ) + Row( + verticalAlignment = Alignment.CenterVertically, + ) { + trailingContent() + } + } +} + @Composable fun FloconDialogButtons( onCancel: () -> Unit, @@ -59,7 +96,7 @@ fun FloconDialogButtons( onClick = onValidate ) { Text( - text = "Validate" + text = "Save" ) } } diff --git a/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconTextField.kt b/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconTextField.kt index 3a348ed9..02e4cf45 100644 --- a/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconTextField.kt +++ b/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconTextField.kt @@ -211,6 +211,11 @@ private fun ContainerBox( @Composable fun defaultLabel(text: String): @Composable () -> Unit = { + DefaultLabel(text) +} + +@Composable +fun DefaultLabel(text: String) { Text( text = text, style = FloconTheme.typography.bodyMedium.copy(fontWeight = FontWeight.Thin),