From 2c3421a67702f560d74cd483ca182082b398a52a Mon Sep 17 00:00:00 2001 From: Amanpal Singh <87360222+aman-alfresco@users.noreply.github.com> Date: Wed, 27 Dec 2023 18:10:42 +0530 Subject: [PATCH 1/2] added single-line text component --- app/build.gradle | 1 + .../content/data/payloads/FieldsData.kt | 8 ++ gradle/libs.versions.toml | 1 + .../alfresco/content/process/FormViewModel.kt | 63 ++++++++++++-- .../content/process/NavigationComponent.kt | 5 +- .../content/process/ProcessFormActivity.kt | 4 +- .../content/process/ui/FormFragment.kt | 86 ++++++++++++++++--- .../ui/components/ComponentSettings.kt | 19 ---- .../CustomLinearProgressIndicator.kt | 28 ++++++ .../process/ui/components/TextInputField.kt | 23 +++-- .../content/process/ui/theme/Color.kt | 3 + .../content/process/ui/theme/Theme.kt | 22 ++++- 12 files changed, 210 insertions(+), 53 deletions(-) delete mode 100644 process-app/src/main/kotlin/com/alfresco/content/process/ui/components/ComponentSettings.kt create mode 100644 process-app/src/main/kotlin/com/alfresco/content/process/ui/components/CustomLinearProgressIndicator.kt diff --git a/app/build.gradle b/app/build.gradle index 68d8c2517..171cd4a20 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -121,6 +121,7 @@ dependencies { implementation libs.coil.core implementation libs.gson + implementation libs.compose.runtime coreLibraryDesugaring libs.android.desugar diff --git a/data/src/main/kotlin/com/alfresco/content/data/payloads/FieldsData.kt b/data/src/main/kotlin/com/alfresco/content/data/payloads/FieldsData.kt index 5db933ef0..67529a6fe 100644 --- a/data/src/main/kotlin/com/alfresco/content/data/payloads/FieldsData.kt +++ b/data/src/main/kotlin/com/alfresco/content/data/payloads/FieldsData.kt @@ -22,6 +22,7 @@ data class FieldsData( var overrideId: Boolean = false, var fields: List = emptyList(), var options: List = emptyList(), + var placeHolder: String? = null, ) : Parcelable { companion object { @@ -45,3 +46,10 @@ data class FieldsData( } } } + +enum class FieldType() { + TEXT, + ; + + fun value() = name.lowercase() +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 37228fb7c..f6bea7535 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -138,4 +138,5 @@ ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" } ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" } material3 = { group = "androidx.compose.material3", name = "material3" } navigation-compose = "androidx.navigation:navigation-compose:2.7.5" +compose-runtime = "androidx.compose.runtime:runtime:1.5.4" diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/FormViewModel.kt b/process-app/src/main/kotlin/com/alfresco/content/process/FormViewModel.kt index 08cc5d046..e00373eb0 100644 --- a/process-app/src/main/kotlin/com/alfresco/content/process/FormViewModel.kt +++ b/process-app/src/main/kotlin/com/alfresco/content/process/FormViewModel.kt @@ -12,25 +12,60 @@ import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.ViewModelContext import com.alfresco.content.data.ProcessEntry import com.alfresco.content.data.ResponseListForm +import com.alfresco.content.data.ResponseListProcessDefinition import com.alfresco.content.data.TaskRepository +import com.alfresco.content.data.payloads.FieldsData import com.alfresco.coroutines.asFlow import kotlinx.coroutines.launch data class FormViewState( - val parent: ProcessEntry, + val parent: ProcessEntry = ProcessEntry(), val requestStartForm: Async = Uninitialized, + val requestProcessDefinition: Async = Uninitialized, + val formFields: List = emptyList(), ) : MavericksState { constructor(target: ProcessEntry) : this(parent = target) + + /** + * update the single process definition entry + */ + fun updateSingleProcessDefinition(response: ResponseListProcessDefinition): FormViewState { + if (parent == null) { + return this + } + val processEntry = ProcessEntry.with(response.listProcessDefinitions.first(), parent) + return copy(parent = processEntry) + } } class FormViewModel( - state: FormViewState, + val state: FormViewState, val context: Context, private val repository: TaskRepository, ) : MavericksViewModel(state) { init { - getStartForm(state.parent) + singleProcessDefinition(state.parent.id) + } + + private fun singleProcessDefinition(appDefinitionId: String) = withState { state -> + viewModelScope.launch { + repository::singleProcessDefinition.asFlow(appDefinitionId).execute { + when (it) { + is Loading -> copy(requestProcessDefinition = Loading()) + is Fail -> copy(requestProcessDefinition = Fail(it.error)) + is Success -> { + val updatedState = updateSingleProcessDefinition(it()) + getStartForm(updatedState.parent) + copy(requestProcessDefinition = Success(it())) + } + + else -> { + this + } + } + } + } } private fun getStartForm(processEntry: ProcessEntry) { @@ -39,12 +74,13 @@ class FormViewModel( repository::startForm.asFlow(processEntry.id).execute { when (it) { is Loading -> copy(requestStartForm = Loading()) - is Fail -> copy(requestStartForm = Fail(it.error)) + is Fail -> { + it.error.printStackTrace() + copy(requestStartForm = Fail(it.error)) } is Success -> { - println("form-data == ${it()}") - copy(requestStartForm = Success(it())) +// println("form-data == ${it()}") + copy(formFields = it().fields.first().fields, requestStartForm = Success(it())) } - else -> { this } @@ -53,6 +89,19 @@ class FormViewModel( } } + fun updateFieldValue(fieldId: String, newValue: String, state: FormViewState) { + val updatedFields = state.copy( + formFields = state.formFields.map { field -> + if (field.id == fieldId) { + field.copy(value = newValue) + } else { + field + } + }, + ) + setState { updatedFields } + } + companion object : MavericksViewModelFactory { override fun create( diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/NavigationComponent.kt b/process-app/src/main/kotlin/com/alfresco/content/process/NavigationComponent.kt index 2d36e93d1..bd15e8f7e 100644 --- a/process-app/src/main/kotlin/com/alfresco/content/process/NavigationComponent.kt +++ b/process-app/src/main/kotlin/com/alfresco/content/process/NavigationComponent.kt @@ -1,6 +1,5 @@ package com.alfresco.content.process -import android.os.Bundle import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material3.Surface import androidx.compose.runtime.Composable @@ -11,14 +10,14 @@ import androidx.navigation.compose.rememberNavController import com.alfresco.content.process.ui.FormFragment @Composable -fun NavigationComponent(extras: Bundle?) { +fun NavigationComponent() { val navController = rememberNavController() Surface(modifier = Modifier.fillMaxSize()) { NavHost(navController = navController, startDestination = "first_screen") { composable("first_screen") { // Replace with the content of your first fragment - FormFragment(navController = navController, extras) + FormFragment(navController = navController) } // Add more composable entries for other fragments in your navigation graph } diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ProcessFormActivity.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ProcessFormActivity.kt index bcbe77036..e04ce69c2 100644 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ProcessFormActivity.kt +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ProcessFormActivity.kt @@ -18,7 +18,7 @@ class ProcessFormActivity : ComponentActivity() { AlfrescoBaseTheme { // A surface container using the 'background' color from the theme Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) { - NavigationComponent(intent.extras) + NavigationComponent() } } } @@ -29,6 +29,6 @@ class ProcessFormActivity : ComponentActivity() { @Composable fun GreetingPreview() { AlfrescoBaseTheme { - NavigationComponent(null) + NavigationComponent() } } diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/FormFragment.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/FormFragment.kt index 520497e4b..fe7d49c16 100644 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ui/FormFragment.kt +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/FormFragment.kt @@ -1,41 +1,58 @@ package com.alfresco.content.process.ui -import android.os.Bundle +import android.app.Activity +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowBack import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold +import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment +import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.navigation.NavController +import com.airbnb.mvrx.Loading +import com.airbnb.mvrx.compose.collectAsState import com.airbnb.mvrx.compose.mavericksActivityViewModel +import com.alfresco.content.data.TaskRepository import com.alfresco.content.process.FormViewModel +import com.alfresco.content.process.FormViewState +import com.alfresco.content.process.ui.components.CustomLinearProgressIndicator import com.alfresco.content.process.ui.components.TextInputField @OptIn(ExperimentalMaterial3Api::class) @Composable -fun FormFragment(navController: NavController, extras: Bundle?) { +fun FormFragment(navController: NavController) { val context = LocalContext.current + // This will get or create a ViewModel scoped to the Activity. + val viewModel: FormViewModel = mavericksActivityViewModel() + val state by viewModel.collectAsState() + Scaffold( topBar = { TopAppBar( title = { - Text(text = "Form Details") + Text(text = "Workflow form") }, navigationIcon = { - IconButton(onClick = { /* Handle navigation icon click */ }) { - // Add navigation icon here - } + BackButton(onClick = { (context as Activity).finish() }) }, actions = { // Add actions if any @@ -43,24 +60,66 @@ fun FormFragment(navController: NavController, extras: Bundle?) { ) }, content = { padding -> - FormDetailScreen(padding) + + val colorScheme = MaterialTheme.colorScheme + + Surface( + color = colorScheme.background, + contentColor = colorScheme.onBackground, + ) { + if (state.requestStartForm is Loading) { + CustomLinearProgressIndicator(padding) + } + FormDetailScreen(padding, state, viewModel) + } }, ) } @Composable -fun FormDetailScreen(padding: PaddingValues) { +fun BackButton(onClick: () -> Unit) { + IconButton(onClick = onClick) { + Icon(imageVector = Icons.Default.ArrowBack, contentDescription = "Back") + } +} + +@OptIn(ExperimentalComposeUiApi::class) +@Composable +fun FormDetailScreen(padding: PaddingValues, state: FormViewState, viewModel: FormViewModel) { // This will get or create a ViewModel scoped to the Activity. - val viewModel: FormViewModel = mavericksActivityViewModel() + /*val viewModel: FormViewModel = mavericksActivityViewModel() + + val state by viewModel.collectAsState()*/ + + val keyboardController = LocalSoftwareKeyboardController.current + val focusManager = LocalFocusManager.current Column( modifier = Modifier .fillMaxSize() - .padding(16.dp), - verticalArrangement = Arrangement.Center, + .clickable { + // Hide the keyboard on click outside of input fields + keyboardController?.hide() + focusManager.clearFocus() + } + .padding(padding), + verticalArrangement = Arrangement.Top, horizontalAlignment = Alignment.CenterHorizontally, + ) { - TextInputField(1) + state.formFields.forEach { field -> + if (field.type == "text") { + println("FormDetailScreen Value 1 == ${field.value as? String}") + TextInputField( + value = field.value as? String, + onValueChange = { newValue -> + println("FormDetailScreen Value == $newValue") + viewModel.updateFieldValue(field.id, newValue, state) + }, + field, + ) + } + } // Add more Composables here based on your UI requirements } } @@ -68,5 +127,6 @@ fun FormDetailScreen(padding: PaddingValues) { @Preview @Composable fun PreviewProcessDetailScreen() { - FormDetailScreen(PaddingValues(16.dp)) + val state = FormViewState() + FormDetailScreen(PaddingValues(16.dp), state, FormViewModel(state, LocalContext.current, TaskRepository())) } diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/ComponentSettings.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/ComponentSettings.kt deleted file mode 100644 index 290a91104..000000000 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/ComponentSettings.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.alfresco.content.process.ui.components - -data class ComponentSettings( - val id: String, - val placeHolder: String, - val isRequired: Boolean, - val isReadOnly: Boolean, - val value: String, - val minLength: Int, - val maxLength: Int, - val minValue: String, - val maxValue: String, - val options: ComponentOptions, -) - -data class ComponentOptions( - val id: String, - val name: String, -) diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/CustomLinearProgressIndicator.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/CustomLinearProgressIndicator.kt new file mode 100644 index 000000000..63f696e00 --- /dev/null +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/CustomLinearProgressIndicator.kt @@ -0,0 +1,28 @@ +package com.alfresco.content.process.ui.components + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.LinearProgressIndicator +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp + +@Composable +fun CustomLinearProgressIndicator(padding: PaddingValues) { + Box( + modifier = Modifier + .fillMaxWidth() + .height(2.dp) + .padding(padding), // Adjust padding as needed + ) { + LinearProgressIndicator( + color = Color.Blue, // Set your desired color here + modifier = Modifier.align(Alignment.TopCenter), + ) + } +} diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/TextInputField.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/TextInputField.kt index e9757522d..dbab5fbc9 100644 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/TextInputField.kt +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/TextInputField.kt @@ -1,5 +1,6 @@ package com.alfresco.content.process.ui.components +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material3.ExperimentalMaterial3Api @@ -10,16 +11,24 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import com.alfresco.content.data.payloads.FieldsData @OptIn(ExperimentalMaterial3Api::class) @Composable -fun TextInputField(maxLines: Int) { +fun TextInputField( + value: String? = null, + onValueChange: (String) -> Unit = { }, + fieldsData: FieldsData = FieldsData(), + maxLines: Int = 1, +) { OutlinedTextField( - value = "", // Initial value of the text field - onValueChange = { /* Handle value changes here */ }, - modifier = Modifier.padding(16.dp), // Add padding or other modifiers as needed - label = { Text("Enter text") }, // Label for the text field - placeholder = { Text("Type something") }, // Placeholder text + value = value ?: "", // Initial value of the text field + onValueChange = onValueChange, + modifier = Modifier + .fillMaxWidth() + .padding(16.dp), // Add padding or other modifiers as needed + label = { Text(fieldsData.name) }, // Label for the text field + placeholder = { Text(fieldsData.placeHolder ?: "") }, // Placeholder text maxLines = maxLines, // Set the maximum number of lines to 1 keyboardOptions = KeyboardOptions.Default.copy(keyboardType = KeyboardType.Text), // Set keyboard type // Other optional parameters like keyboardOptions, keyboardActions, etc., can be added as needed @@ -29,5 +38,5 @@ fun TextInputField(maxLines: Int) { @Preview @Composable fun TextInputFieldPreview() { - TextInputField(1) + TextInputField() } diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/theme/Color.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/theme/Color.kt index 850fa3fb7..808d94c9b 100644 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ui/theme/Color.kt +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/theme/Color.kt @@ -16,6 +16,9 @@ val AlfrescoGray100 = Color(0xFFF5F5F5) val AlfrescoError = Color(0xFFB8082A) +// Define your specific colors +val designDefaultDarkBackgroundColor = Color(0xFF121212) + val Transparent = Color.Transparent val White = Color.White val White15 = Color(0x26FFFFFF) diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/theme/Theme.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/theme/Theme.kt index 25a3c2ace..f5bb7634a 100644 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ui/theme/Theme.kt +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/theme/Theme.kt @@ -2,6 +2,7 @@ package com.alfresco.content.process.ui.theme import android.app.Activity import android.os.Build +import androidx.appcompat.app.AppCompatDelegate import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.material3.MaterialTheme import androidx.compose.material3.darkColorScheme @@ -39,11 +40,19 @@ private val LightColorScheme = lightColorScheme( @Composable fun AlfrescoBaseTheme( - darkTheme: Boolean = isSystemInDarkTheme(), + darkTheme: Boolean = isNightMode(), // Dynamic color is available on Android 12+ dynamicColor: Boolean = true, content: @Composable () -> Unit, ) { + val statusBarColor = if (darkTheme) { + // Set status bar color for dark theme + designDefaultDarkBackgroundColor + } else { + // Set status bar color for light theme + AlfrescoGray900 // Replace with your desired light theme status bar color + } + val colorScheme = when { dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { val context = LocalContext.current @@ -61,7 +70,9 @@ fun AlfrescoBaseTheme( if (!view.isInEditMode) { SideEffect { val window = (view.context as Activity).window - window.statusBarColor = colorScheme.primary.toArgb() + WindowCompat.setDecorFitsSystemWindows(window, false) + window.statusBarColor = statusBarColor.toArgb() +// window.navigationBarColor = AlfrescoGray900.toArgb() WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = darkTheme } } @@ -72,3 +83,10 @@ fun AlfrescoBaseTheme( content = content, ) } + +@Composable +private fun isNightMode() = when (AppCompatDelegate.getDefaultNightMode()) { + AppCompatDelegate.MODE_NIGHT_NO -> false + AppCompatDelegate.MODE_NIGHT_YES -> true + else -> isSystemInDarkTheme() +} From 67c958be858ebd49ddcb5cb88eb263d996b8f399 Mon Sep 17 00:00:00 2001 From: Amanpal Singh <87360222+aman-alfresco@users.noreply.github.com> Date: Thu, 28 Dec 2023 11:41:51 +0530 Subject: [PATCH 2/2] fixed review correction --- .../com/alfresco/content/process/ui/FormFragment.kt | 10 ++-------- .../com/alfresco/content/process/ui/theme/Theme.kt | 12 +----------- 2 files changed, 3 insertions(+), 19 deletions(-) diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/FormFragment.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/FormFragment.kt index fe7d49c16..422726293 100644 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ui/FormFragment.kt +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/FormFragment.kt @@ -32,6 +32,7 @@ import com.airbnb.mvrx.Loading import com.airbnb.mvrx.compose.collectAsState import com.airbnb.mvrx.compose.mavericksActivityViewModel import com.alfresco.content.data.TaskRepository +import com.alfresco.content.data.payloads.FieldType import com.alfresco.content.process.FormViewModel import com.alfresco.content.process.FormViewState import com.alfresco.content.process.ui.components.CustomLinearProgressIndicator @@ -86,11 +87,6 @@ fun BackButton(onClick: () -> Unit) { @OptIn(ExperimentalComposeUiApi::class) @Composable fun FormDetailScreen(padding: PaddingValues, state: FormViewState, viewModel: FormViewModel) { - // This will get or create a ViewModel scoped to the Activity. - /*val viewModel: FormViewModel = mavericksActivityViewModel() - - val state by viewModel.collectAsState()*/ - val keyboardController = LocalSoftwareKeyboardController.current val focusManager = LocalFocusManager.current @@ -108,12 +104,10 @@ fun FormDetailScreen(padding: PaddingValues, state: FormViewState, viewModel: Fo ) { state.formFields.forEach { field -> - if (field.type == "text") { - println("FormDetailScreen Value 1 == ${field.value as? String}") + if (field.type == FieldType.TEXT.value()) { TextInputField( value = field.value as? String, onValueChange = { newValue -> - println("FormDetailScreen Value == $newValue") viewModel.updateFieldValue(field.id, newValue, state) }, field, diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/theme/Theme.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/theme/Theme.kt index f5bb7634a..acd120118 100644 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ui/theme/Theme.kt +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/theme/Theme.kt @@ -26,16 +26,6 @@ private val LightColorScheme = lightColorScheme( onSurface = Color(0xFF212121), // Replace with your alfresco_gray_900 color background = Color.White, onBackground = Color.Black, - - /* Other default colors to override - background = Color(0xFFFFFBFE), - surface = Color(0xFFFFFBFE), - onPrimary = Color.White, - onSecondary = Color.White, - onTertiary = Color.White, - onBackground = Color(0xFF1C1B1F), - onSurface = Color(0xFF1C1B1F), - */ ) @Composable @@ -72,7 +62,7 @@ fun AlfrescoBaseTheme( val window = (view.context as Activity).window WindowCompat.setDecorFitsSystemWindows(window, false) window.statusBarColor = statusBarColor.toArgb() -// window.navigationBarColor = AlfrescoGray900.toArgb() + window.navigationBarColor = AlfrescoGray900.toArgb() WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = darkTheme } }