Begin refactoring FilterSettingsActivity

pull/3197/head
Alex Baker 12 months ago
parent e3edd4797a
commit be5a4dfc01

@ -4,6 +4,7 @@ import android.app.Activity
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
@ -12,19 +13,19 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState import androidx.compose.runtime.MutableState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.snapshots.SnapshotStateList import androidx.compose.runtime.remember
import androidx.compose.runtime.toMutableStateList
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import com.todoroo.astrid.activity.MainActivity import com.todoroo.astrid.activity.MainActivity
import com.todoroo.astrid.activity.TaskListFragment import com.todoroo.astrid.activity.TaskListFragment
import com.todoroo.astrid.api.BooleanCriterion import com.todoroo.astrid.api.BooleanCriterion
import com.todoroo.astrid.api.CustomFilterCriterion import com.todoroo.astrid.api.CustomFilterCriterion
import com.todoroo.astrid.api.MultipleSelectCriterion import com.todoroo.astrid.api.MultipleSelectCriterion
import com.todoroo.astrid.api.PermaSql
import com.todoroo.astrid.api.TextInputCriterion import com.todoroo.astrid.api.TextInputCriterion
import com.todoroo.astrid.core.CriterionInstance import com.todoroo.astrid.core.CriterionInstance
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
@ -41,118 +42,69 @@ import org.tasks.compose.FilterCondition.SelectFromList
import org.tasks.data.NO_ORDER import org.tasks.data.NO_ORDER
import org.tasks.data.dao.FilterDao import org.tasks.data.dao.FilterDao
import org.tasks.data.dao.TaskDao.TaskCriteria.activeAndVisible import org.tasks.data.dao.TaskDao.TaskCriteria.activeAndVisible
import org.tasks.data.db.Database
import org.tasks.data.entity.Filter import org.tasks.data.entity.Filter
import org.tasks.data.entity.Task import org.tasks.data.entity.Task
import org.tasks.data.rawQuery
import org.tasks.data.sql.Field
import org.tasks.data.sql.Query
import org.tasks.data.sql.UnaryCriterion import org.tasks.data.sql.UnaryCriterion
import org.tasks.db.QueryUtils
import org.tasks.extensions.Context.openUri import org.tasks.extensions.Context.openUri
import org.tasks.filters.CustomFilter import org.tasks.filters.CustomFilter
import org.tasks.filters.FilterCriteriaProvider import org.tasks.filters.FilterCriteriaProvider
import org.tasks.filters.mapToSerializedString import org.tasks.filters.mapToSerializedString
import org.tasks.themes.TasksIcons import org.tasks.themes.TasksIcons
import org.tasks.themes.TasksTheme import org.tasks.themes.TasksTheme
import java.util.Locale
import javax.inject.Inject import javax.inject.Inject
import kotlin.math.max
@AndroidEntryPoint @AndroidEntryPoint
class FilterSettingsActivity : BaseListSettingsActivity() { class FilterSettingsActivity : BaseListSettingsActivity() {
@Inject lateinit var filterDao: FilterDao @Inject lateinit var filterDao: FilterDao
@Inject lateinit var locale: Locale
@Inject lateinit var database: Database
@Inject lateinit var filterCriteriaProvider: FilterCriteriaProvider @Inject lateinit var filterCriteriaProvider: FilterCriteriaProvider
@Inject lateinit var localBroadcastManager: LocalBroadcastManager @Inject lateinit var localBroadcastManager: LocalBroadcastManager
private val viewModel: FilterSettingsViewModel by viewModels()
private var filter: CustomFilter? = null
override val defaultIcon = TasksIcons.FILTER_LIST override val defaultIcon = TasksIcons.FILTER_LIST
private var criteria: SnapshotStateList<CriterionInstance> = emptyList<CriterionInstance>().toMutableStateList()
private val fabExtended = mutableStateOf(false)
private val editCriterionType: MutableState<String?> = mutableStateOf(null) private val editCriterionType: MutableState<String?> = mutableStateOf(null)
private val newCriterionTypes: MutableState<List<CustomFilterCriterion>?> = mutableStateOf(null) private val newCriterionTypes: MutableState<List<CustomFilterCriterion>?> = mutableStateOf(null)
private val newCriterionOptions: MutableState<CriterionInstance?> = mutableStateOf(null) private val newCriterionOptions: MutableState<CriterionInstance?> = mutableStateOf(null)
private val filter: CustomFilter?
get() = viewModel.viewState.value.filter
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
filter = intent.getParcelableExtra(TOKEN_FILTER)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
if (savedInstanceState == null && filter != null) { if (savedInstanceState == null) {
selectedColor = filter!!.tint filter?.let {
selectedIcon.value = filter!!.icon ?: defaultIcon selectedColor = it.tint
textState.value = filter!!.title ?: "" selectedIcon.value = it.icon
} textState.value = it.title ?: ""
when {
savedInstanceState != null -> lifecycleScope.launch {
setCriteria(
filterCriteriaProvider.fromString(
savedInstanceState.getString(EXTRA_CRITERIA)!!
)
)
} }
filter != null -> lifecycleScope.launch {
setCriteria(filterCriteriaProvider.fromString(filter!!.criterion))
}
intent.hasExtra(EXTRA_CRITERIA) -> lifecycleScope.launch {
textState.value = intent.getStringExtra(EXTRA_TITLE) ?: ""
setCriteria(
filterCriteriaProvider.fromString(intent.getStringExtra(EXTRA_CRITERIA)!!)
)
} }
else -> setCriteria(universe()) if (savedInstanceState != null) {
intent.getStringExtra(EXTRA_TITLE)?.let { textState.value = it }
} }
updateTheme() updateTheme()
} /* end onCreate */ setContent {
private fun universe() = listOf(CriterionInstance().apply {
criterion = filterCriteriaProvider.startingUniverse
type = CriterionInstance.TYPE_UNIVERSE
})
private fun setCriteria(criteriaList: List<CriterionInstance>) {
criteria = criteriaList
.ifEmpty { universe() }
.toMutableStateList()
fabExtended.value = isNew || criteria.size <= 1
updateList()
this.setContent {
TasksTheme { ActivityContent() } TasksTheme { ActivityContent() }
} }
} }
private fun onDelete(index: Int) { private fun onDelete(index: Int) {
criteria.removeAt(index) viewModel.removeAt(index)
updateList()
}
private fun onMove(from: Int, to: Int) {
val criterion = criteria.removeAt(from)
criteria.add(to, criterion)
} }
private fun newCriterion() { private fun newCriterion() {
fabExtended.value = false // a.k.a. fab.shrink() viewModel.setFabExtended(false)
lifecycleScope.launch { lifecycleScope.launch {
newCriterionTypes.value = filterCriteriaProvider.all() newCriterionTypes.value = filterCriteriaProvider.all()
} }
} }
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putString(EXTRA_CRITERIA, CriterionInstance.serialize(criteria))
}
override val isNew: Boolean override val isNew: Boolean
get() = filter == null get() = viewModel.viewState.value.filter == null
override val toolbarTitle: String override val toolbarTitle: String
get() = if (isNew) getString(R.string.FLA_new_filter) else filter?.title ?: "" get() = if (isNew) getString(R.string.FLA_new_filter) else viewModel.viewState.value.filter?.title ?: ""
override suspend fun save() { override suspend fun save() {
val newName = newName val newName = newName
@ -162,6 +114,7 @@ class FilterSettingsActivity : BaseListSettingsActivity() {
} }
if (hasChanges()) { if (hasChanges()) {
val criteria = viewModel.viewState.value.criteria
var f = Filter( var f = Filter(
id = filter?.id ?: 0L, id = filter?.id ?: 0L,
title = newName, title = newName,
@ -195,6 +148,7 @@ class FilterSettingsActivity : BaseListSettingsActivity() {
get() = textState.value.trim { it <= ' ' } get() = textState.value.trim { it <= ' ' }
override fun hasChanges(): Boolean { override fun hasChanges(): Boolean {
val criteria = viewModel.viewState.value.criteria
return if (isNew) { return if (isNew) {
(!Strings.isNullOrEmpty(newName) (!Strings.isNullOrEmpty(newName)
|| selectedColor != 0 || selectedIcon.value?.isBlank() == false || criteria.size > 1) || selectedColor != 0 || selectedIcon.value?.isBlank() == false || criteria.size > 1)
@ -206,10 +160,6 @@ class FilterSettingsActivity : BaseListSettingsActivity() {
|| criteria.sql != filter!!.sql || criteria.sql != filter!!.sql
} }
override fun finish() {
super.finish()
}
override suspend fun delete() { override suspend fun delete() {
filterDao.delete(filter!!.id) filterDao.delete(filter!!.id)
setResult( setResult(
@ -219,48 +169,6 @@ class FilterSettingsActivity : BaseListSettingsActivity() {
private fun help() = openUri(R.string.url_filters) private fun help() = openUri(R.string.url_filters)
private fun updateList() = lifecycleScope.launch {
val newList = emptyList<CriterionInstance>().toMutableList()
var max = 0
var last = -1
val sql = StringBuilder(Query.select(Field.COUNT).from(Task.TABLE).toString())
.append(" WHERE ")
for (instance in criteria) {
when (instance.type) {
CriterionInstance.TYPE_ADD -> sql.append("OR ")
CriterionInstance.TYPE_SUBTRACT -> sql.append("AND NOT ")
CriterionInstance.TYPE_INTERSECT -> sql.append("AND ")
}
// special code for all tasks universe
if (instance.type == CriterionInstance.TYPE_UNIVERSE || instance.criterion.sql == null) {
sql.append(activeAndVisible()).append(' ')
} else {
var subSql: String = instance.criterion.sql.replace(
"?",
UnaryCriterion.sanitize(instance.valueFromCriterion!!)
)
subSql = PermaSql.replacePlaceholdersForQuery(subSql)
sql.append(Task.ID).append(" IN (").append(subSql).append(")")
}
val sqlString = QueryUtils.showHiddenAndCompleted(sql.toString())
database.rawQuery(sqlString) { cursor ->
cursor.step()
instance.start = if (last == -1) cursor.getInt(0) else last
instance.end = cursor.getInt(0)
last = instance.end
max = max(max, last)
}
newList.add(instance)
}
for (instance in newList) {
instance.max = max
}
criteria.clear()
criteria.addAll(newList)
}
@Composable @Composable
private fun ActivityContent () private fun ActivityContent ()
{ {
@ -269,6 +177,7 @@ class FilterSettingsActivity : BaseListSettingsActivity() {
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.TopStart contentAlignment = Alignment.TopStart
) { ) {
val viewState by viewModel.viewState.collectAsStateWithLifecycle()
BaseSettingsContent( BaseSettingsContent(
optionButton = { optionButton = {
if (isNew) { if (isNew) {
@ -279,21 +188,22 @@ class FilterSettingsActivity : BaseListSettingsActivity() {
} }
) { ) {
FilterCondition( FilterCondition(
items = criteria, items = viewState.criteria,
onDelete = { index -> onDelete(index) }, onDelete = { index -> onDelete(index) },
doSwap = { from, to -> onMove(from, to) }, doSwap = { from, to -> viewModel.move(from, to) },
onComplete = { updateList() },
onClick = { id -> editCriterionType.value = id } onClick = { id -> editCriterionType.value = id }
) )
} }
NewCriterionFAB(fabExtended) { newCriterion() } NewCriterionFAB(viewState.fabExtended) { newCriterion() }
/** edit given criterion type (AND|OR|NOT) **/ /** edit given criterion type (AND|OR|NOT) **/
editCriterionType.value?.let { itemId -> editCriterionType.value?.let { itemId ->
val index = criteria.indexOfFirst { it.id == itemId } val index = viewState.criteria.indexOfFirst { it.id == itemId }
assert(index >= 0) assert(index >= 0)
val criterionInstance = criteria[index] val criterionInstance = remember (index) {
CriterionInstance(viewState.criteria[index])
}
if (criterionInstance.type != CriterionInstance.TYPE_UNIVERSE) { if (criterionInstance.type != CriterionInstance.TYPE_UNIVERSE) {
SelectCriterionType( SelectCriterionType(
title = criterionInstance.titleFromCriterion, title = criterionInstance.titleFromCriterion,
@ -317,7 +227,7 @@ class FilterSettingsActivity : BaseListSettingsActivity() {
} }
if (criterionInstance.type != type) { if (criterionInstance.type != type) {
criterionInstance.type = type criterionInstance.type = type
updateList() viewModel.setCriterion(index, criterionInstance)
} }
editCriterionType.value = null editCriterionType.value = null
} }
@ -334,8 +244,7 @@ class FilterSettingsActivity : BaseListSettingsActivity() {
instance.criterion = list[which] instance.criterion = list[which]
newCriterionTypes.value = null newCriterionTypes.value = null
if (instance.criterion is BooleanCriterion) { if (instance.criterion is BooleanCriterion) {
criteria.add(instance) viewModel.addCriteria(instance)
updateList()
} else } else
newCriterionOptions.value = instance newCriterionOptions.value = instance
} }
@ -355,8 +264,7 @@ class FilterSettingsActivity : BaseListSettingsActivity() {
onCancel = { newCriterionOptions.value = null }, onCancel = { newCriterionOptions.value = null },
onSelected = { which -> onSelected = { which ->
instance.selectedIndex = which instance.selectedIndex = which
criteria.add(instance) viewModel.addCriteria(instance)
updateList()
newCriterionOptions.value = null newCriterionOptions.value = null
} }
) )
@ -370,8 +278,7 @@ class FilterSettingsActivity : BaseListSettingsActivity() {
onDone = { text -> onDone = { text ->
text.trim().takeIf{ it != "" }?. let { text -> text.trim().takeIf{ it != "" }?. let { text ->
instance.selectedText = text instance.selectedText = text
criteria.add(instance) viewModel.addCriteria(instance)
updateList()
} }
newCriterionOptions.value = null newCriterionOptions.value = null
} }

@ -0,0 +1,157 @@
package org.tasks.activities
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.todoroo.astrid.api.PermaSql
import com.todoroo.astrid.core.CriterionInstance
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import org.tasks.activities.FilterSettingsActivity.Companion.EXTRA_CRITERIA
import org.tasks.activities.FilterSettingsActivity.Companion.TOKEN_FILTER
import org.tasks.data.dao.TaskDao.TaskCriteria.activeAndVisible
import org.tasks.data.db.Database
import org.tasks.data.entity.Task
import org.tasks.data.rawQuery
import org.tasks.data.sql.Field
import org.tasks.data.sql.Query
import org.tasks.data.sql.UnaryCriterion
import org.tasks.db.QueryUtils
import org.tasks.filters.CustomFilter
import org.tasks.filters.FilterCriteriaProvider
import javax.inject.Inject
import kotlin.math.max
@HiltViewModel
class FilterSettingsViewModel @Inject constructor(
savedStateHandle: SavedStateHandle,
private val filterCriteriaProvider: FilterCriteriaProvider,
private val database: Database
) : ViewModel() {
data class ViewState(
val filter: CustomFilter? = null,
val fabExtended: Boolean = false,
val criteria: ImmutableList<CriterionInstance> = persistentListOf(),
)
private val _viewState = MutableStateFlow(
ViewState(
filter = savedStateHandle.get<CustomFilter>(TOKEN_FILTER),
)
)
val viewState: StateFlow<ViewState> = _viewState
init {
_viewState.value.filter
?.let { filter ->
viewModelScope.launch {
setCriteria(filterCriteriaProvider.fromString(filter.criterion))
}
}
?: savedStateHandle.get<String>(EXTRA_CRITERIA)?.let { criteria ->
viewModelScope.launch {
setCriteria(filterCriteriaProvider.fromString(criteria))
}
}
?: setCriteria(emptyList())
}
fun setFabExtended(extended: Boolean) {
_viewState.update { it.copy(fabExtended = extended) }
}
private fun setCriteria(criteria: List<CriterionInstance>) {
_viewState.update {
it.copy(
criteria = criteria.ifEmpty { universe() }.toImmutableList(),
fabExtended = it.filter == null || criteria.size <= 1,
)
}
viewModelScope.launch {
_viewState.update {
it.copy(criteria = updateCounts(it.criteria).toImmutableList())
}
}
}
fun removeAt(index: Int) {
setCriteria(_viewState.value.criteria.toMutableList().apply { removeAt(index) })
}
fun move(from: Int, to: Int) {
setCriteria(
_viewState.value.criteria
.toMutableList()
.apply {
val criterion = removeAt(from)
add(to, criterion)
}
)
}
fun addCriteria(instance: CriterionInstance) {
setCriteria(_viewState.value.criteria.toMutableList().apply { add(instance) })
}
private suspend fun updateCounts(criteria: List<CriterionInstance>): List<CriterionInstance> {
val newList = mutableListOf<CriterionInstance>()
var max = 0
var last = -1
val sql = StringBuilder(Query.select(Field.COUNT).from(Task.TABLE).toString())
.append(" WHERE ")
for (instance in criteria.map { CriterionInstance(it) }) {
when (instance.type) {
CriterionInstance.TYPE_ADD -> sql.append("OR ")
CriterionInstance.TYPE_SUBTRACT -> sql.append("AND NOT ")
CriterionInstance.TYPE_INTERSECT -> sql.append("AND ")
}
// special code for all tasks universe
if (instance.type == CriterionInstance.TYPE_UNIVERSE || instance.criterion.sql == null) {
sql.append(activeAndVisible()).append(' ')
} else {
var subSql: String = instance.criterion.sql.replace(
"?",
UnaryCriterion.sanitize(instance.valueFromCriterion!!)
)
subSql = PermaSql.replacePlaceholdersForQuery(subSql)
sql.append(Task.ID).append(" IN (").append(subSql).append(")")
}
val sqlString = QueryUtils.showHiddenAndCompleted(sql.toString())
database.rawQuery(sqlString) { cursor ->
cursor.step()
instance.start = if (last == -1) cursor.getInt(0) else last
instance.end = cursor.getInt(0)
last = instance.end
max = max(max, last)
}
newList.add(instance)
}
for (instance in newList) {
instance.max = max
}
return newList
}
private fun universe() = listOf(
CriterionInstance().apply {
criterion = filterCriteriaProvider.startingUniverse
type = CriterionInstance.TYPE_UNIVERSE
}
)
fun setCriterion(index: Int, criterionInstance: CriterionInstance) {
setCriteria(
_viewState.value.criteria.toMutableList().apply {
set(index, criterionInstance)
}
)
}
}

@ -39,11 +39,9 @@ import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableIntState import androidx.compose.runtime.MutableIntState
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.snapshots.SnapshotStateList
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
@ -61,10 +59,11 @@ import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.Dialog
import androidx.core.os.ConfigurationCompat import androidx.core.os.ConfigurationCompat
import com.todoroo.astrid.core.CriterionInstance import com.todoroo.astrid.core.CriterionInstance
import kotlinx.collections.immutable.ImmutableList
import org.tasks.R import org.tasks.R
import org.tasks.compose.SwipeOut.SwipeOut import org.tasks.compose.SwipeOut.SwipeOut
import org.tasks.kmp.org.tasks.compose.settings.SettingRow
import org.tasks.extensions.formatNumber import org.tasks.extensions.formatNumber
import org.tasks.kmp.org.tasks.compose.settings.SettingRow
import org.tasks.themes.TasksTheme import org.tasks.themes.TasksTheme
import java.util.Locale import java.util.Locale
@ -109,7 +108,7 @@ private fun SwipeOutDecorationPreview () {
private fun FabPreview () { private fun FabPreview () {
TasksTheme { TasksTheme {
FilterCondition.NewCriterionFAB( FilterCondition.NewCriterionFAB(
isExtended = remember { mutableStateOf(true) } isExtended = true
) { ) {
} }
@ -120,13 +119,11 @@ object FilterCondition {
@OptIn(ExperimentalFoundationApi::class) @OptIn(ExperimentalFoundationApi::class)
@Composable @Composable
fun FilterCondition( fun FilterCondition(
items: SnapshotStateList<CriterionInstance>, items: ImmutableList<CriterionInstance>,
onDelete: (Int) -> Unit, onDelete: (Int) -> Unit,
doSwap: (Int, Int) -> Unit, doSwap: (Int, Int) -> Unit,
onComplete: () -> Unit,
onClick: (String) -> Unit onClick: (String) -> Unit
) { ) {
val getIcon: (CriterionInstance) -> Int = { criterion -> val getIcon: (CriterionInstance) -> Int = { criterion ->
when (criterion.type) { when (criterion.type) {
CriterionInstance.TYPE_ADD -> R.drawable.ic_call_split_24px CriterionInstance.TYPE_ADD -> R.drawable.ic_call_split_24px
@ -141,9 +138,9 @@ object FilterCondition {
val dragDropState = rememberDragDropState( val dragDropState = rememberDragDropState(
lazyListState = listState, lazyListState = listState,
confirmDrag = { index -> index != 0 }, confirmDrag = { index -> index != 0 },
completeDragDrop = onComplete, completeDragDrop = {},
) { fromIndex, toIndex -> ) { fromIndex, toIndex ->
if (fromIndex != 0 && toIndex != 0) doSwap(fromIndex, toIndex) if (fromIndex != toIndex) doSwap(fromIndex, toIndex)
} }
Row { Row {
@ -282,10 +279,9 @@ object FilterCondition {
@Composable @Composable
fun NewCriterionFAB( fun NewCriterionFAB(
isExtended: MutableState<Boolean>, isExtended: Boolean,
onClick: () -> Unit onClick: () -> Unit
) { ) {
Box( // lays out over main content as a space to layout FAB Box( // lays out over main content as a space to layout FAB
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.BottomEnd contentAlignment = Alignment.BottomEnd
@ -297,17 +293,15 @@ object FilterCondition {
containerColor = MaterialTheme.colorScheme.secondary, containerColor = MaterialTheme.colorScheme.secondary,
contentColor = Color.White, contentColor = Color.White,
) { ) {
val extended = isExtended.value
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {
Icon( Icon(
imageVector = Icons.Outlined.Add, imageVector = Icons.Outlined.Add,
contentDescription = "New Criteria", contentDescription = "New Criteria",
modifier = Modifier.padding( modifier = Modifier.padding(
start = if (extended) 16.dp else 0.dp start = if (isExtended) 16.dp else 0.dp
) )
) )
if (extended) if (isExtended)
Text( Text(
text = LocalContext.current.getString(R.string.CFA_button_add), text = LocalContext.current.getString(R.string.CFA_button_add),
modifier = Modifier.padding(end = 16.dp) modifier = Modifier.padding(end = 16.dp)

Loading…
Cancel
Save