Skip to content

Commit

Permalink
ComposeMail - Improve MailItem composition logic
Browse files Browse the repository at this point in the history
  • Loading branch information
oscar-ad committed May 20, 2022
1 parent f1b5f58 commit a18db05
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,17 @@ private fun CheapTextPreview() {
Column(
Modifier
.width(40.dp)
.background(Color.LightGray)) {
.background(Color.LightGray)
) {
Text(text = "Hello \nWorld!")
Text(text = "This is a very very long text")
}
Text(text = "Cheap")
Column(
Modifier
.width(40.dp)
.background(Color.LightGray)) {
.background(Color.LightGray)
) {
CheapText(text = "Hello \nWorld!")
CheapText(text = "This is a very very long text")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Check
import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
Expand Down Expand Up @@ -64,65 +63,60 @@ fun MailItem(
state: MailItemState = MailItemState(-1) { _, _ -> },
info: MailEntryInfo?
) {
val shouldAnimate = remember { info == null }
var csTarget: String? by remember { mutableStateOf(null) }
val csTarget: MotionMailState =
when {
info == null -> MotionMailState.Loading
state.isSelected -> MotionMailState.Selected
else -> MotionMailState.Normal
}
MotionLayoutMail(
modifier = modifier,
info = info ?: MailEntryInfo.Default,
startsEmpty = shouldAnimate,
targetId = csTarget,
targetState = csTarget,
onSelectedMail = {
// Toggle selection
state.setSelected(!state.isSelected)
}
)
if (shouldAnimate) {
if (info != null && csTarget == null) {
SideEffect {
csTarget = "normal"
}
}
} else {
if (info != null) {
val nextState = if (state.isSelected) {
"flipped"
} else {
"normal"
}
SideEffect {
csTarget = nextState
}
}
}
}

const val ANIMATION_DURATION: Int = 400

enum class MotionMailState(val tag: String) {
Loading("empty"),
Normal("normal"),
Selected("flipped")
}

@Suppress("NOTHING_TO_INLINE", "EXPERIMENTAL_API_USAGE")
@Composable
inline fun MotionLayoutMail(
modifier: Modifier = Modifier,
info: MailEntryInfo,
startsEmpty: Boolean,
targetId: String?,
targetState: MotionMailState,
crossinline onSelectedMail: (id: Int) -> Unit
) {
val backgroundColor by animateColorAsState(
targetValue = if (targetId == "flipped") {
MaterialTheme.colors.textBackgroundColor
} else {
MaterialTheme.colors.background
targetValue = when (targetState) {
MotionMailState.Selected -> MaterialTheme.colors.textBackgroundColor
else -> MaterialTheme.colors.background
},
animationSpec = tween<Color>(ANIMATION_DURATION)
)
val startId = if (startsEmpty) "empty" else "normal"
val endId = if (startsEmpty) "normal" else "empty"
val initialStart = remember { targetState }
val initialEnd = remember {
when (initialStart) {
MotionMailState.Loading -> MotionMailState.Normal
else -> MotionMailState.Loading
}
}

val motionSceneContent = remember(startId, endId) {
val motionSceneContent = remember {
//language=json5
"""
{
ConstraintSets: {
normal: {
${MotionMailState.Normal.tag}: {
picture: {
width: 60, height: 60,
centerVertically: 'parent',
Expand All @@ -146,8 +140,8 @@ inline fun MotionLayoutMail(
end: ['parent', 'start', 32]
}
},
flipped: {
Extends: 'normal',
${MotionMailState.Selected.tag}: {
Extends: '${MotionMailState.Normal.tag}',
picture: {
rotationY: -180,
alpha: 0.0
Expand All @@ -157,7 +151,7 @@ inline fun MotionLayoutMail(
alpha: 1.0
}
},
empty: {
${MotionMailState.Loading.tag}: {
picture: {
width: 60, height: 60,
top: ['content', 'top', 0],
Expand All @@ -183,12 +177,12 @@ inline fun MotionLayoutMail(
},
Transitions: {
default: {
from: '$startId',
to: '$endId',
from: '${initialStart.tag}',
to: '${initialEnd.tag}',
},
flip: {
from: 'normal',
to: 'flipped',
from: '${MotionMailState.Normal.tag}',
to: '${MotionMailState.Selected.tag}',
KeyFrames: {
KeyAttributes: [
{
Expand All @@ -212,7 +206,7 @@ inline fun MotionLayoutMail(
.fillMaxSize()
.clip(RectangleShape)
.padding(8.dp),
constraintSetName = targetId,
constraintSetName = targetState.tag,
animationSpec = tween<Float>(ANIMATION_DURATION),
motionScene = MotionScene(content = motionSceneContent)
) {
Expand Down Expand Up @@ -241,7 +235,7 @@ inline fun MotionLayoutMail(
modifier = Modifier.layoutId("loading"),
contentAlignment = Alignment.Center
) {
// TODO: Find a good way of not composing this when animation ends
// TODO: Find a way of not composing this (or stop the animation) when transition ends
CircularProgressIndicator(
modifier = Modifier.size(40.dp)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ package com.example.composemail.ui.mails

import androidx.compose.runtime.mutableStateOf

class MailItemState(val id: Int, private val onSelected: (Int, Boolean) -> Unit) {
class MailItemState(val id: Int, private val onSelected: (id: Int, isSelected: Boolean) -> Unit) {
private val _isSelected = mutableStateOf(false)
val isSelected
get() = _isSelected.value
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ import androidx.compose.runtime.remember
@Suppress("NOTHING_TO_INLINE")
@Composable
inline fun rememberNewMailState(
vararg keys: Any? = arrayOf(Unit),
key: Any = Unit,
initialLayoutState: NewMailLayoutState
): NewMailState {
return remember(*keys) { NewMailState(initialLayoutState) }
return remember(key) { NewMailState(initialLayoutState) }
}

class NewMailState(initialLayoutState: NewMailLayoutState) {
Expand Down

0 comments on commit a18db05

Please sign in to comment.