Turn the FAB's glyph between plus and a chevron (#141)
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
package de.jeanlucmakiola.calendula.ui.common
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.Crossfade
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.animation.expandHorizontally
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
@@ -9,6 +9,7 @@ import androidx.compose.animation.scaleIn
|
||||
import androidx.compose.animation.scaleOut
|
||||
import androidx.compose.animation.shrinkHorizontally
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.height
|
||||
@@ -16,7 +17,6 @@ import androidx.compose.foundation.layout.wrapContentHeight
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material.icons.filled.MoreHoriz
|
||||
import androidx.compose.material.icons.filled.Refresh
|
||||
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||
import androidx.compose.material3.ExtendedFloatingActionButton
|
||||
@@ -25,10 +25,14 @@ import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.semantics.contentDescription
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import de.jeanlucmakiola.calendula.R
|
||||
@@ -40,7 +44,6 @@ class FabSelection(
|
||||
val bar: @Composable () -> Unit,
|
||||
)
|
||||
|
||||
private enum class FabIcon { Create, Open, Fold }
|
||||
|
||||
/** The standard FAB's size, which the row it sits in is held to. */
|
||||
private val FAB_SIZE = 56.dp
|
||||
@@ -101,29 +104,53 @@ fun CalendarFabColumn(
|
||||
) {
|
||||
heldBar.value?.invoke()
|
||||
}
|
||||
val icon = when {
|
||||
selection == null -> FabIcon.Create
|
||||
selection.expanded -> FabIcon.Fold
|
||||
else -> FabIcon.Open
|
||||
}
|
||||
FloatingActionButton(onClick = selection?.onToggle ?: onCreate) {
|
||||
Crossfade(targetState = icon, label = "fab-icon") { shown ->
|
||||
when (shown) {
|
||||
FabIcon.Create -> Icon(
|
||||
imageVector = Icons.Default.Add,
|
||||
contentDescription = stringResource(R.string.event_edit_new_title),
|
||||
)
|
||||
FabIcon.Open -> Icon(
|
||||
imageVector = Icons.Default.MoreHoriz,
|
||||
contentDescription = stringResource(R.string.event_selection_actions),
|
||||
)
|
||||
FabIcon.Fold -> Icon(
|
||||
imageVector = Icons.AutoMirrored.Filled.KeyboardArrowRight,
|
||||
contentDescription = stringResource(R.string.event_selection_hide),
|
||||
)
|
||||
}
|
||||
}
|
||||
val label = stringResource(
|
||||
when {
|
||||
selection == null -> R.string.event_edit_new_title
|
||||
selection.expanded -> R.string.event_selection_hide
|
||||
else -> R.string.event_selection_actions
|
||||
},
|
||||
)
|
||||
FloatingActionButton(
|
||||
onClick = selection?.onToggle ?: onCreate,
|
||||
modifier = Modifier.semantics { contentDescription = label },
|
||||
) {
|
||||
FabGlyph(selecting = selection != null, expanded = selection?.expanded == true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The FAB's glyph: "+", or with an event selected a chevron pointing where the
|
||||
* bar unfolds — turned half round once it has, to fold it back. The "+" and the
|
||||
* chevron spin past each other rather than fading.
|
||||
*/
|
||||
@Composable
|
||||
private fun FabGlyph(selecting: Boolean, expanded: Boolean) {
|
||||
val spatial = MaterialTheme.motionScheme.fastSpatialSpec<Float>()
|
||||
val swap by animateFloatAsState(if (selecting) 1f else 0f, spatial, label = "fab-swap")
|
||||
val turn by animateFloatAsState(if (expanded) 0f else 180f, spatial, label = "fab-turn")
|
||||
Box(contentAlignment = Alignment.Center) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Add,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.graphicsLayer {
|
||||
rotationZ = 90f * swap
|
||||
scaleX = 1f - 0.5f * swap
|
||||
scaleY = 1f - 0.5f * swap
|
||||
alpha = (1f - swap).coerceIn(0f, 1f)
|
||||
},
|
||||
)
|
||||
Icon(
|
||||
imageVector = Icons.AutoMirrored.Filled.KeyboardArrowRight,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.graphicsLayer {
|
||||
rotationZ = turn - 90f * (1f - swap)
|
||||
scaleX = 0.5f + 0.5f * swap
|
||||
scaleY = 0.5f + 0.5f * swap
|
||||
alpha = swap.coerceIn(0f, 1f)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user