diff --git a/app/build.gradle b/app/build.gradle index 95c8e4df89..76d1e7e027 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -166,14 +166,14 @@ dependencies { testImplementation 'org.robolectric:shadows-multidex:4.4' implementation 'com.github.bumptech.glide:compose:1.0.0-alpha.1' - implementation 'androidx.compose.ui:ui:1.5.0' - implementation 'androidx.compose.ui:ui-tooling:1.5.0' + implementation 'androidx.compose.ui:ui:1.4.3' + implementation 'androidx.compose.ui:ui-tooling:1.4.3' implementation "com.google.accompanist:accompanist-themeadapter-appcompat:0.31.5-beta" implementation "com.google.accompanist:accompanist-pager-indicators:0.31.5-beta" - implementation "androidx.compose.runtime:runtime-livedata:1.5.0" + implementation "androidx.compose.runtime:runtime-livedata:1.4.3" - implementation 'androidx.compose.foundation:foundation-layout:1.5.0' - implementation 'androidx.compose.material:material:1.5.0' + implementation 'androidx.compose.foundation:foundation-layout:1.4.3' + implementation 'androidx.compose.material:material:1.4.3' } def canonicalVersionCode = 354 diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/expiration/ExpirationSettingsActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/expiration/ExpirationSettingsActivity.kt index 33ed55b01a..ab52a2b909 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/expiration/ExpirationSettingsActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/expiration/ExpirationSettingsActivity.kt @@ -4,11 +4,13 @@ import android.os.Bundle import android.widget.Toast import androidx.activity.viewModels import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.ScrollState import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.heightIn @@ -16,6 +18,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll @@ -29,8 +32,14 @@ import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.drawWithContent +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.graphics.BlendMode import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.CompositingStrategy +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.layout.ModifierLocalBeyondBoundsLayout import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter @@ -48,11 +57,13 @@ import org.thoughtcrime.securesms.database.RecipientDatabase import org.thoughtcrime.securesms.database.ThreadDatabase import org.thoughtcrime.securesms.ui.AppTheme import org.thoughtcrime.securesms.ui.CellNoMargin +import org.thoughtcrime.securesms.ui.Divider import org.thoughtcrime.securesms.ui.GetString import org.thoughtcrime.securesms.ui.PreviewTheme import org.thoughtcrime.securesms.ui.ThemeResPreviewParameterProvider import org.thoughtcrime.securesms.util.ConfigurationMessageUtilities import javax.inject.Inject +import kotlin.math.min @AndroidEntryPoint class ExpirationSettingsActivity: PassphraseRequiredActionBarActivity() { @@ -189,18 +200,22 @@ fun DisappearingMessages( modifier: Modifier = Modifier, onSetClick: () -> Unit = {} ) { + val scrollState = rememberScrollState() + Column(modifier = modifier) { Box(modifier = Modifier.weight(1f)) { Column( modifier = Modifier .padding(horizontal = 32.dp) - .verticalScroll(rememberScrollState()), + .padding(bottom = 20.dp) + .verticalScroll(scrollState) + .fadingEdges(scrollState), verticalArrangement = Arrangement.spacedBy(16.dp) ) { - state.cards.filter { it.options.isNotEmpty() }.forEach { OptionsCard(it) } + state.cards.filter { it.options.isNotEmpty() }.forEach { + OptionsCard(it) + } } - - Gradient(100.dp, modifier = Modifier.align(Alignment.BottomCenter)) } OutlineButton( @@ -213,6 +228,43 @@ fun DisappearingMessages( } } +fun Modifier.fadingEdges( + scrollState: ScrollState, + topEdgeHeight: Dp = 0.dp, + bottomEdgeHeight: Dp = 20.dp +): Modifier = this.then( + Modifier + // adding layer fixes issue with blending gradient and content + .graphicsLayer { alpha = 0.99F } + .drawWithContent { + drawContent() + + val topColors = listOf(Color.Transparent, Color.Black) + val topStartY = scrollState.value.toFloat() + val topGradientHeight = min(topEdgeHeight.toPx(), topStartY) + drawRect( + brush = Brush.verticalGradient( + colors = topColors, + startY = topStartY, + endY = topStartY + topGradientHeight + ), + blendMode = BlendMode.DstIn + ) + + val bottomColors = listOf(Color.Black, Color.Transparent) + val bottomEndY = size.height - scrollState.maxValue + scrollState.value + val bottomGradientHeight = min(bottomEdgeHeight.toPx(), scrollState.maxValue.toFloat() - scrollState.value) + if (bottomGradientHeight != 0f) drawRect( + brush = Brush.verticalGradient( + colors = bottomColors, + startY = bottomEndY - bottomGradientHeight, + endY = bottomEndY + ), + blendMode = BlendMode.DstIn + ) + } +) + @Composable fun OptionsCard(card: CardModel) { Text(text = card.title()) @@ -220,7 +272,8 @@ fun OptionsCard(card: CardModel) { LazyColumn( modifier = Modifier.heightIn(max = 5000.dp) ) { - items(card.options) { + itemsIndexed(card.options) { i, it -> + if (i != 0) Divider() TitledRadioButton(it) } } @@ -233,13 +286,13 @@ fun Gradient(height: Dp, modifier: Modifier = Modifier) { modifier = modifier .fillMaxWidth() .height(height) - .background( - brush = Brush.verticalGradient( - colors = listOf(Color.Transparent, MaterialTheme.colors.primary), - startY = 0f, - endY = height.value - ) - ) +// .background( +// brush = Brush.verticalGradient( +// colors = listOf(Color.Transparent, MaterialTheme.colors.primary), +// startY = 0f, +// endY = height.value +// ) +// ) ) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/expiration/ExpirationSettingsViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/expiration/ExpirationSettingsViewModel.kt index f4f1aeb412..6cbaca9152 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/expiration/ExpirationSettingsViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/expiration/ExpirationSettingsViewModel.kt @@ -90,15 +90,15 @@ class ExpirationSettingsViewModel( fun typeOption( type: ExpiryType, @StringRes title: Int, - @StringRes subtitle: Int, -// @StringRes contentDescription: Int - ) = OptionModel(GetString(title), GetString(subtitle)) { setType(type) } + @StringRes subtitle: Int? = null, + @StringRes contentDescription: Int = title + ) = OptionModel(GetString(title), subtitle?.let(::GetString)) { setType(type) } private fun typeOptions() = listOf( - typeOption(ExpiryType.NONE, R.string.expiration_off, R.string.AccessibilityId_disable_disappearing_messages), - typeOption(ExpiryType.LEGACY, R.string.expiration_type_disappear_legacy, R.string.expiration_type_disappear_legacy_description), - typeOption(ExpiryType.AFTER_READ, R.string.expiration_type_disappear_after_read, R.string.expiration_type_disappear_after_read_description), - typeOption(ExpiryType.AFTER_SEND, R.string.expiration_type_disappear_after_send, R.string.expiration_type_disappear_after_send_description), + typeOption(ExpiryType.NONE, R.string.expiration_off, contentDescription = R.string.AccessibilityId_disable_disappearing_messages), + typeOption(ExpiryType.LEGACY, R.string.expiration_type_disappear_legacy, contentDescription = R.string.expiration_type_disappear_legacy_description), + typeOption(ExpiryType.AFTER_READ, R.string.expiration_type_disappear_after_read, contentDescription = R.string.expiration_type_disappear_after_read_description), + typeOption(ExpiryType.AFTER_SEND, R.string.expiration_type_disappear_after_send, contentDescription = R.string.expiration_type_disappear_after_send_description), ) private fun setType(type: ExpiryType) { @@ -127,7 +127,7 @@ class ExpirationSettingsViewModel( val afterSendTimes = listOf(5.minutes, 1.hours) + afterReadTimes private fun noteToSelfOptions() = listOfNotNull( - typeOption(ExpiryType.NONE, R.string.arrays__off, R.string.arrays__off), + typeOption(ExpiryType.NONE, R.string.arrays__off), noteToSelfOption(1.minutes, subtitle = "for testing purposes").takeIf { BuildConfig.DEBUG }, ) + afterSendTimes.map(::noteToSelfOption) diff --git a/app/src/main/res/layout/activity_expiration_settings.xml b/app/src/main/res/layout/activity_expiration_settings.xml index 30c93b6dbd..4ea3966d05 100644 --- a/app/src/main/res/layout/activity_expiration_settings.xml +++ b/app/src/main/res/layout/activity_expiration_settings.xml @@ -1,33 +1,24 @@ - + android:orientation="vertical"> - + android:background="?colorPrimary" + app:contentInsetStart="0dp" + app:subtitle="@string/activity_expiration_settings_subtitle" + app:subtitleTextAppearance="@style/TextAppearance.Session.ToolbarSubtitle" + app:title="@string/activity_expiration_settings_title" /> - + - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/build.gradle b/build.gradle index e0ae108fe8..7d9857aaf3 100644 --- a/build.gradle +++ b/build.gradle @@ -57,6 +57,6 @@ allprojects { project.ext { androidMinimumSdkVersion = 23 androidTargetSdkVersion = 33 - androidCompileSdkVersion = 34 + androidCompileSdkVersion = 33 } } \ No newline at end of file