diff --git a/composeApp/src/commonMain/kotlin/ru/csasq/cit_is_bot/App.kt b/composeApp/src/commonMain/kotlin/ru/csasq/cit_is_bot/App.kt index d418c91..6e8f117 100644 --- a/composeApp/src/commonMain/kotlin/ru/csasq/cit_is_bot/App.kt +++ b/composeApp/src/commonMain/kotlin/ru/csasq/cit_is_bot/App.kt @@ -1,7 +1,10 @@ package ru.csasq.cit_is_bot +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon +import androidx.compose.material3.LinearProgressIndicator import androidx.compose.material3.MaterialTheme import androidx.compose.material3.NavigationBar import androidx.compose.material3.NavigationBarItem @@ -12,7 +15,9 @@ import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.runtime.* +import androidx.compose.ui.Modifier import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.style.TextOverflow import androidx.navigation.NavDestination.Companion.hierarchy import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable @@ -65,22 +70,33 @@ fun App() { colorScheme = darkScheme, ) { val navController = rememberNavController() - val snackbarHostState = remember { - SnackbarHostState() + val progressIndicatorState = remember { + mutableStateOf(false) } + val snackbarHostState = SnackbarHostState() val floatingActionButtonState = remember { mutableStateOf<(@Composable () -> Unit)?>(null) } Scaffold( topBar = { - TopAppBar( - title = { - Text( - text = "Сообщения", + Column { + TopAppBar( + title = { + Text( + text = "Сообщения", + overflow = TextOverflow.Ellipsis, + softWrap = false, + ) + }, + ) + when { + progressIndicatorState.value -> LinearProgressIndicator( + modifier = Modifier + .fillMaxWidth(), ) - }, - ) + } + } }, bottomBar = { NavigationBar { @@ -119,12 +135,12 @@ fun App() { snackbarHost = { SnackbarHost( hostState = snackbarHostState, - ) { + ) { snackbarData -> Snackbar( - snackbarData = it, - containerColor = MaterialTheme.colorScheme.errorContainer, - contentColor = MaterialTheme.colorScheme.error, - actionColor = MaterialTheme.colorScheme.onErrorContainer, + snackbarData = snackbarData, +// containerColor = MaterialTheme.colorScheme.errorContainer, +// contentColor = MaterialTheme.colorScheme.error, +// actionColor = MaterialTheme.colorScheme.onErrorContainer, ) } }, @@ -145,6 +161,8 @@ fun App() { ScenariosScreen( navController, paddingValues, + progressIndicatorState, + snackbarHostState, floatingActionButtonState, ) } diff --git a/composeApp/src/commonMain/kotlin/ru/csasq/cit_is_bot/ui/dialogs/ScenarioDialog.kt b/composeApp/src/commonMain/kotlin/ru/csasq/cit_is_bot/ui/dialogs/ScenarioDialog.kt index bac92a9..9760b88 100644 --- a/composeApp/src/commonMain/kotlin/ru/csasq/cit_is_bot/ui/dialogs/ScenarioDialog.kt +++ b/composeApp/src/commonMain/kotlin/ru/csasq/cit_is_bot/ui/dialogs/ScenarioDialog.kt @@ -21,6 +21,7 @@ import androidx.compose.material3.ExposedDropdownMenuDefaults import androidx.compose.material3.ExtendedFloatingActionButton import androidx.compose.material3.Icon import androidx.compose.material3.IconButton +import androidx.compose.material3.LinearProgressIndicator import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedTextField @@ -84,11 +85,15 @@ enum class MessageType( fun ScenarioDialog( scenarioDialogState: MutableState, client: HttpClient, + onSuccess: () -> Unit, properties: DialogProperties = DialogProperties( usePlatformDefaultWidth = false, ), ) { val coroutine = rememberCoroutineScope() + val progressIndicatorState = remember { + mutableStateOf(false) + } val nameState = remember { mutableStateOf(scenarioDialogState.value?.name) } @@ -119,71 +124,98 @@ fun ScenarioDialog( modifier = Modifier .fillMaxSize(), topBar = { - TopAppBar( - title = { - Text( - text = scenarioDialogState.value?.id?.let { - "Изменить сценарий" - } ?: "Добавить сценарий", - overflow = TextOverflow.Ellipsis, - maxLines = 1, - ) - }, - navigationIcon = { - IconButton( - onClick = { - scenarioDialogState.value = null - }, - ) { - Icon( - painter = painterResource(Res.drawable.baseline_close_24), - contentDescription = null, - ) - } - }, - actions = { - Button( - onClick = { - scenarioDialogState.value?.name = nameState.value!! - coroutine.launch { - val response = client.put("https://cit.csasq.ru/api/scripts") { - contentType(ContentType.Application.Json) - setBody(scenarioDialogState.value) - } - when(response.status) { - HttpStatusCode.Created -> scenarioDialogState.value = null - } - } - }, - ) { + Column { + TopAppBar( + title = { Text( - text = "Сохранить", + text = scenarioDialogState.value?.id?.let { + "Изменить сценарий" + } ?: "Добавить сценарий", + overflow = TextOverflow.Ellipsis, + softWrap = false, ) - } - val dropdownMenuState = remember { - mutableStateOf(false) - } - IconButton( - onClick = { - dropdownMenuState.value = true - }, - ) { - Icon( - painter = painterResource(Res.drawable.baseline_more_vert_24), - contentDescription = null, - ) - } - DropdownMenu( - expanded = dropdownMenuState.value, - onDismissRequest = { - dropdownMenuState.value = false - }, - ) { - scenarioDialogState.value?.let { + }, + navigationIcon = { + IconButton( + onClick = { + scenarioDialogState.value = null + }, + ) { + Icon( + painter = painterResource(Res.drawable.baseline_close_24), + contentDescription = null, + ) + } + }, + actions = { + Button( + onClick = { + scenarioDialogState.value?.name = nameState.value!! + coroutine.launch { + progressIndicatorState.value = true + val response = client.put("https://cit.csasq.ru/api/scripts") { + contentType(ContentType.Application.Json) + setBody(scenarioDialogState.value) + } + progressIndicatorState.value = false + when (response.status) { + HttpStatusCode.Created -> { + onSuccess() + scenarioDialogState.value = null + } + } + } + }, + ) { + Text( + text = "Сохранить", + ) + } + val dropdownMenuState = remember { + mutableStateOf(false) + } + IconButton( + onClick = { + dropdownMenuState.value = true + }, + ) { + Icon( + painter = painterResource(Res.drawable.baseline_more_vert_24), + contentDescription = null, + ) + } + DropdownMenu( + expanded = dropdownMenuState.value, + onDismissRequest = { + dropdownMenuState.value = false + }, + ) { + scenarioDialogState.value?.let { + DropdownMenuItem( + text = { + Text( + text = "Удалить", + ) + }, + onClick = { + dropdownMenuState.value = false + }, + ) + } DropdownMenuItem( text = { Text( - text = "Удалить", + text = "Сообщить о проблеме", + ) + }, + onClick = { + dropdownMenuState.value = false + }, + ) + DropdownMenuItem( + text = { + Text( + text = "Справка", ) }, onClick = { @@ -191,29 +223,15 @@ fun ScenarioDialog( }, ) } - DropdownMenuItem( - text = { - Text( - text = "Сообщить о проблеме", - ) - }, - onClick = { - dropdownMenuState.value = false - }, - ) - DropdownMenuItem( - text = { - Text( - text = "Справка", - ) - }, - onClick = { - dropdownMenuState.value = false - }, - ) - } - }, - ) + }, + ) + when { + progressIndicatorState.value -> LinearProgressIndicator( + modifier = Modifier + .fillMaxWidth(), + ) + } + } }, floatingActionButton = { ExtendedFloatingActionButton( diff --git a/composeApp/src/commonMain/kotlin/ru/csasq/cit_is_bot/ui/screens/ScenariosScreen.kt b/composeApp/src/commonMain/kotlin/ru/csasq/cit_is_bot/ui/screens/ScenariosScreen.kt index 3f07b3e..550a56f 100644 --- a/composeApp/src/commonMain/kotlin/ru/csasq/cit_is_bot/ui/screens/ScenariosScreen.kt +++ b/composeApp/src/commonMain/kotlin/ru/csasq/cit_is_bot/ui/screens/ScenariosScreen.kt @@ -8,6 +8,8 @@ import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.ExtendedFloatingActionButton import androidx.compose.material3.Icon +import androidx.compose.material3.SnackbarDuration +import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -15,6 +17,7 @@ import androidx.compose.runtime.MutableState import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Modifier import androidx.compose.ui.text.buildAnnotatedString @@ -46,8 +49,11 @@ data class Scenario( fun ScenariosScreen( navController: NavController, paddingValues: PaddingValues, + progressIndicatorState: MutableState, + snackbarHostState: SnackbarHostState, floatingActionButtonState: MutableState<(@Composable () -> Unit)?>, ) { + val snackbarCoroutineScope = rememberCoroutineScope() val verticalScrollState = rememberScrollState() val floatingActionButtonExpandedState = remember { mutableStateOf(true) @@ -74,7 +80,9 @@ fun ScenariosScreen( } LaunchedEffect(false) { client.launch { + progressIndicatorState.value = true val response = client.get("https://cit.csasq.ru/api/scripts") + progressIndicatorState.value = false when (response.status) { HttpStatusCode.OK -> scenarioList.addAll(response.body()) } @@ -127,7 +135,7 @@ fun ScenariosScreen( } val captionAnnotatedString = buildAnnotatedString { append(it.time) - append(" \u2022 ") + append(" \u2022 ") append(it.messageNumber) } SwitchButton( @@ -147,6 +155,14 @@ fun ScenariosScreen( ScenarioDialog( scenarioDialogState = scenarioDialogState, client = client, + onSuccess = { + snackbarCoroutineScope.launch { + snackbarHostState.showSnackbar( + message = "Сценарий сохранен", + duration = SnackbarDuration.Short, + ) + } + }, ) } }