diff --git a/app/src/main/java/app/closer/core/notifications/NotificationHelper.kt b/app/src/main/java/app/closer/core/notifications/NotificationHelper.kt index 313dfa6d..9dc2babc 100644 --- a/app/src/main/java/app/closer/core/notifications/NotificationHelper.kt +++ b/app/src/main/java/app/closer/core/notifications/NotificationHelper.kt @@ -56,7 +56,7 @@ object NotificationHelper { PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE ) val notification = NotificationCompat.Builder(context, channelId) - .setSmallIcon(R.drawable.ic_launcher_foreground) + .setSmallIcon(R.drawable.ic_notification_closer) .setContentTitle(title) .setContentText(body) .setAutoCancel(true) diff --git a/app/src/main/java/app/closer/notifications/PartnerNotificationManager.kt b/app/src/main/java/app/closer/notifications/PartnerNotificationManager.kt index 313081e6..e1cd2551 100644 --- a/app/src/main/java/app/closer/notifications/PartnerNotificationManager.kt +++ b/app/src/main/java/app/closer/notifications/PartnerNotificationManager.kt @@ -131,7 +131,7 @@ class PartnerNotificationManager @Inject constructor( ) val notification = NotificationCompat.Builder(context, type.channelId) - .setSmallIcon(R.drawable.ic_launcher_foreground) + .setSmallIcon(R.drawable.ic_notification_closer) .setContentTitle(type.title) .setContentText(type.body) .setAutoCancel(true) diff --git a/app/src/main/java/app/closer/ui/components/LoadingState.kt b/app/src/main/java/app/closer/ui/components/LoadingState.kt index ba04bea3..d2530821 100644 --- a/app/src/main/java/app/closer/ui/components/LoadingState.kt +++ b/app/src/main/java/app/closer/ui/components/LoadingState.kt @@ -1,5 +1,6 @@ package app.closer.ui.components +import app.closer.R import app.closer.ui.theme.closerCardColor import android.provider.Settings import androidx.compose.animation.core.FastOutSlowInEasing @@ -8,7 +9,7 @@ import androidx.compose.animation.core.animateFloat import androidx.compose.animation.core.infiniteRepeatable import androidx.compose.animation.core.rememberInfiniteTransition import androidx.compose.animation.core.tween -import androidx.compose.foundation.Canvas +import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth @@ -20,13 +21,9 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.drawscope.clipRect -import androidx.compose.ui.graphics.drawscope.withTransform import androidx.compose.ui.graphics.graphicsLayer -import androidx.compose.ui.graphics.vector.PathParser import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource import androidx.compose.ui.semantics.clearAndSetSemantics import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.Dp @@ -67,6 +64,14 @@ fun LoadingState( fun CloserHeartLoader( modifier: Modifier = Modifier, size: Dp = 76.dp +) { + CloserMarkLoader(modifier = modifier, size = size) +} + +@Composable +fun CloserMarkLoader( + modifier: Modifier = Modifier, + size: Dp = 76.dp ) { val context = LocalContext.current val reducedMotion = remember { @@ -76,16 +81,7 @@ fun CloserHeartLoader( 1f ) == 0f } - val transition = rememberInfiniteTransition(label = "closerHeartLoader") - val animatedFill = transition.animateFloat( - initialValue = 0.08f, - targetValue = 1f, - animationSpec = infiniteRepeatable( - animation = tween(durationMillis = 1500, easing = FastOutSlowInEasing), - repeatMode = RepeatMode.Restart - ), - label = "closerHeartFill" - ) + val transition = rememberInfiniteTransition(label = "closerMarkLoader") val animatedPulse = transition.animateFloat( initialValue = 0.96f, targetValue = 1.04f, @@ -93,38 +89,13 @@ fun CloserHeartLoader( animation = tween(durationMillis = 900, easing = FastOutSlowInEasing), repeatMode = RepeatMode.Reverse ), - label = "closerHeartPulse" + label = "closerMarkPulse" ) - - val fillProgress = if (reducedMotion) 1f else animatedFill.value val pulse = if (reducedMotion) 1f else animatedPulse.value - val shadowPath = remember { - PathParser().parsePathString( - "M54,89C48,82 25,65 20,50C15,35 23,22 37,22C45,22 51,26 54,33C57,26 63,22 71,22C85,22 93,35 88,50C83,65 60,82 54,89Z" - ).toPath() - } - val leftPath = remember { - PathParser().parsePathString( - "M54,85C49,79 27,62 22,48C17,35 24,24 37,24C45,24 51,28 54,35Z" - ).toPath() - } - val rightPath = remember { - PathParser().parsePathString( - "M54,85C59,79 81,62 86,48C91,35 84,24 71,24C63,24 57,28 54,35Z" - ).toPath() - } - val leftHighlight = remember { - PathParser().parsePathString( - "M27,42C28,32 34,27 42,27C48,27 52,30 54,35L54,41C47,36 37,36 27,42Z" - ).toPath() - } - val rightHighlight = remember { - PathParser().parsePathString( - "M54,35C57,30 62,27 69,27C78,27 84,32 85,42C75,36 65,36 54,41Z" - ).toPath() - } - Canvas( + Image( + painter = painterResource(R.drawable.closer_mark_loader), + contentDescription = null, modifier = modifier .size(size) .graphicsLayer { @@ -132,22 +103,5 @@ fun CloserHeartLoader( scaleY = pulse } .clearAndSetSemantics {} - ) { - val scaleX = this.size.width / 108f - val scaleY = this.size.height / 108f - - withTransform({ - scale(scaleX = scaleX, scaleY = scaleY, pivot = Offset.Zero) - }) { - drawPath(shadowPath, color = Color(0xFF24122F).copy(alpha = 0.10f)) - drawPath(leftPath, color = Color(0xFFF7C8E4).copy(alpha = 0.22f)) - drawPath(rightPath, color = Color(0xFFD9B8FF).copy(alpha = 0.22f)) - clipRect(top = 108f * (1f - fillProgress), bottom = 108f) { - drawPath(leftPath, color = Color(0xFFF7C8E4)) - drawPath(rightPath, color = Color(0xFFD9B8FF)) - drawPath(leftHighlight, color = Color(0xFFFFF4FA).copy(alpha = 0.68f)) - drawPath(rightHighlight, color = Color(0xFFF3E8FF).copy(alpha = 0.52f)) - } - } - } + ) } diff --git a/app/src/main/res/drawable-nodpi/closer_launcher_foreground.png b/app/src/main/res/drawable-nodpi/closer_launcher_foreground.png new file mode 100644 index 00000000..5cba8845 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/closer_launcher_foreground.png differ diff --git a/app/src/main/res/drawable-nodpi/closer_launcher_monochrome.png b/app/src/main/res/drawable-nodpi/closer_launcher_monochrome.png new file mode 100644 index 00000000..01a98076 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/closer_launcher_monochrome.png differ diff --git a/app/src/main/res/drawable-nodpi/closer_mark_loader.png b/app/src/main/res/drawable-nodpi/closer_mark_loader.png new file mode 100644 index 00000000..cddf19b2 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/closer_mark_loader.png differ diff --git a/app/src/main/res/drawable-nodpi/ic_notification_closer.png b/app/src/main/res/drawable-nodpi/ic_notification_closer.png new file mode 100644 index 00000000..54f7a6f2 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/ic_notification_closer.png differ diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml index 0b32b258..f1e0bbbe 100644 --- a/app/src/main/res/drawable/ic_launcher_foreground.xml +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -1,33 +1,4 @@ - - - - - - - - - + diff --git a/app/src/main/res/drawable/ic_launcher_monochrome.xml b/app/src/main/res/drawable/ic_launcher_monochrome.xml index 8c748e38..e6f99611 100644 --- a/app/src/main/res/drawable/ic_launcher_monochrome.xml +++ b/app/src/main/res/drawable/ic_launcher_monochrome.xml @@ -1,10 +1,4 @@ - - - + diff --git a/docs/brand/asset-system.md b/docs/brand/asset-system.md index 56a9c8f0..95a81665 100644 --- a/docs/brand/asset-system.md +++ b/docs/brand/asset-system.md @@ -4,8 +4,8 @@ This is the working artwork asset set for Closer. It keeps the existing purple/p and the 2D pastel couple illustration style, but gives every visual surface a clearer job. The brand should feel like a private ritual for two people: warm, quiet, equal, and intentional. -The heart remains the compact brand mark. The couple artwork should become the primary visual -language anywhere there is enough space to show a human moment. +The compact brand mark is now the approved Closer C-heart-keyhole. The couple artwork should remain +the primary visual language anywhere there is enough space to show a human moment. ## Current Artwork Review @@ -33,19 +33,21 @@ Avoid: Keep: -- `docs/store/sources/app-icon.svg` as the source of the compact heart mark. +- `docs/brand/sources/closer-approved-icon-source.png` as the visual source of truth for the compact + C-heart-keyhole mark. +- `docs/store/sources/app-icon.svg` as the source wrapper for the launcher/store icon. - `iphone/Closer/Resources/illustration-couple-*.png` as the human brand style. - `iphone/Closer/Resources/pack-art-*.png` as the category/pack art direction. - `iphone/Closer/Resources/particle-heart.png` and `particle-petal.png` for celebration moments. Improve: -- The heart is strong for launchers and tiny UI, but too generic when used alone at larger sizes. - Use couple illustrations for onboarding, paywall, empty states, store screenshots, and web/social. +- The mark is strong for launchers, auth, loaders, notification glyphs, and small privacy seals. Use + couple illustrations for onboarding, paywall, empty states, store screenshots, and web/social. - Android currently has the launcher vectors but not the larger illustration library. Mirror the iOS resources into Android when those screens start using raster art. -- Store feature graphics should show the heart plus one illustrated/private ritual scene, not only - cards and symbols. +- Store feature graphics should show the C-heart-keyhole plus one illustrated/private ritual scene, + not only cards and symbols. ### Notification Artwork @@ -63,18 +65,20 @@ This section is only about the artwork used to represent notifications, not noti | Asset | Use | Source / Target | | --- | --- | --- | -| Primary app mark | Launcher, favicon, small brand moments | `docs/store/sources/app-icon.svg` | +| Primary app mark | Launcher, favicon, small brand moments | `docs/brand/sources/closer-approved-icon-source.png` | | Adaptive foreground | Android launcher layer | `app/src/main/res/drawable/ic_launcher_foreground.xml` | | Adaptive background | Android launcher layer | `app/src/main/res/drawable/ic_launcher_background.xml` | | Monochrome mark | Android themed icon, single-color use | `app/src/main/res/drawable/ic_launcher_monochrome.xml` | -| Notification glyph | Android/iOS notification art direction | Needed: monochrome heart/paired-card source | +| Notification glyph | Android notification small icon | `app/src/main/res/drawable-nodpi/ic_notification_closer.png` | | Wordmark lockup | Website, store hero, press kit | Needed: `docs/brand/sources/closer-lockup.svg` | | Horizontal logo | Email header, social headers | Needed: SVG + PNG exports | | One-color logo | Legal docs, monochrome print, dark/light footer | Needed: SVG exports | | Favicon set | Website/browser/PWA | Needed: 16, 32, 48, 180, 192, 512 px | -Logo rule: the heart mark should mean "two equal people meeting in the middle." Do not split it, -rotate it, add faces, add text inside it, or use it as a reaction emoji. +Logo rule: the mark should mean "Closer is the private space around your relationship." Keep the +approved pink upper C, lavender lower sweep, heart-shaped inner space, and true keyhole. Do not +redraw it as a generic `C`, turn the keyhole into a heart, add a key or lock shackle, add faces, add +text inside it, or use it as a reaction emoji. ### 2. App Icons @@ -86,9 +90,8 @@ rotate it, add faces, add text inside it, or use it as a reaction emoji. Current status: -- Android and Play icon assets exist. -- iOS has an asset catalog folder but no visible app icon set in the checked file list. Add the - full iOS app icon set before TestFlight/App Store review. +- Android, Play, and iOS AppIcon assets exist and should be regenerated from the approved source + image after any future mark change. ### 3. Illustration Library @@ -158,7 +161,7 @@ These should be simple single-color vectors that work at 20-32 dp/pt. | Asset | Spec | Direction | | --- | --- | --- | -| Play feature graphic | 1024 x 500 PNG | Heart + one private ritual illustration + short promise | +| Play feature graphic | 1024 x 500 PNG | C-heart-keyhole + one private ritual illustration + short promise | | Play screenshots | Up to 8 phone screenshots | Use product screens; omit login unless testing trust | | App Store screenshots | iPhone 6.7", 6.5", 5.5" as needed | Mirror Play story | | Social open graph | 1200 x 630 | Couple illustration + "A private space for two." | @@ -234,10 +237,9 @@ iphone/Closer/Resources/ ## Priority Build List -1. Keep the current heart mark, but create wordmark/horizontal/one-color SVG lockups. -2. Add the missing iOS AppIcon set. -3. Mirror illustration PNGs into Android and start using them in onboarding, empty states, paywall, +1. Build wordmark/horizontal/one-color lockups around the approved C-heart-keyhole. +2. Mirror illustration PNGs into Android and start using them in onboarding, empty states, paywall, and store screenshots. -4. Rework the Play feature graphic to include one couple/private-ritual illustration. -5. Add the new notification and privacy illustrations listed above. -6. Build a small custom glyph set for privacy/reveal/date/capsule concepts. +3. Rework the Play feature graphic to include one couple/private-ritual illustration. +4. Add the new notification and privacy illustrations listed above. +5. Build a small custom glyph set for privacy/reveal/date/capsule concepts. diff --git a/docs/brand/exports/logo/app-icon/closer-app-icon-512.png b/docs/brand/exports/logo/app-icon/closer-app-icon-512.png new file mode 100644 index 00000000..82e3065c Binary files /dev/null and b/docs/brand/exports/logo/app-icon/closer-app-icon-512.png differ diff --git a/docs/brand/exports/logo/social/closer-mark-social-1024.png b/docs/brand/exports/logo/social/closer-mark-social-1024.png new file mode 100644 index 00000000..fea5b03e Binary files /dev/null and b/docs/brand/exports/logo/social/closer-mark-social-1024.png differ diff --git a/docs/brand/exports/logo/social/closer-mark-social-2048.png b/docs/brand/exports/logo/social/closer-mark-social-2048.png new file mode 100644 index 00000000..25bb0a2a Binary files /dev/null and b/docs/brand/exports/logo/social/closer-mark-social-2048.png differ diff --git a/docs/brand/exports/logo/transparent-keyhole-aubergine/closer-mark-1024.png b/docs/brand/exports/logo/transparent-keyhole-aubergine/closer-mark-1024.png new file mode 100644 index 00000000..e287de74 Binary files /dev/null and b/docs/brand/exports/logo/transparent-keyhole-aubergine/closer-mark-1024.png differ diff --git a/docs/brand/exports/logo/transparent-keyhole-aubergine/closer-mark-128.png b/docs/brand/exports/logo/transparent-keyhole-aubergine/closer-mark-128.png new file mode 100644 index 00000000..93b89115 Binary files /dev/null and b/docs/brand/exports/logo/transparent-keyhole-aubergine/closer-mark-128.png differ diff --git a/docs/brand/exports/logo/transparent-keyhole-aubergine/closer-mark-192.png b/docs/brand/exports/logo/transparent-keyhole-aubergine/closer-mark-192.png new file mode 100644 index 00000000..124b151d Binary files /dev/null and b/docs/brand/exports/logo/transparent-keyhole-aubergine/closer-mark-192.png differ diff --git a/docs/brand/exports/logo/transparent-keyhole-aubergine/closer-mark-24.png b/docs/brand/exports/logo/transparent-keyhole-aubergine/closer-mark-24.png new file mode 100644 index 00000000..5986883b Binary files /dev/null and b/docs/brand/exports/logo/transparent-keyhole-aubergine/closer-mark-24.png differ diff --git a/docs/brand/exports/logo/transparent-keyhole-aubergine/closer-mark-256.png b/docs/brand/exports/logo/transparent-keyhole-aubergine/closer-mark-256.png new file mode 100644 index 00000000..cddf19b2 Binary files /dev/null and b/docs/brand/exports/logo/transparent-keyhole-aubergine/closer-mark-256.png differ diff --git a/docs/brand/exports/logo/transparent-keyhole-aubergine/closer-mark-32.png b/docs/brand/exports/logo/transparent-keyhole-aubergine/closer-mark-32.png new file mode 100644 index 00000000..c5ad0856 Binary files /dev/null and b/docs/brand/exports/logo/transparent-keyhole-aubergine/closer-mark-32.png differ diff --git a/docs/brand/exports/logo/transparent-keyhole-aubergine/closer-mark-48.png b/docs/brand/exports/logo/transparent-keyhole-aubergine/closer-mark-48.png new file mode 100644 index 00000000..600c5baa Binary files /dev/null and b/docs/brand/exports/logo/transparent-keyhole-aubergine/closer-mark-48.png differ diff --git a/docs/brand/exports/logo/transparent-keyhole-aubergine/closer-mark-512.png b/docs/brand/exports/logo/transparent-keyhole-aubergine/closer-mark-512.png new file mode 100644 index 00000000..99d5b956 Binary files /dev/null and b/docs/brand/exports/logo/transparent-keyhole-aubergine/closer-mark-512.png differ diff --git a/docs/brand/exports/logo/transparent-keyhole-aubergine/closer-mark-64.png b/docs/brand/exports/logo/transparent-keyhole-aubergine/closer-mark-64.png new file mode 100644 index 00000000..b4a82e7b Binary files /dev/null and b/docs/brand/exports/logo/transparent-keyhole-aubergine/closer-mark-64.png differ diff --git a/docs/brand/exports/logo/transparent-keyhole-aubergine/closer-mark-96.png b/docs/brand/exports/logo/transparent-keyhole-aubergine/closer-mark-96.png new file mode 100644 index 00000000..b8a10227 Binary files /dev/null and b/docs/brand/exports/logo/transparent-keyhole-aubergine/closer-mark-96.png differ diff --git a/docs/brand/exports/logo/transparent-keyhole-black/closer-mark-1024.png b/docs/brand/exports/logo/transparent-keyhole-black/closer-mark-1024.png new file mode 100644 index 00000000..3c715973 Binary files /dev/null and b/docs/brand/exports/logo/transparent-keyhole-black/closer-mark-1024.png differ diff --git a/docs/brand/exports/logo/transparent-keyhole-black/closer-mark-128.png b/docs/brand/exports/logo/transparent-keyhole-black/closer-mark-128.png new file mode 100644 index 00000000..e10bc586 Binary files /dev/null and b/docs/brand/exports/logo/transparent-keyhole-black/closer-mark-128.png differ diff --git a/docs/brand/exports/logo/transparent-keyhole-black/closer-mark-192.png b/docs/brand/exports/logo/transparent-keyhole-black/closer-mark-192.png new file mode 100644 index 00000000..49c6f718 Binary files /dev/null and b/docs/brand/exports/logo/transparent-keyhole-black/closer-mark-192.png differ diff --git a/docs/brand/exports/logo/transparent-keyhole-black/closer-mark-24.png b/docs/brand/exports/logo/transparent-keyhole-black/closer-mark-24.png new file mode 100644 index 00000000..0378c3b2 Binary files /dev/null and b/docs/brand/exports/logo/transparent-keyhole-black/closer-mark-24.png differ diff --git a/docs/brand/exports/logo/transparent-keyhole-black/closer-mark-256.png b/docs/brand/exports/logo/transparent-keyhole-black/closer-mark-256.png new file mode 100644 index 00000000..12338cfd Binary files /dev/null and b/docs/brand/exports/logo/transparent-keyhole-black/closer-mark-256.png differ diff --git a/docs/brand/exports/logo/transparent-keyhole-black/closer-mark-32.png b/docs/brand/exports/logo/transparent-keyhole-black/closer-mark-32.png new file mode 100644 index 00000000..88dc41aa Binary files /dev/null and b/docs/brand/exports/logo/transparent-keyhole-black/closer-mark-32.png differ diff --git a/docs/brand/exports/logo/transparent-keyhole-black/closer-mark-48.png b/docs/brand/exports/logo/transparent-keyhole-black/closer-mark-48.png new file mode 100644 index 00000000..0b7b9361 Binary files /dev/null and b/docs/brand/exports/logo/transparent-keyhole-black/closer-mark-48.png differ diff --git a/docs/brand/exports/logo/transparent-keyhole-black/closer-mark-512.png b/docs/brand/exports/logo/transparent-keyhole-black/closer-mark-512.png new file mode 100644 index 00000000..54970231 Binary files /dev/null and b/docs/brand/exports/logo/transparent-keyhole-black/closer-mark-512.png differ diff --git a/docs/brand/exports/logo/transparent-keyhole-black/closer-mark-64.png b/docs/brand/exports/logo/transparent-keyhole-black/closer-mark-64.png new file mode 100644 index 00000000..c83243a5 Binary files /dev/null and b/docs/brand/exports/logo/transparent-keyhole-black/closer-mark-64.png differ diff --git a/docs/brand/exports/logo/transparent-keyhole-black/closer-mark-96.png b/docs/brand/exports/logo/transparent-keyhole-black/closer-mark-96.png new file mode 100644 index 00000000..270b6c4d Binary files /dev/null and b/docs/brand/exports/logo/transparent-keyhole-black/closer-mark-96.png differ diff --git a/docs/brand/exports/logo/transparent-keyhole-white/closer-mark-1024.png b/docs/brand/exports/logo/transparent-keyhole-white/closer-mark-1024.png new file mode 100644 index 00000000..17482954 Binary files /dev/null and b/docs/brand/exports/logo/transparent-keyhole-white/closer-mark-1024.png differ diff --git a/docs/brand/exports/logo/transparent-keyhole-white/closer-mark-128.png b/docs/brand/exports/logo/transparent-keyhole-white/closer-mark-128.png new file mode 100644 index 00000000..ebb77749 Binary files /dev/null and b/docs/brand/exports/logo/transparent-keyhole-white/closer-mark-128.png differ diff --git a/docs/brand/exports/logo/transparent-keyhole-white/closer-mark-192.png b/docs/brand/exports/logo/transparent-keyhole-white/closer-mark-192.png new file mode 100644 index 00000000..7169ccc3 Binary files /dev/null and b/docs/brand/exports/logo/transparent-keyhole-white/closer-mark-192.png differ diff --git a/docs/brand/exports/logo/transparent-keyhole-white/closer-mark-24.png b/docs/brand/exports/logo/transparent-keyhole-white/closer-mark-24.png new file mode 100644 index 00000000..8ae1ea97 Binary files /dev/null and b/docs/brand/exports/logo/transparent-keyhole-white/closer-mark-24.png differ diff --git a/docs/brand/exports/logo/transparent-keyhole-white/closer-mark-256.png b/docs/brand/exports/logo/transparent-keyhole-white/closer-mark-256.png new file mode 100644 index 00000000..1210cc2c Binary files /dev/null and b/docs/brand/exports/logo/transparent-keyhole-white/closer-mark-256.png differ diff --git a/docs/brand/exports/logo/transparent-keyhole-white/closer-mark-32.png b/docs/brand/exports/logo/transparent-keyhole-white/closer-mark-32.png new file mode 100644 index 00000000..11b6bba3 Binary files /dev/null and b/docs/brand/exports/logo/transparent-keyhole-white/closer-mark-32.png differ diff --git a/docs/brand/exports/logo/transparent-keyhole-white/closer-mark-48.png b/docs/brand/exports/logo/transparent-keyhole-white/closer-mark-48.png new file mode 100644 index 00000000..22adc914 Binary files /dev/null and b/docs/brand/exports/logo/transparent-keyhole-white/closer-mark-48.png differ diff --git a/docs/brand/exports/logo/transparent-keyhole-white/closer-mark-512.png b/docs/brand/exports/logo/transparent-keyhole-white/closer-mark-512.png new file mode 100644 index 00000000..f1a2a365 Binary files /dev/null and b/docs/brand/exports/logo/transparent-keyhole-white/closer-mark-512.png differ diff --git a/docs/brand/exports/logo/transparent-keyhole-white/closer-mark-64.png b/docs/brand/exports/logo/transparent-keyhole-white/closer-mark-64.png new file mode 100644 index 00000000..d673ccff Binary files /dev/null and b/docs/brand/exports/logo/transparent-keyhole-white/closer-mark-64.png differ diff --git a/docs/brand/exports/logo/transparent-keyhole-white/closer-mark-96.png b/docs/brand/exports/logo/transparent-keyhole-white/closer-mark-96.png new file mode 100644 index 00000000..5d127825 Binary files /dev/null and b/docs/brand/exports/logo/transparent-keyhole-white/closer-mark-96.png differ diff --git a/docs/brand/sources/closer-approved-icon-source.png b/docs/brand/sources/closer-approved-icon-source.png new file mode 100644 index 00000000..1668565b Binary files /dev/null and b/docs/brand/sources/closer-approved-icon-source.png differ diff --git a/docs/brand/sources/closer-approved-icon-square.png b/docs/brand/sources/closer-approved-icon-square.png new file mode 100644 index 00000000..6e8ce333 Binary files /dev/null and b/docs/brand/sources/closer-approved-icon-square.png differ diff --git a/docs/brand/sources/closer-mark-transparent-keyhole-aubergine.png b/docs/brand/sources/closer-mark-transparent-keyhole-aubergine.png new file mode 100644 index 00000000..70dee1e6 Binary files /dev/null and b/docs/brand/sources/closer-mark-transparent-keyhole-aubergine.png differ diff --git a/docs/brand/sources/closer-mark-transparent-keyhole-black.png b/docs/brand/sources/closer-mark-transparent-keyhole-black.png new file mode 100644 index 00000000..9cd15ea7 Binary files /dev/null and b/docs/brand/sources/closer-mark-transparent-keyhole-black.png differ diff --git a/docs/brand/sources/closer-mark-transparent-keyhole-white.png b/docs/brand/sources/closer-mark-transparent-keyhole-white.png new file mode 100644 index 00000000..d6826f54 Binary files /dev/null and b/docs/brand/sources/closer-mark-transparent-keyhole-white.png differ diff --git a/docs/brand/sources/closer-mark.svg b/docs/brand/sources/closer-mark.svg new file mode 100644 index 00000000..f5a352a2 --- /dev/null +++ b/docs/brand/sources/closer-mark.svg @@ -0,0 +1,3 @@ + + + diff --git a/docs/brand/visual-identity.md b/docs/brand/visual-identity.md index ff7f8cbd..de2ad2fd 100644 --- a/docs/brand/visual-identity.md +++ b/docs/brand/visual-identity.md @@ -11,14 +11,21 @@ requirements, see `docs/brand/asset-system.md`. ## Brand mark -The mark is one heart formed by two equal halves. Pink and lavender represent two people meeting at -the center; neither side visually dominates. Keep the mark intact and do not separate, rotate, add -text inside, or place it directly over a busy image. +The mark is the approved Closer `C-heart-keyhole`: a soft pink upper `C`, lavender lower sweep, +a heart-shaped inner space, and a true centered keyhole. Pink and lavender represent two people +meeting in one private space; the keyhole represents trust and privacy. +- Master mark source: `docs/brand/sources/closer-approved-icon-source.png` +- Transparent mark source: `docs/brand/sources/closer-mark-transparent-keyhole-aubergine.png` - Launcher source: `docs/store/sources/app-icon.svg` - Android adaptive layers: `app/src/main/res/drawable/ic_launcher_*` +- Android notification glyph: `app/src/main/res/drawable-nodpi/ic_notification_closer.png` - Minimum clear space: one quarter of the mark's width on all sides. -- Minimum digital size: 24 px. At small sizes, use the solid monochrome mark. +- Minimum digital size: 24 px. At small sizes, use the solid monochrome C-heart-keyhole glyph. + +Keep the mark visually faithful to the approved artwork. Do not redraw it as a generic `C`, close +the aperture into an `O`, add a padlock shackle, turn the keyhole into a heart, add a separate key, +or place text inside the icon. ## Core colors @@ -64,8 +71,9 @@ when the couple key is unavailable. These claims describe deployed behavior. - Store graphics and screenshots should use the same purple/pink palette as the product. - Lead with privacy and mutual connection before feature volume. -- The Play feature graphic should show the heart mark, the primary promise, and compact product cues - for private reveals, two-person use, and daily rituals. Do not turn it into a feature checklist. +- The Play feature graphic should show the C-heart-keyhole mark, the primary promise, and compact + product cues for private reveals, two-person use, and daily rituals. Do not turn it into a feature + checklist. - Do not show intimate answer content, real email addresses, invite codes, or notification tokens. - Use clean demo data and crop out development indicators before publishing. - Re-export `docs/store/app-icon-512.png` and `docs/store/feature-graphic-1024x500.png` from the diff --git a/docs/store/app-icon-512.png b/docs/store/app-icon-512.png index 26b1f796..b15dd5e0 100644 Binary files a/docs/store/app-icon-512.png and b/docs/store/app-icon-512.png differ diff --git a/docs/store/feature-graphic-1024x500.png b/docs/store/feature-graphic-1024x500.png index 448a9f35..9e46d407 100644 Binary files a/docs/store/feature-graphic-1024x500.png and b/docs/store/feature-graphic-1024x500.png differ diff --git a/docs/store/sources/app-icon.svg b/docs/store/sources/app-icon.svg index ea6517ca..137dff7f 100644 --- a/docs/store/sources/app-icon.svg +++ b/docs/store/sources/app-icon.svg @@ -1,17 +1,3 @@ - - - - - - - - - - - - - - - - + + diff --git a/docs/store/sources/feature-graphic.svg b/docs/store/sources/feature-graphic.svg index e4311206..3eeabe90 100644 --- a/docs/store/sources/feature-graphic.svg +++ b/docs/store/sources/feature-graphic.svg @@ -13,17 +13,7 @@ - - - - - - - - - - - + Closer A private space diff --git a/iphone/Closer/Components/CommonViews.swift b/iphone/Closer/Components/CommonViews.swift index 4977bae3..3e90ff25 100644 --- a/iphone/Closer/Components/CommonViews.swift +++ b/iphone/Closer/Components/CommonViews.swift @@ -7,7 +7,7 @@ struct LoadingView: View { var body: some View { VStack(spacing: CloserSpacing.lg) { - CloserHeartLoader() + CloserMarkLoader() Text(message) .font(CloserFont.callout) .foregroundColor(.closerTextSecondary) @@ -17,167 +17,44 @@ struct LoadingView: View { } struct CloserHeartLoader: View { + var size: CGFloat = 76 + + var body: some View { + CloserMarkLoader(size: size) + } +} + +struct CloserMarkLoader: View { @Environment(\.accessibilityReduceMotion) private var reduceMotion - @State private var fillProgress: CGFloat = 0.08 @State private var isPulsing = false var size: CGFloat = 76 var body: some View { - ZStack { - CloserHeartShape() - .fill( - LinearGradient( - colors: [ - Color(hex: "F7C8E4").opacity(0.22), - Color(hex: "D9B8FF").opacity(0.22) - ], - startPoint: .leading, - endPoint: .trailing - ) - ) + Image("closer-mark-loader") + .resizable() + .scaledToFit() + .frame(width: size, height: size) + .scaleEffect(reduceMotion ? 1 : (isPulsing ? 1.04 : 0.96)) + .accessibilityHidden(true) + .onAppear { + guard !reduceMotion else { + isPulsing = false + return + } - HStack(spacing: 0) { - Color(hex: "F7C8E4") - Color(hex: "D9B8FF") + withAnimation(.easeInOut(duration: 0.9).repeatForever(autoreverses: true)) { + isPulsing = true + } } - .mask(CloserHeartShape()) - .mask(alignment: .bottom) { - Rectangle() - .frame(height: size * (reduceMotion ? 1 : fillProgress)) + .onChange(of: reduceMotion) { _, newValue in + if newValue { + isPulsing = false + } } - - CloserHeartHighlightShape(side: .left) - .fill(Color(hex: "FFF4FA").opacity(reduceMotion ? 0.68 : 0.68 * fillProgress)) - - CloserHeartHighlightShape(side: .right) - .fill(Color(hex: "F3E8FF").opacity(reduceMotion ? 0.52 : 0.52 * fillProgress)) - } - .frame(width: size, height: size) - .scaleEffect(reduceMotion ? 1 : (isPulsing ? 1.04 : 0.96)) - .accessibilityHidden(true) - .onAppear { - guard !reduceMotion else { - fillProgress = 1 - isPulsing = false - return - } - - withAnimation(.easeInOut(duration: 1.5).repeatForever(autoreverses: false)) { - fillProgress = 1 - } - withAnimation(.easeInOut(duration: 0.9).repeatForever(autoreverses: true)) { - isPulsing = true - } - } - .onChange(of: reduceMotion) { _, newValue in - if newValue { - fillProgress = 1 - isPulsing = false - } - } } } -private struct CloserHeartShape: Shape { - func path(in rect: CGRect) -> Path { - var path = Path() - path.move(to: point(54, 85, in: rect)) - path.addCurve( - to: point(22, 48, in: rect), - control1: point(49, 79, in: rect), - control2: point(27, 62, in: rect) - ) - path.addCurve( - to: point(37, 24, in: rect), - control1: point(17, 35, in: rect), - control2: point(24, 24, in: rect) - ) - path.addCurve( - to: point(54, 35, in: rect), - control1: point(45, 24, in: rect), - control2: point(51, 28, in: rect) - ) - path.addCurve( - to: point(71, 24, in: rect), - control1: point(57, 28, in: rect), - control2: point(63, 24, in: rect) - ) - path.addCurve( - to: point(86, 48, in: rect), - control1: point(84, 24, in: rect), - control2: point(91, 35, in: rect) - ) - path.addCurve( - to: point(54, 85, in: rect), - control1: point(81, 62, in: rect), - control2: point(59, 79, in: rect) - ) - path.closeSubpath() - return path - } -} - -private struct CloserHeartHighlightShape: Shape { - enum Side { - case left - case right - } - - let side: Side - - func path(in rect: CGRect) -> Path { - var path = Path() - switch side { - case .left: - path.move(to: point(27, 42, in: rect)) - path.addCurve( - to: point(42, 27, in: rect), - control1: point(28, 32, in: rect), - control2: point(34, 27, in: rect) - ) - path.addCurve( - to: point(54, 35, in: rect), - control1: point(48, 27, in: rect), - control2: point(52, 30, in: rect) - ) - path.addLine(to: point(54, 41, in: rect)) - path.addCurve( - to: point(27, 42, in: rect), - control1: point(47, 36, in: rect), - control2: point(37, 36, in: rect) - ) - path.closeSubpath() - case .right: - path.move(to: point(54, 35, in: rect)) - path.addCurve( - to: point(69, 27, in: rect), - control1: point(57, 30, in: rect), - control2: point(62, 27, in: rect) - ) - path.addCurve( - to: point(85, 42, in: rect), - control1: point(78, 27, in: rect), - control2: point(84, 32, in: rect) - ) - path.addCurve( - to: point(54, 41, in: rect), - control1: point(75, 36, in: rect), - control2: point(65, 36, in: rect) - ) - path.closeSubpath() - } - return path - } -} - -private func point(_ x: CGFloat, _ y: CGFloat, in rect: CGRect) -> CGPoint { - CGPoint( - x: rect.minX + rect.width * (x / 108), - y: rect.minY + rect.height * (y / 108) - ) -} - // MARK: - Error View struct ErrorView: View { diff --git a/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png index dc1ea7ea..797ed8d4 100644 Binary files a/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png and b/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png index 84281505..80d8bee3 100644 Binary files a/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and b/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png index c5c9022a..3995ea83 100644 Binary files a/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and b/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png index 7ac150a0..e21b4475 100644 Binary files a/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and b/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png index 6fabc100..f3af606a 100644 Binary files a/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and b/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png index 96d4bd9b..ca2b310e 100644 Binary files a/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and b/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png index 44e79a77..fd980d94 100644 Binary files a/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and b/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png index 788a3adc..a9477769 100644 Binary files a/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and b/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png index 93dfda32..0e0a1688 100644 Binary files a/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and b/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png index bba0f5b1..a310774a 100644 Binary files a/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and b/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png index bba0f5b1..a310774a 100644 Binary files a/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and b/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png index 5984b722..376a357b 100644 Binary files a/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and b/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png index 111f65ef..3e44065d 100644 Binary files a/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and b/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png index 60aa80b2..6081d92d 100644 Binary files a/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and b/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png index 05ad42c5..1b79f987 100644 Binary files a/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and b/iphone/Closer/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/iphone/Closer/Resources/closer-mark-loader.png b/iphone/Closer/Resources/closer-mark-loader.png new file mode 100644 index 00000000..cddf19b2 Binary files /dev/null and b/iphone/Closer/Resources/closer-mark-loader.png differ