Skip to content

Commit 7c320e6

Browse files
committed
Bug 2021398 - Refined s2s gradient
1 parent 411fd75 commit 7c320e6

5 files changed

Lines changed: 120 additions & 68 deletions

File tree

mobile/android/android-components/components/feature/summarize/src/main/java/mozilla/components/feature/summarize/SummarizationScreen.kt

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@ import androidx.compose.ui.draw.clip
3131
import androidx.compose.ui.graphics.Color
3232
import androidx.compose.ui.input.nestedscroll.nestedScroll
3333
import androidx.compose.ui.platform.rememberNestedScrollInteropConnection
34-
import androidx.compose.ui.tooling.preview.Preview
3534
import androidx.compose.ui.tooling.preview.PreviewParameter
3635
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
3736
import androidx.compose.ui.unit.dp
3837
import androidx.lifecycle.compose.collectAsStateWithLifecycle
38+
import mozilla.components.compose.base.annotation.FlexibleWindowLightDarkPreview
3939
import mozilla.components.compose.base.modifier.thenConditional
4040
import mozilla.components.compose.base.theme.AcornTheme
4141
import mozilla.components.feature.summarize.ui.DownloadError
@@ -111,7 +111,9 @@ private fun SummarizationScreen(
111111
},
112112
)
113113
}
114-
is SummarizationState.Summarizing -> SummarizingContent()
114+
is SummarizationState.Summarizing -> SummarizingContent(
115+
modifier = Modifier.height(252.dp),
116+
)
115117
is SummarizationState.Summarized -> SummarizedContent(
116118
text = state.text,
117119
modifier = Modifier.verticalScroll(rememberScrollState())
@@ -194,16 +196,18 @@ private class SummarizationStatePreviewProvider : PreviewParameterProvider<Summa
194196
)
195197
}
196198

197-
@Preview
199+
@FlexibleWindowLightDarkPreview
198200
@Composable
199201
private fun SummarizationScreenPreview(
200202
@PreviewParameter(SummarizationStatePreviewProvider::class) state: SummarizationState,
201203
) {
202-
SummarizationScreen(
203-
store = SummarizationStore(
204-
initialState = state,
205-
reducer = ::summarizationReducer,
206-
middleware = listOf(),
207-
),
208-
)
204+
AcornTheme {
205+
SummarizationScreen(
206+
store = SummarizationStore(
207+
initialState = state,
208+
reducer = ::summarizationReducer,
209+
middleware = listOf(),
210+
),
211+
)
212+
}
209213
}

mobile/android/android-components/components/feature/summarize/src/main/java/mozilla/components/feature/summarize/ui/SummarizingContent.kt

Lines changed: 72 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,68 +5,116 @@
55
package mozilla.components.feature.summarize.ui
66

77
import androidx.compose.foundation.background
8+
import androidx.compose.foundation.layout.Arrangement
89
import androidx.compose.foundation.layout.Box
10+
import androidx.compose.foundation.layout.Column
911
import androidx.compose.foundation.layout.fillMaxSize
1012
import androidx.compose.foundation.layout.fillMaxWidth
1113
import androidx.compose.foundation.layout.height
1214
import androidx.compose.foundation.layout.padding
15+
import androidx.compose.foundation.layout.requiredHeight
16+
import androidx.compose.foundation.layout.requiredSize
17+
import androidx.compose.foundation.layout.size
1318
import androidx.compose.foundation.shape.RoundedCornerShape
19+
import androidx.compose.material3.Icon
1420
import androidx.compose.material3.MaterialTheme
1521
import androidx.compose.material3.Surface
1622
import androidx.compose.material3.Text
1723
import androidx.compose.runtime.Composable
24+
import androidx.compose.foundation.isSystemInDarkTheme
1825
import androidx.compose.ui.Alignment
1926
import androidx.compose.ui.Modifier
27+
import androidx.compose.ui.graphics.Color
28+
import androidx.compose.ui.res.painterResource
2029
import androidx.compose.ui.res.stringResource
2130
import androidx.compose.ui.text.font.FontWeight
2231
import androidx.compose.ui.text.style.TextAlign
23-
import androidx.compose.ui.tooling.preview.Preview
2432
import androidx.compose.ui.unit.dp
2533
import androidx.compose.ui.unit.sp
34+
import mozilla.components.compose.base.annotation.FlexibleWindowLightDarkPreview
35+
import mozilla.components.compose.base.theme.AcornTheme
2636
import mozilla.components.feature.summarize.R
37+
import mozilla.components.feature.summarize.ui.gradient.summaryLoadingGradient
38+
import mozilla.components.ui.icons.R as iconsR
2739

