You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
125 lines
4.5 KiB
125 lines
4.5 KiB
package io.eugenethedev.taigamobile.ui.components.editors
|
|
|
|
import androidx.annotation.StringRes
|
|
import androidx.compose.animation.*
|
|
import androidx.compose.animation.core.MutableTransitionState
|
|
import androidx.compose.animation.core.tween
|
|
import androidx.compose.foundation.background
|
|
import androidx.compose.foundation.layout.*
|
|
import androidx.compose.foundation.lazy.LazyColumn
|
|
import androidx.compose.foundation.lazy.LazyItemScope
|
|
import androidx.compose.foundation.lazy.itemsIndexed
|
|
import androidx.compose.material.Divider
|
|
import androidx.compose.material3.MaterialTheme
|
|
import androidx.compose.material3.Text
|
|
import androidx.compose.runtime.*
|
|
import androidx.compose.runtime.saveable.rememberSaveable
|
|
import androidx.compose.ui.Alignment
|
|
import androidx.compose.ui.Modifier
|
|
import androidx.compose.ui.res.stringResource
|
|
import androidx.compose.ui.text.input.TextFieldValue
|
|
import androidx.compose.ui.unit.dp
|
|
import androidx.paging.LoadState
|
|
import androidx.paging.compose.LazyPagingItems
|
|
import androidx.paging.compose.itemsIndexed as itemsIndexedLazy
|
|
import com.google.accompanist.insets.navigationBarsHeight
|
|
import io.eugenethedev.taigamobile.ui.components.appbars.AppBarWithBackButton
|
|
import io.eugenethedev.taigamobile.ui.components.loaders.DotsLoader
|
|
import io.eugenethedev.taigamobile.ui.utils.onBackPressed
|
|
|
|
/**
|
|
* Selector list, which expands from bottom to top.
|
|
* Could be used to search and select something
|
|
*/
|
|
@Composable
|
|
fun <T : Any> SelectorList(
|
|
@StringRes titleHintId: Int,
|
|
items: List<T> = emptyList(),
|
|
itemsLazy: LazyPagingItems<T>? = null,
|
|
key: ((index: Int, item: T) -> Any)? = null, // used to preserve position with lazy items
|
|
isVisible: Boolean = false,
|
|
isItemsLoading: Boolean = false,
|
|
isSearchable: Boolean = true,
|
|
searchData: (String) -> Unit = {},
|
|
navigateBack: () -> Unit = {},
|
|
animationDurationMillis: Int = SelectorListConstants.defaultAnimDurationMillis,
|
|
itemContent: @Composable (T) -> Unit
|
|
) = AnimatedVisibility(
|
|
visibleState = remember { MutableTransitionState(false) }
|
|
.apply { targetState = isVisible },
|
|
enter = slideInVertically(initialOffsetY = { it }, animationSpec = tween(animationDurationMillis)),
|
|
exit = slideOutVertically(targetOffsetY = { it }, animationSpec = tween(animationDurationMillis))
|
|
) {
|
|
var query by rememberSaveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue()) }
|
|
|
|
onBackPressed(navigateBack)
|
|
|
|
val isLoading = itemsLazy
|
|
?.run { loadState.refresh is LoadState.Loading || loadState.append is LoadState.Loading }
|
|
?: isItemsLoading
|
|
|
|
val lastIndex = itemsLazy?.itemCount?.minus(1) ?: items.lastIndex
|
|
|
|
val listItemContent: @Composable LazyItemScope.(Int, T?) -> Unit = lambda@ { index, item ->
|
|
if (item == null) return@lambda
|
|
|
|
itemContent(item)
|
|
|
|
if (index < lastIndex) {
|
|
Divider(
|
|
modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp),
|
|
color = MaterialTheme.colorScheme.outline
|
|
)
|
|
}
|
|
}
|
|
|
|
Column(
|
|
modifier = Modifier.fillMaxSize().background(MaterialTheme.colorScheme.surface),
|
|
horizontalAlignment = Alignment.CenterHorizontally
|
|
) {
|
|
|
|
AppBarWithBackButton(
|
|
title = {
|
|
Box(
|
|
modifier = Modifier.fillMaxSize(),
|
|
contentAlignment = Alignment.CenterStart
|
|
) {
|
|
if (isSearchable) {
|
|
TextFieldWithHint(
|
|
hintId = titleHintId,
|
|
value = query,
|
|
onValueChange = { query = it },
|
|
singleLine = true,
|
|
onSearchClick = { searchData(query.text) }
|
|
)
|
|
} else {
|
|
Text(stringResource(titleHintId))
|
|
}
|
|
}
|
|
},
|
|
navigateBack = navigateBack
|
|
)
|
|
|
|
LazyColumn {
|
|
itemsLazy?.let {
|
|
itemsIndexedLazy(
|
|
items = it,
|
|
key = key,
|
|
itemContent = listItemContent
|
|
)
|
|
} ?: itemsIndexed(items, itemContent = listItemContent)
|
|
|
|
item {
|
|
if (isLoading) {
|
|
DotsLoader()
|
|
}
|
|
Spacer(Modifier.navigationBarsHeight(8.dp))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
object SelectorListConstants {
|
|
const val defaultAnimDurationMillis = 200
|
|
}
|