Skip to content

Instantly share code, notes, and snippets.

@fvilarino
Created April 26, 2024 01:59
Show Gist options
  • Save fvilarino/9b78a63c062fa4ce04105cea5071740f to your computer and use it in GitHub Desktop.
Save fvilarino/9b78a63c062fa4ce04105cea5071740f to your computer and use it in GitHub Desktop.
Container Transform - Final
data class User(
val name: String,
val email: String,
)
@OptIn(ExperimentalSharedTransitionApi::class)
@Composable
fun MorphingFab(modifier: Modifier = Modifier) {
val users = remember { mutableStateListOf<User>() }
var showDialog by remember { mutableStateOf(false) }
SharedTransitionLayout(
modifier = Modifier
.fillMaxSize(),
) {
Box(modifier = modifier) {
UserList(
users = users,
modifier = Modifier.fillMaxSize(),
)
AnimatedContent(
targetState = showDialog,
modifier = modifier,
label = "morphing_fab",
) { addingUser ->
if (addingUser) {
Box {
InputBox(
onAddUser = {
users.add(it)
showDialog = false
},
onCancel = { showDialog = false },
modifier = Modifier
.align(Alignment.Center)
.width(320.dp)
.shadow(elevation = 4.dp)
.sharedBounds(
sharedContentState = rememberSharedContentState(key = "fab"),
animatedVisibilityScope = this@AnimatedContent,
),
)
}
} else {
Box {
FloatingActionButton(
modifier = Modifier
.align(Alignment.BottomEnd)
.padding(all = 16.dp)
.sharedBounds(
sharedContentState = rememberSharedContentState(key = "fab"),
animatedVisibilityScope = this@AnimatedContent,
),
onClick = {
showDialog = true
}
) {
Icon(
imageVector = Icons.Default.Add,
contentDescription = "Add",
)
}
}
}
}
}
}
}
@Composable
fun UserList(
users: List<User>,
modifier: Modifier = Modifier,
) {
LazyColumn(
modifier = modifier,
verticalArrangement = Arrangement.spacedBy(16.dp),
contentPadding = PaddingValues(16.dp),
) {
items(
items = users,
key = { user -> user.email },
) { user ->
UserCard(
user = user,
modifier = Modifier.fillMaxWidth(),
)
}
}
}
@Composable
fun InputBox(
onAddUser: (User) -> Unit,
onCancel: () -> Unit,
modifier: Modifier = Modifier,
) {
Card(
modifier = modifier,
colors = CardDefaults.cardColors().copy(
containerColor = MaterialTheme.colorScheme.tertiaryContainer
),
) {
var name by remember { mutableStateOf("") }
var email by remember { mutableStateOf("") }
val canAdd by remember {
derivedStateOf {
name.isNotBlank() && email.isNotBlank()
}
}
val focusManager = LocalFocusManager.current
Column(
modifier = Modifier
.fillMaxWidth()
.padding(all = 16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp),
) {
OutlinedTextField(
value = name,
onValueChange = { name = it },
modifier = Modifier.fillMaxWidth(),
label = { Text(text = "Name") },
keyboardOptions = KeyboardOptions(
imeAction = ImeAction.Next,
),
keyboardActions = KeyboardActions(
onNext = {
focusManager.moveFocus(FocusDirection.Down)
},
),
)
OutlinedTextField(
value = email,
onValueChange = { email = it },
modifier = Modifier.fillMaxWidth(),
label = { Text(text = "Email") },
keyboardOptions = KeyboardOptions(
imeAction = ImeAction.Done,
),
keyboardActions = KeyboardActions(
onDone = {
if (canAdd) {
onAddUser(User(name, email))
name = ""
email = ""
}
}
)
)
Spacer(modifier = Modifier.height(16.dp))
Row(
modifier = Modifier.align(Alignment.End),
horizontalArrangement = Arrangement.spacedBy(16.dp),
) {
TextButton(
onClick = onCancel
) {
Text(text = "Cancel")
}
TextButton(
onClick = {
onAddUser(User(name, email))
name = ""
email = ""
},
enabled = canAdd,
) {
Text(text = "Add")
}
}
}
}
}
@Composable
fun UserCard(
user: User,
modifier: Modifier = Modifier,
) {
Card(modifier = modifier) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(all = 16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp),
) {
LineListItem(label = "Name", value = user.name)
LineListItem(label = "Email", value = user.email)
}
}
}
@Composable
fun LineListItem(
label: String,
value: String,
modifier: Modifier = Modifier
) {
Column(
verticalArrangement = Arrangement.spacedBy(8.dp),
modifier = modifier,
) {
Text(text = label, style = MaterialTheme.typography.bodyMedium)
Text(text = value, style = MaterialTheme.typography.bodyLarge)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment