mirror of
https://github.com/bitwarden/android.git
synced 2025-03-15 18:58:59 +03:00
Add Modifier.scrolledContainerBackground (#407)
This commit is contained in:
parent
8015fc7b5f
commit
ff4eeced33
4 changed files with 154 additions and 18 deletions
|
@ -0,0 +1,33 @@
|
|||
package com.x8bit.bitwarden.ui.platform.base.util
|
||||
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.drawBehind
|
||||
import com.x8bit.bitwarden.data.platform.annotation.OmitFromCoverage
|
||||
|
||||
/**
|
||||
* Adds a performance-optimized background color specified by the given [topAppBarScrollBehavior]
|
||||
* and its current scroll state.
|
||||
*/
|
||||
@OmitFromCoverage
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Stable
|
||||
@Composable
|
||||
fun Modifier.scrolledContainerBackground(
|
||||
topAppBarScrollBehavior: TopAppBarScrollBehavior,
|
||||
): Modifier {
|
||||
val expandedColor = MaterialTheme.colorScheme.surface
|
||||
val collapsedColor = MaterialTheme.colorScheme.surfaceContainer
|
||||
return this then drawBehind {
|
||||
drawRect(
|
||||
color = topAppBarScrollBehavior.toScrolledContainerColor(
|
||||
expandedColor = expandedColor,
|
||||
collapsedColor = collapsedColor,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package com.x8bit.bitwarden.ui.platform.base.util
|
||||
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.lerp
|
||||
|
||||
/**
|
||||
* Returns the correct color for a scrolled container based on the given [TopAppBarScrollBehavior]
|
||||
* and target [expandedColor] / [collapsedColor].
|
||||
*/
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
fun TopAppBarScrollBehavior.toScrolledContainerColor(
|
||||
expandedColor: Color,
|
||||
collapsedColor: Color,
|
||||
): Color {
|
||||
val progressFraction = if (this.isPinned) {
|
||||
this.state.overlappedFraction
|
||||
} else {
|
||||
this.state.collapsedFraction
|
||||
}
|
||||
return lerp(
|
||||
start = expandedColor,
|
||||
stop = collapsedColor,
|
||||
fraction = progressFraction,
|
||||
)
|
||||
}
|
|
@ -35,14 +35,13 @@ import androidx.compose.runtime.remember
|
|||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.drawBehind
|
||||
import androidx.compose.ui.graphics.lerp
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.semantics.clearAndSetSemantics
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.lowercaseWithCurrentLocal
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.scrolledContainerBackground
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.toSafeOverlayColor
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.toUnscaledTextUnit
|
||||
import com.x8bit.bitwarden.ui.platform.components.model.AccountSummary
|
||||
|
@ -185,8 +184,6 @@ private fun AnimatedAccountSwitcher(
|
|||
topAppBarScrollBehavior: TopAppBarScrollBehavior,
|
||||
currentAnimationState: (isVisible: Boolean) -> Unit,
|
||||
) {
|
||||
val expandedColor = MaterialTheme.colorScheme.surface
|
||||
val collapsedColor = MaterialTheme.colorScheme.surfaceContainer
|
||||
val transition = updateTransition(
|
||||
targetState = isVisible,
|
||||
label = "AnimatedAccountSwitcher",
|
||||
|
@ -203,20 +200,7 @@ private fun AnimatedAccountSwitcher(
|
|||
// bottom padding.
|
||||
.padding(bottom = 24.dp)
|
||||
// Match the color of the switcher the different states of the app bar.
|
||||
.drawBehind {
|
||||
val progressFraction = if (topAppBarScrollBehavior.isPinned) {
|
||||
topAppBarScrollBehavior.state.overlappedFraction
|
||||
} else {
|
||||
topAppBarScrollBehavior.state.collapsedFraction
|
||||
}
|
||||
val contentBackgroundColor =
|
||||
lerp(
|
||||
start = expandedColor,
|
||||
stop = collapsedColor,
|
||||
fraction = progressFraction,
|
||||
)
|
||||
drawRect(contentBackgroundColor)
|
||||
},
|
||||
.scrolledContainerBackground(topAppBarScrollBehavior),
|
||||
) {
|
||||
items(accountSummaries) { accountSummary ->
|
||||
AccountSummaryItem(
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
package com.x8bit.bitwarden.ui.platform.base.util
|
||||
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import org.junit.Test
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
class TopAppBarScrollBehaviorExtensionsTest {
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `toScrolledContainerColor for pinned states should interpolate based on the overlappedFraction`() {
|
||||
val expandedColor = Color(
|
||||
red = 0f,
|
||||
green = 0f,
|
||||
blue = 0f,
|
||||
alpha = 0f,
|
||||
)
|
||||
val collapsedColor = Color(
|
||||
red = 1f,
|
||||
green = 1f,
|
||||
blue = 1f,
|
||||
alpha = 1f,
|
||||
)
|
||||
var overlappedFraction = 0f
|
||||
val topAppBarScrollBehavior = mockk<TopAppBarScrollBehavior> {
|
||||
every { isPinned } returns true
|
||||
every { state.overlappedFraction } answers { overlappedFraction }
|
||||
}
|
||||
|
||||
overlappedFraction = 0f
|
||||
assertEquals(
|
||||
expandedColor,
|
||||
topAppBarScrollBehavior.toScrolledContainerColor(
|
||||
expandedColor = expandedColor,
|
||||
collapsedColor = collapsedColor,
|
||||
),
|
||||
)
|
||||
|
||||
overlappedFraction = 1f
|
||||
assertEquals(
|
||||
collapsedColor,
|
||||
topAppBarScrollBehavior.toScrolledContainerColor(
|
||||
expandedColor = expandedColor,
|
||||
collapsedColor = collapsedColor,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `toScrolledContainerColor for pinned states should interpolate based on the collapsedFraction`() {
|
||||
val expandedColor = Color(
|
||||
red = 0f,
|
||||
green = 0f,
|
||||
blue = 0f,
|
||||
alpha = 0f,
|
||||
)
|
||||
val collapsedColor = Color(
|
||||
red = 1f,
|
||||
green = 1f,
|
||||
blue = 1f,
|
||||
alpha = 1f,
|
||||
)
|
||||
var collapsedFraction = 0f
|
||||
val topAppBarScrollBehavior = mockk<TopAppBarScrollBehavior> {
|
||||
every { isPinned } returns false
|
||||
every { state.collapsedFraction } answers { collapsedFraction }
|
||||
}
|
||||
|
||||
collapsedFraction = 0f
|
||||
assertEquals(
|
||||
expandedColor,
|
||||
topAppBarScrollBehavior.toScrolledContainerColor(
|
||||
expandedColor = expandedColor,
|
||||
collapsedColor = collapsedColor,
|
||||
),
|
||||
)
|
||||
|
||||
collapsedFraction = 1f
|
||||
assertEquals(
|
||||
collapsedColor,
|
||||
topAppBarScrollBehavior.toScrolledContainerColor(
|
||||
expandedColor = expandedColor,
|
||||
collapsedColor = collapsedColor,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue