brand(art): wire Messages-empty (A8) + Bucket List-empty (A6); add BrandIllustration helper

EmptyState already supports illustrationResId (rounded-tile clip), so Bucket List just
passes illustration_bucket_list_empty. Messages inbox gained a proper empty state
("Your private conversation starts here") with illustration_messages_empty. Added
BrandIllustration() helper (theme-safe rounded tile / tile=false for transparent art)
for the upcoming header/hero placements. Verified live both themes: rounded illustration
tile reads cleanly on dark (card) and light (white card on blush); 0 FATAL.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
null 2026-06-26 09:36:53 -05:00
parent 077a408785
commit 4aec224f0d
3 changed files with 67 additions and 0 deletions

View File

@ -0,0 +1,49 @@
package app.closer.ui.components
import androidx.annotation.DrawableRes
import androidx.compose.foundation.Image
import androidx.compose.foundation.border
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
/**
* Brand illustration that reads on BOTH the light and dark themes.
*
* Most of the generated empty-state / header illustrations ship with a soft
* near-white background; rendered raw on the dark (aubergine) theme that background
* would float as a pale block. Clipping to a generous rounded tile with a hairline
* outline turns it into an intentional, modern illustration card on either surface.
*
* Transparent art (e.g. the pairing-success celebration) should pass [tile] = false
* so it floats freely with no card edge.
*/
@Composable
fun BrandIllustration(
@DrawableRes res: Int,
contentDescription: String?,
modifier: Modifier = Modifier,
tile: Boolean = true,
cornerRadius: Dp = 28.dp,
) {
val shape = RoundedCornerShape(cornerRadius)
val shaped = if (tile) {
modifier
.clip(shape)
.border(1.dp, MaterialTheme.colorScheme.outline.copy(alpha = 0.10f), shape)
} else {
modifier
}
Image(
painter = painterResource(res),
contentDescription = contentDescription,
contentScale = ContentScale.Fit,
modifier = shaped,
)
}

View File

@ -276,6 +276,7 @@ private fun BucketListItems(
app.closer.ui.components.EmptyState( app.closer.ui.components.EmptyState(
title = "Your shared list is empty", title = "Your shared list is empty",
body = "Add something you've been dreaming about doing together — big or small. Tap + to start.", body = "Add something you've been dreaming about doing together — big or small. Tap + to start.",
illustrationResId = app.closer.R.drawable.illustration_bucket_list_empty,
modifier = Modifier.padding(top = 80.dp) modifier = Modifier.padding(top = 80.dp)
) )
return return

View File

@ -30,8 +30,10 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import app.closer.R
import app.closer.core.navigation.AppRoute import app.closer.core.navigation.AppRoute
import app.closer.domain.model.Conversation import app.closer.domain.model.Conversation
import app.closer.ui.components.EmptyState
import app.closer.ui.theme.CloserPalette import app.closer.ui.theme.CloserPalette
import coil.compose.AsyncImage import coil.compose.AsyncImage
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
@ -74,6 +76,21 @@ fun MessagesInboxScreen(
return return
} }
if (state.conversations.isEmpty()) {
Column(
modifier = Modifier.fillMaxSize().padding(24.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
EmptyState(
title = "Your private conversation starts here",
body = "Say hi, share a thought, or pick a question to talk through together. Everything you send stays end-to-end encrypted, just for the two of you.",
illustrationResId = R.drawable.illustration_messages_empty
)
}
return
}
LazyColumn( LazyColumn(
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),
contentPadding = PaddingValues(vertical = 4.dp) contentPadding = PaddingValues(vertical = 4.dp)