@@ -17,7 +17,12 @@ package com.android.developers.androidify.results
1717
1818import androidx.compose.foundation.basicMarquee
1919import androidx.compose.foundation.layout.Box
20+ import androidx.compose.foundation.layout.BoxScope
21+ import androidx.compose.foundation.layout.BoxWithConstraints
2022import androidx.compose.foundation.layout.fillMaxSize
23+ import androidx.compose.foundation.layout.fillMaxWidth
24+ import androidx.compose.foundation.layout.requiredWidthIn
25+ import androidx.compose.foundation.layout.size
2126import androidx.compose.material3.MaterialTheme
2227import androidx.compose.material3.Text
2328import androidx.compose.runtime.Composable
@@ -27,42 +32,56 @@ import androidx.compose.ui.Modifier
2732import androidx.compose.ui.platform.LocalInspectionMode
2833import androidx.compose.ui.res.stringArrayResource
2934import androidx.compose.ui.text.font.FontWeight.Companion.Bold
35+ import androidx.compose.ui.tooling.preview.Preview
3036import androidx.compose.ui.unit.dp
3137import androidx.compose.ui.unit.sp
38+ import com.android.developers.androidify.theme.AndroidifyTheme
39+ import com.android.developers.androidify.util.LargeScreensPreview
3240
3341@Composable
34- fun BackgroundQuotes (quote1 : String , quote2 : String? , verboseLayout : Boolean = true) {
42+ fun BackgroundQuotes (
43+ quote1 : String ,
44+ quote2 : String? ,
45+ verboseLayout : Boolean = true,
46+ enableAnimations : Boolean = !LocalInspectionMode .current,
47+ ) {
3548 // Disable animation in tests
36- val iterations = if (LocalInspectionMode .current) 0 else 100
49+ val iterations = if (enableAnimations) 100 else 0
3750
3851 Box (modifier = Modifier .fillMaxSize()) {
39- Text (
40- quote1,
41- style = MaterialTheme .typography.titleLarge.copy(fontWeight = Bold ),
42- fontSize = 120 .sp,
43- modifier = Modifier
44- .align(if (verboseLayout) Alignment .TopCenter else Alignment .Center )
45- .basicMarquee(
52+ AlwaysMarquee (
53+ size = 1.2f ,
54+ modifier = Modifier .align(if (verboseLayout) Alignment .TopCenter else Alignment .Center ),
55+ marqueeModifier = Modifier .basicMarquee(
56+ iterations = iterations,
57+ repeatDelayMillis = 0 ,
58+ velocity = 80 .dp,
59+ initialDelayMillis = 500 ,
60+ ),
61+ ) {
62+ Text (
63+ quote1,
64+ style = MaterialTheme .typography.titleLarge.copy(fontWeight = Bold ),
65+ fontSize = 120 .sp,
66+ )
67+ }
68+ if (quote2 != null ) {
69+ AlwaysMarquee (
70+ size = 1.2f ,
71+ modifier = Modifier .align(Alignment .BottomCenter ),
72+ marqueeModifier = Modifier .basicMarquee(
4673 iterations = iterations,
4774 repeatDelayMillis = 0 ,
48- velocity = 80 .dp,
75+ velocity = 60 .dp,
4976 initialDelayMillis = 500 ,
5077 ),
51- )
52- if (quote2 != null ) {
53- Text (
54- quote2,
55- style = MaterialTheme .typography.titleLarge.copy(fontWeight = Bold ),
56- fontSize = 110 .sp,
57- modifier = Modifier
58- .align(Alignment .BottomCenter )
59- .basicMarquee(
60- iterations = iterations,
61- repeatDelayMillis = 0 ,
62- velocity = 60 .dp,
63- initialDelayMillis = 500 ,
64- ),
65- )
78+ ) {
79+ Text (
80+ quote2,
81+ style = MaterialTheme .typography.titleLarge.copy(fontWeight = Bold ),
82+ fontSize = 110 .sp,
83+ )
84+ }
6685 }
6786 }
6887}
@@ -93,3 +112,80 @@ fun BackgroundRandomQuotes(verboseLayout: Boolean = true) {
93112 }
94113 BackgroundQuotes (quote1, quote2, verboseLayout)
95114}
115+
116+ /* *
117+ * A composable that will always scroll its contents. [Modifier.basicMarquee] does nothing when the
118+ * contents fit in the max constraints. This composable creates a box that is always larger than the
119+ * max constraints and applies the marquee to that box.
120+ */
121+ @Composable
122+ private fun AlwaysMarquee (
123+ size : Float ,
124+ marqueeModifier : Modifier ,
125+ modifier : Modifier = Modifier ,
126+ content : @Composable BoxScope .() -> Unit ,
127+ ) {
128+ BoxWithConstraints (modifier = modifier.fillMaxWidth()) {
129+ Box (marqueeModifier) {
130+ Box (Modifier .requiredWidthIn(min = this @BoxWithConstraints.maxWidth * size)) {
131+ content()
132+ }
133+ }
134+ }
135+ }
136+
137+ @Preview
138+ @Composable
139+ private fun ShortTextMarqueePreview () {
140+ Box (Modifier .size(600 .dp)) {
141+ AlwaysMarquee (
142+ 1.2f ,
143+ marqueeModifier = Modifier .basicMarquee(
144+ iterations = Int .MAX_VALUE ,
145+ repeatDelayMillis = 0 ,
146+ velocity = 80 .dp,
147+ initialDelayMillis = 500 ,
148+ ),
149+ ) {
150+ Text (
151+ modifier = Modifier .align(Alignment .Center ),
152+ text = " I'm small but I want to marquee!" ,
153+ style = MaterialTheme .typography.titleLarge.copy(fontWeight = Bold ),
154+ fontSize = 20 .sp,
155+ )
156+ }
157+ }
158+ }
159+
160+ @Preview
161+ @Composable
162+ private fun LongTextMarqueePreview () {
163+ Box (Modifier .size(600 .dp)) {
164+ AlwaysMarquee (
165+ 1.2f ,
166+ marqueeModifier = Modifier .basicMarquee(
167+ iterations = Int .MAX_VALUE ,
168+ repeatDelayMillis = 0 ,
169+ velocity = 80 .dp,
170+ initialDelayMillis = 500 ,
171+ ),
172+ ) {
173+ Text (
174+ modifier = Modifier .align(Alignment .Center ),
175+
176+ text = " I'm big and moving!" ,
177+ style = MaterialTheme .typography.titleLarge.copy(fontWeight = Bold ),
178+ fontSize = 70 .sp,
179+ )
180+ }
181+ }
182+ }
183+
184+ @Preview
185+ @Composable
186+ @LargeScreensPreview
187+ private fun BackgroundQuotesPreview () {
188+ AndroidifyTheme {
189+ BackgroundRandomQuotes ()
190+ }
191+ }
0 commit comments