Improve banner design.

This commit is contained in:
Michelle Tang
2026-08-03 13:36:50 -04:00
committed by Alex Hart
parent b63b9ce71c
commit 99acf606d9
8 changed files with 128 additions and 55 deletions
@@ -5,7 +5,7 @@
package org.thoughtcrime.securesms.backup.v2.ui.status
import androidx.compose.foundation.border
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
@@ -31,6 +31,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
@@ -69,7 +70,10 @@ fun ArchiveRestoreStatusBanner(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.padding(contentPadding)
.border(1.dp, color = MaterialTheme.colorScheme.outline.copy(alpha = 0.38f), shape = RoundedCornerShape(12.dp))
.background(
color = colorResource(CoreUiR.color.signal_colorSurface2),
shape = RoundedCornerShape(24.dp)
)
.fillMaxWidth()
.defaultMinSize(minHeight = 48.dp)
.clickable(onClick = onBannerClick)
@@ -119,6 +123,7 @@ fun ArchiveRestoreStatusBanner(
CircularProgressIndicator(
progress = { data.progress!! },
strokeWidth = 3.dp,
color = MaterialTheme.colorScheme.onSurface,
strokeCap = StrokeCap.Round,
modifier = Modifier
.size(24.dp, 24.dp)
@@ -5,22 +5,40 @@
package org.thoughtcrime.securesms.banner.banners
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
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.clip
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.pluralStringResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import org.signal.core.ui.compose.DayNightPreviews
import org.signal.core.ui.compose.Previews
import org.signal.core.ui.compose.SignalIcons
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.banner.Banner
import org.thoughtcrime.securesms.banner.ui.compose.Action
import org.thoughtcrime.securesms.banner.ui.compose.DefaultBanner
import org.signal.core.ui.R as CoreUiR
/**
* Shows the number of pending requests to join the group.
@@ -51,19 +69,61 @@ private fun Banner(contentPadding: PaddingValues, suggestionsSize: Int, onViewCl
return
}
DefaultBanner(
title = null,
body = pluralStringResource(
id = R.plurals.PendingGroupJoinRequestsReminder_d_pending_member_requests,
count = suggestionsSize,
suggestionsSize
),
onDismissListener = { visible = false },
actions = listOf(
Action(R.string.PendingGroupJoinRequestsReminder_view, onClick = onViewClicked)
),
paddingValues = contentPadding
)
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.padding(horizontal = 12.dp, vertical = 8.dp)
.clip(RoundedCornerShape(24.dp))
.background(color = colorResource(CoreUiR.color.signal_colorSurface2))
.padding(horizontal = 16.dp)
) {
Icon(
imageVector = ImageVector.vectorResource(R.drawable.symbol_group_24),
tint = MaterialTheme.colorScheme.onSurface,
contentDescription = null,
modifier = Modifier.padding(end = 16.dp)
)
Text(
text = pluralStringResource(
id = R.plurals.PendingGroupJoinRequestsReminder_d_pending_member_requests,
count = suggestionsSize,
suggestionsSize
),
color = MaterialTheme.colorScheme.onSurface,
style = MaterialTheme.typography.bodyLarge,
modifier = Modifier
.weight(1f)
.padding()
)
TextButton(
onClick = onViewClicked,
colors = ButtonDefaults.textButtonColors(
containerColor = colorResource(CoreUiR.color.signal_colorSurface5),
contentColor = MaterialTheme.colorScheme.onSurface
),
modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp)
) {
Text(
text = stringResource(id = R.string.PendingGroupJoinRequestsReminder_view),
style = MaterialTheme.typography.labelLarge,
modifier = Modifier.padding(horizontal = 12.dp)
)
}
IconButton(
onClick = { visible = false },
modifier = Modifier.size(24.dp)
) {
Icon(
imageVector = SignalIcons.X.imageVector,
contentDescription = stringResource(id = R.string.InviteActivity_cancel),
tint = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
}
@DayNightPreviews
@@ -59,7 +59,7 @@ private fun Banner(contentPadding: PaddingValues, usernameSyncState: UsernameSyn
} else {
stringResource(id = R.string.UsernameOutOfSyncReminder__link_corrupt)
},
importance = Importance.ERROR,
importance = Importance.NORMAL,
actions = listOf(
Action(R.string.UsernameOutOfSyncReminder__fix_now) {
onFixClicked(usernameSyncState)
@@ -6,7 +6,7 @@
package org.thoughtcrime.securesms.banner.ui.compose
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
@@ -28,6 +28,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.pluralStringResource
import androidx.compose.ui.res.stringResource
@@ -56,40 +57,36 @@ fun DefaultBanner(
progressPercent: Int = -1,
paddingValues: PaddingValues
) {
val isDarkTheme = isSystemInDarkTheme()
Box(
modifier = Modifier
.padding(paddingValues)
.clip(RoundedCornerShape(12.dp))
.clip(RoundedCornerShape(24.dp))
.background(
color = when (importance) {
Importance.NORMAL -> MaterialTheme.colorScheme.surface
Importance.NORMAL -> colorResource(CoreUiR.color.signal_colorSurface2)
Importance.ERROR -> colorResource(id = R.color.reminder_background)
}
)
.border(
width = 1.dp,
color = colorResource(id = CoreUiR.color.signal_colorOutline_38),
shape = RoundedCornerShape(12.dp)
)
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.defaultMinSize(minHeight = 74.dp)
.defaultMinSize(minHeight = 54.dp)
) {
Column {
Row(modifier = Modifier.fillMaxWidth()) {
Column(
modifier = Modifier
.weight(1f)
.padding(start = 16.dp, top = 16.dp)
.padding(start = 16.dp, end = 16.dp, top = 16.dp)
) {
if (title.isNotNullOrBlank()) {
Text(
text = title,
color = when (importance) {
Importance.NORMAL -> MaterialTheme.colorScheme.onSurface
Importance.ERROR -> colorResource(id = CoreUiR.color.signal_light_colorOnSurface)
Importance.ERROR -> if (isDarkTheme) Color(0xFFC79869) else colorResource(id = CoreUiR.color.signal_light_colorOnSurface)
},
style = MaterialTheme.typography.bodyLarge
)
@@ -99,7 +96,7 @@ fun DefaultBanner(
text = body,
color = when (importance) {
Importance.NORMAL -> MaterialTheme.colorScheme.onSurfaceVariant
Importance.ERROR -> colorResource(id = CoreUiR.color.signal_light_colorOnSurface)
Importance.ERROR -> if (isDarkTheme) Color(0xFFC79869) else colorResource(id = CoreUiR.color.signal_light_colorOnSurface)
},
style = MaterialTheme.typography.bodyMedium
)
@@ -133,26 +130,26 @@ fun DefaultBanner(
style = MaterialTheme.typography.bodySmall,
color = when (importance) {
Importance.NORMAL -> MaterialTheme.colorScheme.onSurfaceVariant
Importance.ERROR -> colorResource(id = CoreUiR.color.signal_light_colorOnSurface)
Importance.ERROR -> if (isDarkTheme) Color(0xFFC79869) else colorResource(id = CoreUiR.color.signal_light_colorOnSurface)
}
)
}
Box(modifier = Modifier.size(48.dp)) {
if (onDismissListener != null) {
if (onDismissListener != null) {
Box(modifier = Modifier.size(40.dp)) {
IconButton(
onClick = {
onHideListener?.invoke()
onDismissListener()
},
modifier = Modifier.size(48.dp)
modifier = Modifier.size(40.dp)
) {
Icon(
imageVector = SignalIcons.X.imageVector,
contentDescription = stringResource(id = R.string.InviteActivity_cancel),
tint = when (importance) {
Importance.NORMAL -> MaterialTheme.colorScheme.onSurfaceVariant
Importance.ERROR -> colorResource(id = CoreUiR.color.signal_light_colorOnSurface)
Importance.ERROR -> colorResource(id = CoreUiR.color.signal_colorOnSurface)
}
)
}
@@ -163,22 +160,31 @@ fun DefaultBanner(
horizontalArrangement = Arrangement.End,
modifier = Modifier
.fillMaxWidth()
.padding(end = 8.dp)
.padding(end = 8.dp, bottom = 8.dp)
) {
for (action in actions) {
TextButton(
onClick = action.onClick,
colors = when (importance) {
Importance.NORMAL -> ButtonDefaults.textButtonColors()
Importance.ERROR -> ButtonDefaults.textButtonColors(contentColor = colorResource(CoreUiR.color.signal_light_colorPrimary))
}
Importance.NORMAL -> ButtonDefaults.textButtonColors(
containerColor = colorResource(CoreUiR.color.signal_colorSurface5),
contentColor = MaterialTheme.colorScheme.onSurface
)
Importance.ERROR -> ButtonDefaults.textButtonColors(
containerColor = if (isDarkTheme) Color(0xFF392D22) else Color(0xFFF5E1B8),
contentColor = if (isDarkTheme) Color(0xFFC79869) else colorResource(id = CoreUiR.color.signal_colorNeutralInverse)
)
},
modifier = Modifier.padding(horizontal = 8.dp)
) {
Text(
text = if (!action.isPluralizedLabel) {
stringResource(id = action.label)
} else {
pluralStringResource(id = action.label, count = action.pluralQuantity)
}
},
style = MaterialTheme.typography.labelLarge,
modifier = Modifier.padding(horizontal = 12.dp)
)
}
}
@@ -124,7 +124,7 @@ private fun BasicMegaphone(
Card(
elevation = CardDefaults.outlinedCardElevation(),
border = BorderStroke(1.dp, MaterialTheme.colorScheme.outline.copy(alpha = 0.38f)),
shape = RoundedCornerShape(12.dp),
shape = RoundedCornerShape(24.dp),
colors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.background
),
+13 -14
View File
@@ -14,11 +14,9 @@
android:layout_marginVertical="11dp"
android:background="@color/signal_background_primary"
android:minHeight="66dp"
app:cardCornerRadius="12dp"
app:cardBackgroundColor="@color/signal_colorSurface"
app:cardElevation="0dp"
app:strokeColor="@color/signal_colorOutline_38"
app:strokeWidth="1dp">
app:cardCornerRadius="24dp"
app:cardBackgroundColor="@color/signal_colorSurface2"
app:cardElevation="0dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
@@ -83,6 +81,7 @@
android:layout_marginStart="16dp"
android:layout_marginVertical="16dp"
android:text="@string/ReviewBannerView__name_conflict_found"
android:textColor="@color/signal_colorOnSurface"
android:textAppearance="@style/Signal.Text.BodyMedium"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/banner_tap_to_review"
@@ -91,27 +90,27 @@
<ImageView
android:id="@+id/banner_close"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_width="24dp"
android:layout_height="24dp"
android:contentDescription="@string/Material3SearchToolbar__close"
android:scaleType="centerInside"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginEnd="16dp"
app:tint="@color/signal_colorOnSurface"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_x_20" />
app:srcCompat="@drawable/symbol_x_24" />
<com.google.android.material.button.MaterialButton
android:id="@+id/banner_tap_to_review"
style="@style/Signal.Widget.Button.Small.Primary"
style="@style/Signal.Widget.Button.Medium.Primary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginHorizontal="8dp"
android:minWidth="0dp"
android:paddingHorizontal="16dp"
android:paddingVertical="6dp"
android:text="@string/ReviewBannerView__view"
android:textColor="@color/signal_colorOnSecondaryContainer"
app:backgroundTint="@color/signal_colorSurface2"
android:textColor="@color/signal_colorOnSurface"
app:backgroundTint="@color/signal_colorSurface5"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/banner_close"
app:layout_constraintStart_toEndOf="@id/banner_message"
@@ -65,4 +65,5 @@
<color name="signal_colorSurfaceVariant_16_no_alpha">#3F4249</color>
<color name="signal_colorSurfaceVariant_32_no_alpha">#5D5E62</color>
<color name="reminder_background">#26221D</color>
</resources>
@@ -65,4 +65,6 @@
<!-- Core color alpha variants without alpha channel -->
<color name="signal_colorSurfaceVariant_16_no_alpha">#D5D8DE</color>
<color name="signal_colorSurfaceVariant_32_no_alpha">#B8BCC5</color>
<color name="reminder_background">#faf0dc</color>
</resources>