Add StatusBarColorNestedScrollConnection.
This commit is contained in:
parent
2e45bd719a
commit
f249a6edd5
3 changed files with 249 additions and 4 deletions
|
@ -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)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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")
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue