Add StatusBarColorNestedScrollConnection.

This commit is contained in:
Alex Hart 2023-03-30 16:16:57 -03:00
parent 2e45bd719a
commit f249a6edd5
3 changed files with 249 additions and 4 deletions

View file

@ -1,5 +1,6 @@
package org.thoughtcrime.securesms.components.settings.app.privacy.pnp
import android.os.Bundle
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.padding
@ -10,6 +11,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
@ -22,12 +24,24 @@ import org.signal.core.ui.Scaffolds
import org.signal.core.ui.Texts
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.compose.ComposeFragment
import org.thoughtcrime.securesms.compose.StatusBarColorNestedScrollConnection
import org.thoughtcrime.securesms.keyvalue.PhoneNumberPrivacyValues.PhoneNumberListingMode
import org.thoughtcrime.securesms.keyvalue.PhoneNumberPrivacyValues.PhoneNumberSharingMode
class PhoneNumberPrivacySettingsFragment : ComposeFragment() {
private val viewModel: PhoneNumberPrivacySettingsViewModel by viewModels()
private lateinit var statusBarNestedScrollConnection: StatusBarColorNestedScrollConnection
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
statusBarNestedScrollConnection = StatusBarColorNestedScrollConnection(requireActivity())
}
override fun onResume() {
super.onResume()
statusBarNestedScrollConnection.setColorImmediate()
}
@Composable
override fun SheetContent() {
@ -40,7 +54,8 @@ class PhoneNumberPrivacySettingsFragment : ComposeFragment() {
title = stringResource(id = R.string.preferences_app_protection__phone_number),
onNavigationClick = onNavigationClick,
navigationIconPainter = painterResource(id = R.drawable.ic_arrow_left_24),
navigationContentDescription = stringResource(id = R.string.Material3SearchToolbar__close)
navigationContentDescription = stringResource(id = R.string.Material3SearchToolbar__close),
modifier = Modifier.nestedScroll(statusBarNestedScrollConnection)
) { contentPadding ->
Box(modifier = Modifier.padding(contentPadding)) {
LazyColumn {
@ -120,6 +135,146 @@ class PhoneNumberPrivacySettingsFragment : ComposeFragment() {
modifier = Modifier.padding(horizontal = dimensionResource(id = R.dimen.core_ui__gutter), vertical = 16.dp)
)
}
item {
Text(
text = stringResource(
id = when (state.findMeByPhoneNumber) {
PhoneNumberListingMode.UNLISTED -> R.string.WhoCanSeeMyPhoneNumberFragment__nobody_on_signal
PhoneNumberListingMode.LISTED -> R.string.WhoCanSeeMyPhoneNumberFragment__anyone_who_has
}
),
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.padding(horizontal = dimensionResource(id = R.dimen.core_ui__gutter), vertical = 16.dp)
)
}
item {
Text(
text = stringResource(
id = when (state.findMeByPhoneNumber) {
PhoneNumberListingMode.UNLISTED -> R.string.WhoCanSeeMyPhoneNumberFragment__nobody_on_signal
PhoneNumberListingMode.LISTED -> R.string.WhoCanSeeMyPhoneNumberFragment__anyone_who_has
}
),
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.padding(horizontal = dimensionResource(id = R.dimen.core_ui__gutter), vertical = 16.dp)
)
}
item {
Text(
text = stringResource(
id = when (state.findMeByPhoneNumber) {
PhoneNumberListingMode.UNLISTED -> R.string.WhoCanSeeMyPhoneNumberFragment__nobody_on_signal
PhoneNumberListingMode.LISTED -> R.string.WhoCanSeeMyPhoneNumberFragment__anyone_who_has
}
),
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.padding(horizontal = dimensionResource(id = R.dimen.core_ui__gutter), vertical = 16.dp)
)
}
item {
Text(
text = stringResource(
id = when (state.findMeByPhoneNumber) {
PhoneNumberListingMode.UNLISTED -> R.string.WhoCanSeeMyPhoneNumberFragment__nobody_on_signal
PhoneNumberListingMode.LISTED -> R.string.WhoCanSeeMyPhoneNumberFragment__anyone_who_has
}
),
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.padding(horizontal = dimensionResource(id = R.dimen.core_ui__gutter), vertical = 16.dp)
)
}
item {
Text(
text = stringResource(
id = when (state.findMeByPhoneNumber) {
PhoneNumberListingMode.UNLISTED -> R.string.WhoCanSeeMyPhoneNumberFragment__nobody_on_signal
PhoneNumberListingMode.LISTED -> R.string.WhoCanSeeMyPhoneNumberFragment__anyone_who_has
}
),
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.padding(horizontal = dimensionResource(id = R.dimen.core_ui__gutter), vertical = 16.dp)
)
}
item {
Text(
text = stringResource(
id = when (state.findMeByPhoneNumber) {
PhoneNumberListingMode.UNLISTED -> R.string.WhoCanSeeMyPhoneNumberFragment__nobody_on_signal
PhoneNumberListingMode.LISTED -> R.string.WhoCanSeeMyPhoneNumberFragment__anyone_who_has
}
),
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.padding(horizontal = dimensionResource(id = R.dimen.core_ui__gutter), vertical = 16.dp)
)
}
item {
Text(
text = stringResource(
id = when (state.findMeByPhoneNumber) {
PhoneNumberListingMode.UNLISTED -> R.string.WhoCanSeeMyPhoneNumberFragment__nobody_on_signal
PhoneNumberListingMode.LISTED -> R.string.WhoCanSeeMyPhoneNumberFragment__anyone_who_has
}
),
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.padding(horizontal = dimensionResource(id = R.dimen.core_ui__gutter), vertical = 16.dp)
)
}
item {
Text(
text = stringResource(
id = when (state.findMeByPhoneNumber) {
PhoneNumberListingMode.UNLISTED -> R.string.WhoCanSeeMyPhoneNumberFragment__nobody_on_signal
PhoneNumberListingMode.LISTED -> R.string.WhoCanSeeMyPhoneNumberFragment__anyone_who_has
}
),
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.padding(horizontal = dimensionResource(id = R.dimen.core_ui__gutter), vertical = 16.dp)
)
}
item {
Text(
text = stringResource(
id = when (state.findMeByPhoneNumber) {
PhoneNumberListingMode.UNLISTED -> R.string.WhoCanSeeMyPhoneNumberFragment__nobody_on_signal
PhoneNumberListingMode.LISTED -> R.string.WhoCanSeeMyPhoneNumberFragment__anyone_who_has
}
),
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.padding(horizontal = dimensionResource(id = R.dimen.core_ui__gutter), vertical = 16.dp)
)
}
item {
Text(
text = stringResource(
id = when (state.findMeByPhoneNumber) {
PhoneNumberListingMode.UNLISTED -> R.string.WhoCanSeeMyPhoneNumberFragment__nobody_on_signal
PhoneNumberListingMode.LISTED -> R.string.WhoCanSeeMyPhoneNumberFragment__anyone_who_has
}
),
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.padding(horizontal = dimensionResource(id = R.dimen.core_ui__gutter), vertical = 16.dp)
)
}
}
}
}

View file

@ -0,0 +1,80 @@
package org.thoughtcrime.securesms.compose
import android.animation.ValueAnimator
import android.app.Activity
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
import androidx.compose.ui.unit.Velocity
import androidx.core.content.ContextCompat
import com.google.android.material.animation.ArgbEvaluatorCompat
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.util.WindowUtil
import kotlin.math.abs
/**
* Controls status-bar color based off a nested scroll
*/
class StatusBarColorNestedScrollConnection(
private val activity: Activity
) : NestedScrollConnection {
private var animator: ValueAnimator? = null
private val normalColor = ContextCompat.getColor(activity, R.color.signal_colorBackground)
private val scrollColor = ContextCompat.getColor(activity, R.color.signal_colorSurface2)
private var contentOffset = 0f
override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity {
return Velocity.Zero
}
override fun onPostScroll(consumed: Offset, available: Offset, source: NestedScrollSource): Offset {
val oldContentOffset = contentOffset
if (consumed.y == 0f && available.y > 0f) {
contentOffset = 0f
} else {
contentOffset += consumed.y
}
if (oldContentOffset.isNearZero() xor contentOffset.isNearZero()) {
applyState()
}
return Offset.Zero
}
fun setColorImmediate() {
val end = when {
contentOffset.isNearZero() -> normalColor
else -> scrollColor
}
animator?.cancel()
WindowUtil.setStatusBarColor(
activity.window,
end
)
}
private fun applyState() {
val (start, end) = when {
contentOffset.isNearZero() -> scrollColor to normalColor
else -> normalColor to scrollColor
}
animator?.cancel()
animator = ValueAnimator.ofFloat(0f, 1f).apply {
duration = 200
addUpdateListener {
WindowUtil.setStatusBarColor(
activity.window,
ArgbEvaluatorCompat.getInstance().evaluate(it.animatedFraction, start, end)
)
}
start()
}
}
private fun Float.isNearZero(): Boolean = abs(this) < 0.001
}

View file

@ -11,12 +11,14 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.ColorPainter
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import org.signal.core.ui.theme.SignalTheme
@ -32,6 +34,8 @@ object Scaffolds {
navigationContentDescription: String? = null,
content: @Composable (PaddingValues) -> Unit
) {
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
Scaffold(
topBar = {
TopAppBar(
@ -51,10 +55,14 @@ object Scaffolds {
contentDescription = navigationContentDescription
)
}
}
},
scrollBehavior = scrollBehavior,
colors = TopAppBarDefaults.smallTopAppBarColors(
scrolledContainerColor = SignalTheme.colors.colorSurface2
)
)
},
modifier = modifier,
modifier = modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
content = content
)
}
@ -71,7 +79,9 @@ private fun SettingsScaffoldPreview() {
) { paddingValues ->
Box(
contentAlignment = Alignment.Center,
modifier = Modifier.padding(paddingValues).fillMaxSize()
modifier = Modifier
.padding(paddingValues)
.fillMaxSize()
) {
Text("Content")
}