|
|
@ -39,6 +39,8 @@ import androidx.compose.material3.IconButton
|
|
|
|
import androidx.compose.material3.MaterialTheme
|
|
|
|
import androidx.compose.material3.MaterialTheme
|
|
|
|
import androidx.compose.material3.Scaffold
|
|
|
|
import androidx.compose.material3.Scaffold
|
|
|
|
import androidx.compose.material3.Text
|
|
|
|
import androidx.compose.material3.Text
|
|
|
|
|
|
|
|
import androidx.compose.material3.TopAppBar
|
|
|
|
|
|
|
|
import androidx.compose.material3.TopAppBarDefaults
|
|
|
|
import androidx.compose.runtime.Composable
|
|
|
|
import androidx.compose.runtime.Composable
|
|
|
|
import androidx.compose.runtime.getValue
|
|
|
|
import androidx.compose.runtime.getValue
|
|
|
|
import androidx.compose.runtime.mutableStateOf
|
|
|
|
import androidx.compose.runtime.mutableStateOf
|
|
|
@ -67,77 +69,56 @@ import kotlin.math.roundToInt
|
|
|
|
@OptIn(ExperimentalMaterial3Api::class)
|
|
|
|
@OptIn(ExperimentalMaterial3Api::class)
|
|
|
|
@Composable
|
|
|
|
@Composable
|
|
|
|
fun TaskListDrawer(
|
|
|
|
fun TaskListDrawer(
|
|
|
|
begForMoney: Boolean,
|
|
|
|
bottomSearchBar: Boolean,
|
|
|
|
filters: ImmutableList<DrawerItem>,
|
|
|
|
filters: ImmutableList<DrawerItem>,
|
|
|
|
onClick: (DrawerItem) -> Unit,
|
|
|
|
onClick: (DrawerItem) -> Unit,
|
|
|
|
onDrawerAction: (DrawerAction) -> Unit,
|
|
|
|
|
|
|
|
onAddClick: (DrawerItem.Header) -> Unit,
|
|
|
|
onAddClick: (DrawerItem.Header) -> Unit,
|
|
|
|
onErrorClick: () -> Unit,
|
|
|
|
onErrorClick: () -> Unit,
|
|
|
|
query: String,
|
|
|
|
searchBar: @Composable RowScope.() -> Unit,
|
|
|
|
onQueryChange: (String) -> Unit,
|
|
|
|
|
|
|
|
) {
|
|
|
|
) {
|
|
|
|
val bottomAppBarScrollBehavior = BottomAppBarDefaults.exitAlwaysScrollBehavior()
|
|
|
|
val bottomAppBarScrollBehavior = BottomAppBarDefaults.exitAlwaysScrollBehavior()
|
|
|
|
|
|
|
|
val topAppBarScrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
|
|
|
|
Scaffold(
|
|
|
|
Scaffold(
|
|
|
|
modifier = Modifier
|
|
|
|
modifier = Modifier
|
|
|
|
.nestedScroll(bottomAppBarScrollBehavior.nestedScrollConnection),
|
|
|
|
.nestedScroll(
|
|
|
|
|
|
|
|
if (bottomSearchBar)
|
|
|
|
|
|
|
|
bottomAppBarScrollBehavior.nestedScrollConnection
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
topAppBarScrollBehavior.nestedScrollConnection
|
|
|
|
|
|
|
|
),
|
|
|
|
bottomBar = {
|
|
|
|
bottomBar = {
|
|
|
|
BottomAppBar(
|
|
|
|
if (bottomSearchBar) {
|
|
|
|
modifier = Modifier.layout { measurable, constraints ->
|
|
|
|
BottomAppBar(
|
|
|
|
val placeable = measurable.measure(constraints)
|
|
|
|
modifier = Modifier.layout { measurable, constraints ->
|
|
|
|
bottomAppBarScrollBehavior.state.heightOffsetLimit = -placeable.height.toFloat()
|
|
|
|
val placeable = measurable.measure(constraints)
|
|
|
|
val height = placeable.height + bottomAppBarScrollBehavior.state.heightOffset
|
|
|
|
bottomAppBarScrollBehavior.state.heightOffsetLimit =
|
|
|
|
layout(placeable.width, height.roundToInt().coerceAtLeast(0)) {
|
|
|
|
-placeable.height.toFloat()
|
|
|
|
placeable.place(0, 0)
|
|
|
|
val height =
|
|
|
|
}
|
|
|
|
placeable.height + bottomAppBarScrollBehavior.state.heightOffset
|
|
|
|
},
|
|
|
|
layout(placeable.width, height.roundToInt().coerceAtLeast(0)) {
|
|
|
|
containerColor = MaterialTheme.colorScheme.surface,
|
|
|
|
placeable.place(0, 0)
|
|
|
|
scrollBehavior = bottomAppBarScrollBehavior
|
|
|
|
}
|
|
|
|
) {
|
|
|
|
|
|
|
|
var hasFocus by remember { mutableStateOf(false) }
|
|
|
|
|
|
|
|
SearchBar(
|
|
|
|
|
|
|
|
modifier = Modifier
|
|
|
|
|
|
|
|
.onFocusChanged { hasFocus = it.hasFocus }
|
|
|
|
|
|
|
|
.padding(start = 8.dp, end = if (hasFocus) 8.dp else 0.dp, bottom = 4.dp)
|
|
|
|
|
|
|
|
.weight(1f)
|
|
|
|
|
|
|
|
.animateContentSize(
|
|
|
|
|
|
|
|
animationSpec = spring(
|
|
|
|
|
|
|
|
dampingRatio = Spring.DampingRatioNoBouncy,
|
|
|
|
|
|
|
|
stiffness = Spring.StiffnessMedium
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
text = query,
|
|
|
|
|
|
|
|
onTextChange = { onQueryChange(it) },
|
|
|
|
|
|
|
|
placeHolder = stringResource(Res.string.search),
|
|
|
|
|
|
|
|
onCloseClicked = { onQueryChange("") },
|
|
|
|
|
|
|
|
onSearchClicked = {
|
|
|
|
|
|
|
|
// TODO: close keyboard
|
|
|
|
|
|
|
|
},
|
|
|
|
},
|
|
|
|
)
|
|
|
|
containerColor = MaterialTheme.colorScheme.surface,
|
|
|
|
if (!hasFocus) {
|
|
|
|
scrollBehavior = bottomAppBarScrollBehavior
|
|
|
|
if (begForMoney) {
|
|
|
|
) {
|
|
|
|
IconButton(onClick = { onDrawerAction(DrawerAction.PURCHASE) }) {
|
|
|
|
searchBar()
|
|
|
|
Icon(
|
|
|
|
}
|
|
|
|
imageVector = Icons.Outlined.AttachMoney,
|
|
|
|
}
|
|
|
|
contentDescription = stringResource(Res.string.subscribe),
|
|
|
|
},
|
|
|
|
tint = MaterialTheme.colorScheme.onSurface,
|
|
|
|
topBar = {
|
|
|
|
)
|
|
|
|
if (!bottomSearchBar) {
|
|
|
|
|
|
|
|
TopAppBar(
|
|
|
|
|
|
|
|
colors = TopAppBarDefaults.topAppBarColors(
|
|
|
|
|
|
|
|
containerColor = MaterialTheme.colorScheme.surface,
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
scrollBehavior = topAppBarScrollBehavior,
|
|
|
|
|
|
|
|
title = {
|
|
|
|
|
|
|
|
Row {
|
|
|
|
|
|
|
|
searchBar()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
IconButton(onClick = { onDrawerAction(DrawerAction.HELP_AND_FEEDBACK) }) {
|
|
|
|
)
|
|
|
|
Icon(
|
|
|
|
|
|
|
|
imageVector = Icons.AutoMirrored.Outlined.HelpOutline,
|
|
|
|
|
|
|
|
contentDescription = stringResource(Res.string.help_and_feedback),
|
|
|
|
|
|
|
|
tint = MaterialTheme.colorScheme.onSurface,
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
IconButton(onClick = { onDrawerAction(DrawerAction.SETTINGS) }) {
|
|
|
|
|
|
|
|
Icon(
|
|
|
|
|
|
|
|
imageVector = Icons.Outlined.Settings,
|
|
|
|
|
|
|
|
contentDescription = stringResource(Res.string.settings),
|
|
|
|
|
|
|
|
tint = MaterialTheme.colorScheme.onSurface,
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
) { contentPadding ->
|
|
|
|
) { contentPadding ->
|
|
|
@ -145,14 +126,17 @@ fun TaskListDrawer(
|
|
|
|
modifier = Modifier
|
|
|
|
modifier = Modifier
|
|
|
|
.fillMaxSize(),
|
|
|
|
.fillMaxSize(),
|
|
|
|
contentPadding = PaddingValues(
|
|
|
|
contentPadding = PaddingValues(
|
|
|
|
bottom = maxOf(
|
|
|
|
top = if (bottomSearchBar) 0.dp else contentPadding.calculateTopPadding(),
|
|
|
|
|
|
|
|
bottom = if (bottomSearchBar)
|
|
|
|
|
|
|
|
maxOf(
|
|
|
|
WindowInsets.mandatorySystemGestures
|
|
|
|
WindowInsets.mandatorySystemGestures
|
|
|
|
.asPaddingValues()
|
|
|
|
.asPaddingValues()
|
|
|
|
.calculateBottomPadding(),
|
|
|
|
.calculateBottomPadding(),
|
|
|
|
contentPadding.calculateBottomPadding()
|
|
|
|
contentPadding.calculateBottomPadding()
|
|
|
|
)
|
|
|
|
) else
|
|
|
|
|
|
|
|
48.dp
|
|
|
|
),
|
|
|
|
),
|
|
|
|
verticalArrangement = Arrangement.Bottom,
|
|
|
|
verticalArrangement = if (bottomSearchBar) Arrangement.Bottom else Arrangement.Top,
|
|
|
|
) {
|
|
|
|
) {
|
|
|
|
items(items = filters, key = { it.key() }) {
|
|
|
|
items(items = filters, key = { it.key() }) {
|
|
|
|
when (it) {
|
|
|
|
when (it) {
|
|
|
@ -294,3 +278,61 @@ private fun MenuRow(
|
|
|
|
content = content
|
|
|
|
content = content
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Composable
|
|
|
|
|
|
|
|
fun RowScope.MenuSearchBar(
|
|
|
|
|
|
|
|
begForMoney: Boolean,
|
|
|
|
|
|
|
|
onDrawerAction: (DrawerAction) -> Unit,
|
|
|
|
|
|
|
|
query: String,
|
|
|
|
|
|
|
|
onQueryChange: (String) -> Unit,
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
var hasFocus by remember { mutableStateOf(false) }
|
|
|
|
|
|
|
|
SearchBar(
|
|
|
|
|
|
|
|
modifier = Modifier
|
|
|
|
|
|
|
|
.onFocusChanged { hasFocus = it.hasFocus }
|
|
|
|
|
|
|
|
.padding(
|
|
|
|
|
|
|
|
start = 8.dp,
|
|
|
|
|
|
|
|
end = if (hasFocus) 8.dp else 0.dp,
|
|
|
|
|
|
|
|
bottom = 4.dp
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
.weight(1f)
|
|
|
|
|
|
|
|
.animateContentSize(
|
|
|
|
|
|
|
|
animationSpec = spring(
|
|
|
|
|
|
|
|
dampingRatio = Spring.DampingRatioNoBouncy,
|
|
|
|
|
|
|
|
stiffness = Spring.StiffnessMedium
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
text = query,
|
|
|
|
|
|
|
|
onTextChange = { onQueryChange(it) },
|
|
|
|
|
|
|
|
placeHolder = stringResource(Res.string.search),
|
|
|
|
|
|
|
|
onCloseClicked = { onQueryChange("") },
|
|
|
|
|
|
|
|
onSearchClicked = {
|
|
|
|
|
|
|
|
// TODO: close keyboard
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
if (!hasFocus) {
|
|
|
|
|
|
|
|
if (begForMoney) {
|
|
|
|
|
|
|
|
IconButton(onClick = { onDrawerAction(DrawerAction.PURCHASE) }) {
|
|
|
|
|
|
|
|
Icon(
|
|
|
|
|
|
|
|
imageVector = Icons.Outlined.AttachMoney,
|
|
|
|
|
|
|
|
contentDescription = stringResource(Res.string.subscribe),
|
|
|
|
|
|
|
|
tint = MaterialTheme.colorScheme.onSurface,
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
IconButton(onClick = { onDrawerAction(DrawerAction.HELP_AND_FEEDBACK) }) {
|
|
|
|
|
|
|
|
Icon(
|
|
|
|
|
|
|
|
imageVector = Icons.AutoMirrored.Outlined.HelpOutline,
|
|
|
|
|
|
|
|
contentDescription = stringResource(Res.string.help_and_feedback),
|
|
|
|
|
|
|
|
tint = MaterialTheme.colorScheme.onSurface,
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
IconButton(onClick = { onDrawerAction(DrawerAction.SETTINGS) }) {
|
|
|
|
|
|
|
|
Icon(
|
|
|
|
|
|
|
|
imageVector = Icons.Outlined.Settings,
|
|
|
|
|
|
|
|
contentDescription = stringResource(Res.string.settings),
|
|
|
|
|
|
|
|
tint = MaterialTheme.colorScheme.onSurface,
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|