2840
/**
2941
* Content shown while a page summary is being generated.
30-
* Displays the animated gradient background with centered loading text.
42+
* Displays a Firefox logo icon and loading text over the animated gradient background.
3143
*/
3244
@Composable
3345
internal fun SummarizingContent(
46+
modifier: Modifier = Modifier,
3447
title: String = stringResource(R.string.mozac_feature_summarize_loading_title),
3548
) {
36-
Box(
37-
contentAlignment = Alignment.Center,
49+
Column(
50+
modifier = modifier
51+
.fillMaxWidth()
52+
.padding(top = 80.dp),
53+
horizontalAlignment = Alignment.CenterHorizontally,
54+
verticalArrangement = Arrangement.spacedBy(10.dp),
3855
) {
56+
val contentColor = if (isSystemInDarkTheme()) {
57+
MaterialTheme.colorScheme.onSurface
58+
} else {
59+
MaterialTheme.colorScheme.onPrimary
60+
}
61+
62+
Icon(
63+
painter = painterResource(id = iconsR.drawable.mozac_ic_logo_firefox_24),
64+
contentDescription = null,
65+
modifier = Modifier.size(48.dp),
66+
tint = contentColor,
67+
)
68+
3969
Text(
4070
text = title,
41-
modifier = Modifier
42-
.fillMaxWidth()
43-
.padding(horizontal = 16.dp),
4471
textAlign = TextAlign.Center,
45-
color = MaterialTheme.colorScheme.onSurface,
46-
fontSize = 20.sp,
47-
fontWeight = FontWeight.Medium,
48-
lineHeight = 24.sp,
49-
letterSpacing = 0.15.sp,
72+
color = contentColor.copy(alpha = 0.5f),
73+
fontSize = 16.sp,
74+
fontWeight = FontWeight.SemiBold,
75+
lineHeight = 21.sp,
76+
letterSpacing = (-0.31).sp,
5077
)
5178
}
5279
}
5380

54-
@Preview(showBackground = true, heightDp = 800)
81+
@FlexibleWindowLightDarkPreview
5582
@Composable
5683
private fun SummarizingContentPreview() {
57-
Box(
58-
modifier = Modifier
59-
.fillMaxSize()
60-
.background(MaterialTheme.colorScheme.surfaceVariant),
61-
contentAlignment = Alignment.BottomCenter,
62-
) {
63-
Surface(
84+
AcornTheme {
85+
Box(
6486
modifier = Modifier
65-
.fillMaxWidth()
66-
.height(400.dp),
67-
shape = RoundedCornerShape(topStart = 28.dp, topEnd = 28.dp),
87+
.fillMaxSize()
88+
.background(MaterialTheme.colorScheme.surfaceVariant),
89+
contentAlignment = Alignment.BottomCenter,
6890
) {
69-
SummarizingContent()
91+
Surface(
92+
modifier = Modifier
93+
.fillMaxWidth()
94+
.height(336.dp),
95+
shape = RoundedCornerShape(topStart = 28.dp, topEnd = 28.dp),
96+
) {
97+
Box(modifier = Modifier.fillMaxSize().summaryLoadingGradient()) {
98+
Column(modifier = Modifier.fillMaxWidth()) {
99+
Box(
100+
modifier = Modifier.fillMaxWidth().requiredHeight(36.dp),
101+
contentAlignment = Alignment.Center,
102+
) {
103+
Box(
104+
modifier = Modifier
105+
.requiredSize(width = 32.dp, height = 4.dp)
106+
.background(
107+
color = MaterialTheme.colorScheme.outline,
108+
shape = RoundedCornerShape(50),
109+
),
110+
)
111+
}
112+
SummarizingContent()
113+
}
114+
}
115+
}
70116
}
71117
}
72118
}
119+
120+

mobile/android/android-components/components/feature/summarize/src/main/java/mozilla/components/feature/summarize/ui/gradient/AnimationLayer.kt

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
package mozilla.components.feature.summarize.ui.gradient
66

77
import android.graphics.BlurMaskFilter
8-
import android.os.Build
98
import androidx.compose.animation.core.LinearEasing
109
import androidx.compose.animation.core.LinearOutSlowInEasing
1110
import androidx.compose.animation.core.RepeatMode
@@ -50,7 +49,6 @@ import androidx.compose.ui.unit.dp
5049
import androidx.compose.ui.util.lerp
5150
import kotlin.math.cos
5251
import kotlin.math.sin
53-
import android.graphics.BlendMode as AndroidBlendMode
5452
import android.graphics.Paint as AndroidPaint
5553

5654
private object GradientDefaults {
@@ -67,25 +65,24 @@ private object BlobDefaults {
6765
}
6866

6967
private object GradientPalette {
70-
val gradientStart = Color(0xFF3A0F6E)
71-
val gradientMiddle = Color(0xFF7543E3)
72-
val gradientEnd = Color(0xFFFF7638)
68+
val gradientStart = Color(0xFF9059FF)
69+
val gradientMiddle = Color(0xFFFF4AA2)
70+
val gradientEnd = Color(0xFFFFA436)
7371
}
7472

7573
private data class BlobDrawLayer(
7674
val spec: BlobSpec,
7775
val phases: BlobPhases,
7876
val color: Color,
79-
val useColorDodge: Boolean = false,
8077
)
8178

8279
private val BLOB_DRAW_LAYERS = listOf(
8380
BlobDrawLayer(DARK_PURPLE_BLOB, DARK_PURPLE_G1_PHASES, GradientPalette.gradientStart),
8481
BlobDrawLayer(LIGHT_PURPLE_BLOB, LIGHT_PURPLE_G1_PHASES, GradientPalette.gradientMiddle),
8582
BlobDrawLayer(ORANGE_BLOB, ORANGE_G1_PHASES, GradientPalette.gradientEnd),
86-
BlobDrawLayer(DARK_PURPLE_BLOB, DARK_PURPLE_G2_PHASES, GradientPalette.gradientStart, useColorDodge = true),
87-
BlobDrawLayer(LIGHT_PURPLE_BLOB, LIGHT_PURPLE_G2_PHASES, GradientPalette.gradientMiddle, useColorDodge = true),
88-
BlobDrawLayer(ORANGE_BLOB, ORANGE_G2_PHASES, GradientPalette.gradientEnd, useColorDodge = true),
83+
BlobDrawLayer(DARK_PURPLE_BLOB, DARK_PURPLE_G2_PHASES, GradientPalette.gradientStart),
84+
BlobDrawLayer(LIGHT_PURPLE_BLOB, LIGHT_PURPLE_G2_PHASES, GradientPalette.gradientMiddle),
85+
BlobDrawLayer(ORANGE_BLOB, ORANGE_G2_PHASES, GradientPalette.gradientEnd),
8986
)
9087

9188
private data class CircleSegment(
@@ -157,7 +154,6 @@ fun Modifier.summaryLoadingGradient(): Modifier = composed {
157154
paint = blobPaint,
158155
maskFilter = blobMaskFilter,
159156
widthDp = pose.widthDp,
160-
useColorDodge = layer.useColorDodge,
161157
)
162158
}
163159
}
@@ -278,7 +274,6 @@ private fun DrawScope.drawBlob(
278274
paint: AndroidPaint,
279275
maskFilter: BlurMaskFilter,
280276
widthDp: Float = spec.widthDp,
281-
useColorDodge: Boolean = false,
282277
) {
283278
val xPx = positionDp.x * density
284279
val yPx = positionDp.y * density
@@ -287,10 +282,6 @@ private fun DrawScope.drawBlob(
287282
val rotationPivot = Offset(spec.originalWidthDp / 2f, spec.originalWidthDp / 2f)
288283

289284
paint.color = color.toArgb()
290-
// COLOR_DODGE requires API 29+; on older devices blobs render with normal blending.
291-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
292-
paint.blendMode = if (useColorDodge) AndroidBlendMode.COLOR_DODGE else null
293-
}
294285
paint.maskFilter = maskFilter
295286

296287
translate(left = xPx, top = yPx) {

mobile/android/android-components/components/feature/summarize/src/main/java/mozilla/components/feature/summarize/ui/gradient/PhaseData.kt

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -56,40 +56,49 @@ internal val ORANGE_BLOB = BlobSpec(
5656
rotationDeg = 240f,
5757
)
5858

59+
// G1 (Group 3) is static — same position at all keyframes.
60+
private val DARK_PURPLE_G1_POSE = BlobPose(offsetDp = Offset(135f, 159f), widthDp = 343f)
61+
5962
internal val DARK_PURPLE_G1_PHASES = BlobPhases(
60-
phase1 = BlobPose(offsetDp = Offset(135f, 159f), widthDp = 343f),
61-
phase2 = BlobPose(offsetDp = Offset(19f, 16f), widthDp = 343f),
62-
phase3 = BlobPose(offsetDp = Offset(-21f, 188f), widthDp = 271f),
63+
phase1 = DARK_PURPLE_G1_POSE,
64+
phase2 = DARK_PURPLE_G1_POSE,
65+
phase3 = DARK_PURPLE_G1_POSE,
6366
)
6467

68+
private val LIGHT_PURPLE_G1_POSE = BlobPose(offsetDp = Offset(-15f, 4f), widthDp = 439f)
69+
6570
internal val LIGHT_PURPLE_G1_PHASES = BlobPhases(
66-
phase1 = BlobPose(offsetDp = Offset(421.225f, 4f), widthDp = 439f),
67-
phase2 = BlobPose(offsetDp = Offset(220f, 143f), widthDp = 439f),
68-
phase3 = BlobPose(offsetDp = Offset(167f, 188f), widthDp = 405f),
71+
phase1 = LIGHT_PURPLE_G1_POSE,
72+
phase2 = LIGHT_PURPLE_G1_POSE,
73+
phase3 = LIGHT_PURPLE_G1_POSE,
6974
)
7075

76+
private val ORANGE_G1_POSE = BlobPose(offsetDp = Offset(373f, -27f), widthDp = 269.225f)
77+
7178
internal val ORANGE_G1_PHASES = BlobPhases(
72-
phase1 = BlobPose(offsetDp = Offset(373f, -27.322f), widthDp = 269.225f),
73-
phase2 = BlobPose(offsetDp = Offset(-10.225f, -13.322f), widthDp = 269.225f),
74-
phase3 = BlobPose(offsetDp = Offset(491f, -1f), widthDp = 277f),
79+
phase1 = ORANGE_G1_POSE,
80+
phase2 = ORANGE_G1_POSE,
81+
phase3 = ORANGE_G1_POSE,
7582
)
7683

84+
// G2 (Group 2) animates. Phase 1 overlaps G1; phases 2/3 from Figma variants 6/4.
85+
// Positions mapped by COLOR (where each color appears in the Figma keyframe).
7786
internal val DARK_PURPLE_G2_PHASES = BlobPhases(
78-
phase1 = DARK_PURPLE_G1_PHASES.phase1,
79-
phase2 = BlobPose(offsetDp = Offset(288f, 214f), widthDp = 259f),
80-
phase3 = BlobPose(offsetDp = Offset(-21f, -1f), widthDp = 259f),
87+
phase1 = DARK_PURPLE_G1_POSE,
88+
phase2 = BlobPose(offsetDp = Offset(220f, 143f), widthDp = 439f),
89+
phase3 = BlobPose(offsetDp = Offset(-63f, 156f), widthDp = 271f),
8190
)
8291

8392
internal val LIGHT_PURPLE_G2_PHASES = BlobPhases(
84-
phase1 = LIGHT_PURPLE_G1_PHASES.phase1,
85-
phase2 = BlobPose(offsetDp = Offset(242f, 155f), widthDp = 439f),
86-
phase3 = BlobPose(offsetDp = Offset(9f, 35f), widthDp = 671f),
93+
phase1 = LIGHT_PURPLE_G1_POSE,
94+
phase2 = BlobPose(offsetDp = Offset(19f, 16f), widthDp = 343f),
95+
phase3 = BlobPose(offsetDp = Offset(125f, 156f), widthDp = 405f),
8796
)
8897

8998
internal val ORANGE_G2_PHASES = BlobPhases(
90-
phase1 = ORANGE_G1_PHASES.phase1,
91-
phase2 = BlobPose(offsetDp = Offset(-61.225f, -13.322f), widthDp = 269.225f),
92-
phase3 = BlobPose(offsetDp = Offset(208f, 4f), widthDp = 195f),
99+
phase1 = ORANGE_G1_POSE,
100+
phase2 = BlobPose(offsetDp = Offset(-10f, -13f), widthDp = 372f),
101+
phase3 = BlobPose(offsetDp = Offset(385f, -33f), widthDp = 341f),
93102
)
94103

95104
internal object CircleAnimation {

mobile/android/android-components/components/feature/summarize/src/main/res/values/static_strings.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,5 +82,5 @@
8282
<string name="mozac_summarize_info_error_fallback_message">Unknown error</string>
8383

8484
<!-- Loading text displayed while a page summary is being generated -->
85-
<string name="mozac_feature_summarize_loading_title" translatable="false">Creating summary…</string>
85+
<string name="mozac_feature_summarize_loading_title" translatable="false">Summarizing…</string>
8686
</resources>

0 commit comments

Comments
 (0)