Skip to content

Commit 76a32c2

Browse files
mindy-stripeclaude
andauthored
[link] Move Link brand logo inline to terms and conditions (#13154)
* Move Link brand logo from input field to inline terms Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Committed-By-Agent: claude * Re-record screenshots after logo relocation Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Committed-By-Agent: claude * Apply subtitle tint to Link logo * Regenerate snapshots * Api dump * Fix import detekt --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 0e32ba3 commit 76a32c2

69 files changed

Lines changed: 63 additions & 99 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

paymentsheet/api/paymentsheet.api

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -273,8 +273,10 @@ public final class com/stripe/android/link/ui/ComposableSingletons$LinkSpinnerKt
273273
public final class com/stripe/android/link/ui/ComposableSingletons$LinkTermsKt {
274274
public static final field INSTANCE Lcom/stripe/android/link/ui/ComposableSingletons$LinkTermsKt;
275275
public fun <init> ()V
276-
public final fun getLambda$-2087552559$paymentsheet_release ()Lkotlin/jvm/functions/Function2;
277-
public final fun getLambda$1274925453$paymentsheet_release ()Lkotlin/jvm/functions/Function2;
276+
public final fun getLambda$-146480353$paymentsheet_release ()Lkotlin/jvm/functions/Function2;
277+
public final fun getLambda$-1583971741$paymentsheet_release ()Lkotlin/jvm/functions/Function2;
278+
public final fun getLambda$-789569505$paymentsheet_release ()Lkotlin/jvm/functions/Function2;
279+
public final fun getLambda$620731363$paymentsheet_release ()Lkotlin/jvm/functions/Function2;
278280
}
279281

280282
public final class com/stripe/android/link/ui/ComposableSingletons$PrimaryButtonKt {

paymentsheet/src/main/java/com/stripe/android/link/ui/LinkTerms.kt

Lines changed: 47 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
11
package com.stripe.android.link.ui
22

3+
import androidx.compose.foundation.layout.Arrangement
4+
import androidx.compose.foundation.layout.Column
5+
import androidx.compose.foundation.layout.padding
36
import androidx.compose.material.MaterialTheme
47
import androidx.compose.material.Surface
58
import androidx.compose.runtime.Composable
69
import androidx.compose.ui.Modifier
10+
import androidx.compose.ui.graphics.ColorFilter
711
import androidx.compose.ui.res.stringResource
812
import androidx.compose.ui.text.PlaceholderVerticalAlign
913
import androidx.compose.ui.text.style.TextAlign
1014
import androidx.compose.ui.tooling.preview.Preview
15+
import androidx.compose.ui.unit.dp
1116
import com.stripe.android.model.LinkBrand
1217
import com.stripe.android.paymentsheet.R
1318
import com.stripe.android.ui.core.elements.Mandate
1419
import com.stripe.android.uicore.StripeTheme
15-
import com.stripe.android.uicore.shouldUseDarkDynamicColor
1620
import com.stripe.android.uicore.stripeColors
1721
import com.stripe.android.uicore.text.EmbeddableImage
1822

@@ -34,19 +38,17 @@ internal fun LinkTerms(
3438
val text = linkTermsText(type, linkBrand)
3539

3640
val imageLoader = buildMap {
37-
if (type == LinkTermsType.InlineWithDefaultOptIn) {
41+
if (type != LinkTermsType.Full) {
3842
put(
3943
"link_logo",
4044
EmbeddableImage.Drawable(
41-
id = if (MaterialTheme.stripeColors.component.shouldUseDarkDynamicColor()) {
42-
linkBrand.logoRes(LinkLogoStyle.TermsKnockoutBlack)
43-
} else {
44-
linkBrand.logoRes(LinkLogoStyle.TermsKnockoutWhite)
45-
},
45+
id = linkBrand.logoRes(LinkLogoStyle.InlineKnockout),
4646
contentDescription = when (linkBrand) {
4747
LinkBrand.Link -> com.stripe.android.R.string.stripe_link
4848
LinkBrand.Onelink -> com.stripe.android.R.string.stripe_onelink
4949
},
50+
colorFilter = ColorFilter.tint(MaterialTheme.stripeColors.subtitle),
51+
verticalOffset = 1.dp,
5052
)
5153
)
5254
}
@@ -66,38 +68,43 @@ private fun linkTermsText(type: LinkTermsType, linkBrand: LinkBrand): String {
6668
val brandName = linkBrand.brandName()
6769
return when (type) {
6870
LinkTermsType.InlineOptionalWithPhoneFirst -> {
69-
if (linkBrand == LinkBrand.Link) {
71+
val terms = if (linkBrand == LinkBrand.Link) {
7072
stringResource(R.string.stripe_sign_up_terms_alternative_with_phone_number)
7173
} else {
7274
stringResource(R.string.stripe_sign_up_terms_alternative_with_phone_number_branded, brandName)
7375
}
76+
terms.withLeadingLogo()
7477
}
7578
LinkTermsType.InlineOptional -> {
76-
if (linkBrand == LinkBrand.Link) {
79+
val terms = if (linkBrand == LinkBrand.Link) {
7780
stringResource(R.string.stripe_sign_up_terms_alternative)
7881
} else {
7982
stringResource(R.string.stripe_sign_up_terms_alternative_branded, brandName)
8083
}
84+
terms.withLeadingLogo()
8185
}
8286
LinkTermsType.Inline -> {
83-
if (linkBrand == LinkBrand.Link) {
87+
val terms = if (linkBrand == LinkBrand.Link) {
8488
stringResource(R.string.stripe_sign_up_terms)
8589
} else {
8690
stringResource(R.string.stripe_sign_up_terms_branded, brandName)
8791
}
92+
terms.withLeadingLogo()
8893
}
8994
LinkTermsType.InlineWithDefaultOptIn -> {
9095
val terms = if (linkBrand == LinkBrand.Link) {
9196
stringResource(R.string.stripe_sign_up_terms_default_opt_in)
9297
} else {
9398
stringResource(R.string.stripe_sign_up_terms_default_opt_in_branded, brandName)
9499
}
95-
"<img src=\"link_logo\"> • $terms"
100+
terms.withLeadingLogo()
96101
}
97102
LinkTermsType.Full -> stringResource(R.string.stripe_link_sign_up_terms)
98103
}
99104
}
100105

106+
private fun String.withLeadingLogo() = "<img src=\"link_logo\"> • $this"
107+
101108
internal fun String.replaceHyperlinks(linkBrand: LinkBrand) = this.replace(
102109
"<terms>",
103110
"<a href=\"${linkBrand.termsUrl()}\">"
@@ -109,15 +116,38 @@ internal fun String.replaceHyperlinks(linkBrand: LinkBrand) = this.replace(
109116
"<a href=\"${linkBrand.baseUrl()}\">"
110117
).replace("</link>", "</a>")
111118

112-
@Preview
119+
@Preview(name = "All types - Link")
113120
@Composable
114-
private fun LinkTermsPreview() {
121+
private fun LinkTermsAllTypesLinkPreview() {
115122
StripeTheme {
116123
Surface {
117-
LinkTerms(
118-
type = LinkTermsType.InlineOptional,
119-
linkBrand = LinkBrand.Link,
120-
)
124+
Column(verticalArrangement = Arrangement.spacedBy(4.dp)) {
125+
LinkTermsType.entries.forEach { type ->
126+
LinkTerms(
127+
type = type,
128+
linkBrand = LinkBrand.Link,
129+
modifier = Modifier.padding(bottom = 12.dp),
130+
)
131+
}
132+
}
133+
}
134+
}
135+
}
136+
137+
@Preview(name = "All types - Onelink")
138+
@Composable
139+
private fun LinkTermsAllTypesOnelinkPreview() {
140+
StripeTheme {
141+
Surface {
142+
Column(verticalArrangement = Arrangement.spacedBy(4.dp)) {
143+
LinkTermsType.entries.forEach { type ->
144+
LinkTerms(
145+
type = type,
146+
linkBrand = LinkBrand.Onelink,
147+
modifier = Modifier.padding(bottom = 12.dp),
148+
)
149+
}
150+
}
121151
}
122152
}
123153
}

paymentsheet/src/main/java/com/stripe/android/link/ui/inline/LinkInlineSignup.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -551,7 +551,6 @@ internal fun LinkFields(
551551
emailFocusRequester = emailFocusRequester,
552552
requiresNameCollection = requiresNameCollection,
553553
allowsDefaultOptIn = allowsDefaultOptIn,
554-
linkBrand = linkBrand,
555554
errorMessage = errorMessage,
556555
didShowAllFields = didShowAllFields,
557556
onShowingAllFields = { didShowAllFields = true },

paymentsheet/src/main/java/com/stripe/android/link/ui/inline/LinkInlineSignupFields.kt

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import androidx.compose.ui.unit.dp
2626
import androidx.compose.ui.unit.sp
2727
import com.stripe.android.link.theme.DefaultLinkTheme
2828
import com.stripe.android.link.ui.signup.SignUpState
29-
import com.stripe.android.model.LinkBrand
3029
import com.stripe.android.paymentsheet.R
3130
import com.stripe.android.ui.core.elements.HyperlinkedText
3231
import com.stripe.android.uicore.elements.EmailConfig
@@ -40,8 +39,6 @@ import com.stripe.android.uicore.elements.TextFieldController
4039
import com.stripe.android.uicore.stripeColors
4140
import com.stripe.android.uicore.stripeShapes
4241

43-
private val LinkLogoModifier = Modifier.padding(end = 16.dp)
44-
4542
@Suppress("LongMethod")
4643
@Composable
4744
internal fun LinkInlineSignupFields(
@@ -54,7 +51,6 @@ internal fun LinkInlineSignupFields(
5451
isShowingPhoneFirst: Boolean,
5552
requiresNameCollection: Boolean,
5653
allowsDefaultOptIn: Boolean,
57-
linkBrand: LinkBrand,
5854
errorMessage: String?,
5955
didShowAllFields: Boolean,
6056
onShowingAllFields: () -> Unit,
@@ -79,16 +75,6 @@ internal fun LinkInlineSignupFields(
7975
ImeAction.Done
8076
},
8177
focusRequester = phoneFocusRequester,
82-
trailingIcon = if (!allowsDefaultOptIn) {
83-
{
84-
LinkLogo(
85-
modifier = LinkLogoModifier,
86-
linkBrand = linkBrand,
87-
)
88-
}
89-
} else {
90-
null
91-
},
9278
)
9379
} else {
9480
EmailCollection(
@@ -101,16 +87,6 @@ internal fun LinkInlineSignupFields(
10187
ImeAction.Done
10288
},
10389
focusRequester = emailFocusRequester,
104-
trailingIcon = if (!allowsDefaultOptIn) {
105-
{
106-
LinkLogo(
107-
modifier = LinkLogoModifier,
108-
linkBrand = linkBrand,
109-
)
110-
}
111-
} else {
112-
null
113-
},
11490
)
11591
}
11692

@@ -242,7 +218,6 @@ internal fun PreviewLinkInlineSignupFields() {
242218
enabled = true,
243219
isShowingPhoneFirst = false,
244220
requiresNameCollection = false,
245-
linkBrand = LinkBrand.Link,
246221
errorMessage = "This is a large error!",
247222
didShowAllFields = false,
248223
allowsDefaultOptIn = false,

paymentsheet/src/main/java/com/stripe/android/link/ui/inline/LinkOptionalInlineSignup.kt

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,10 @@ import androidx.compose.foundation.ExperimentalFoundationApi
77
import androidx.compose.foundation.layout.Column
88
import androidx.compose.foundation.layout.Row
99
import androidx.compose.foundation.layout.fillMaxWidth
10-
import androidx.compose.foundation.layout.height
1110
import androidx.compose.foundation.layout.padding
1211
import androidx.compose.foundation.layout.size
1312
import androidx.compose.foundation.relocation.BringIntoViewRequester
1413
import androidx.compose.foundation.relocation.bringIntoViewRequester
15-
import androidx.compose.material.Icon
1614
import androidx.compose.material.MaterialTheme
1715
import androidx.compose.material.Surface
1816
import androidx.compose.runtime.Composable
@@ -26,21 +24,17 @@ import androidx.compose.ui.Alignment
2624
import androidx.compose.ui.Modifier
2725
import androidx.compose.ui.focus.FocusRequester
2826
import androidx.compose.ui.focus.focusRequester
29-
import androidx.compose.ui.graphics.Color
3027
import androidx.compose.ui.platform.LocalFocusManager
3128
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
32-
import androidx.compose.ui.res.painterResource
3329
import androidx.compose.ui.semantics.semantics
3430
import androidx.compose.ui.semantics.testTag
3531
import androidx.compose.ui.text.input.ImeAction
3632
import androidx.compose.ui.text.style.TextAlign
3733
import androidx.compose.ui.tooling.preview.Preview
3834
import androidx.compose.ui.unit.dp
3935
import com.stripe.android.link.theme.DefaultLinkTheme
40-
import com.stripe.android.link.ui.LinkLogoStyle
4136
import com.stripe.android.link.ui.LinkTerms
4237
import com.stripe.android.link.ui.LinkTermsType
43-
import com.stripe.android.link.ui.logoRes
4438
import com.stripe.android.link.ui.signup.SignUpState
4539
import com.stripe.android.model.LinkBrand
4640
import com.stripe.android.ui.core.CircularProgressIndicator
@@ -50,9 +44,7 @@ import com.stripe.android.uicore.elements.PhoneNumberController
5044
import com.stripe.android.uicore.elements.SectionController
5145
import com.stripe.android.uicore.elements.TextField
5246
import com.stripe.android.uicore.elements.TextFieldController
53-
import com.stripe.android.uicore.shouldUseDarkDynamicColor
5447
import com.stripe.android.uicore.strings.resolve
55-
import com.stripe.android.uicore.stripeColors
5648
import com.stripe.android.uicore.utils.collectAsState
5749
import kotlinx.coroutines.job
5850

@@ -148,7 +140,6 @@ internal fun LinkOptionalInlineSignup(
148140
isShowingPhoneFirst = isShowingPhoneFirst,
149141
requiresNameCollection = requiresNameCollection,
150142
allowsDefaultOptIn = false,
151-
linkBrand = linkBrand,
152143
errorMessage = errorMessage,
153144
emailFocusRequester = emailFocusRequester,
154145
phoneFocusRequester = phoneFocusRequester,
@@ -220,27 +211,6 @@ internal fun EmailCollection(
220211
}
221212
}
222213

223-
@Composable
224-
internal fun LinkLogo(
225-
modifier: Modifier = Modifier,
226-
linkBrand: LinkBrand,
227-
) {
228-
Icon(
229-
painter = painterResource(
230-
id = if (MaterialTheme.stripeColors.component.shouldUseDarkDynamicColor()) {
231-
linkBrand.logoRes(LinkLogoStyle.TermsKnockoutBlack)
232-
} else {
233-
linkBrand.logoRes(LinkLogoStyle.TermsKnockoutWhite)
234-
}
235-
),
236-
contentDescription = linkBrand.brandName(),
237-
modifier = modifier
238-
.semantics { testTag = "LinkLogoIcon" }
239-
.height(16.dp),
240-
tint = Color.Unspecified,
241-
)
242-
}
243-
244214
@Preview
245215
@Composable
246216
private fun PreviewInitial() {

paymentsheet/src/test/java/com/stripe/android/link/ui/inline/LinkInlineSignupViewTest.kt

Lines changed: 5 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.stripe.android.link.ui.inline
22

3-
import androidx.compose.ui.test.assertContentDescriptionContains
43
import androidx.compose.ui.test.assertIsEnabled
54
import androidx.compose.ui.test.junit4.createComposeRule
65
import androidx.compose.ui.test.onNodeWithContentDescription
@@ -117,24 +116,6 @@ internal class LinkInlineSignupViewTest {
117116
composeTestRule.onNodeWithText(errorMessage).assertExists()
118117
}
119118

120-
@Test
121-
fun when_expanded_inline_logo_visible() {
122-
setContent(
123-
expanded = true,
124-
linkBrand = LinkBrand.Link,
125-
)
126-
onInlineLinkLogo().assertExists()
127-
}
128-
129-
@Test
130-
fun when_not_expanded_inline_logo_not_visible() {
131-
setContent(
132-
expanded = false,
133-
linkBrand = LinkBrand.Link,
134-
)
135-
onInlineLinkLogo().assertDoesNotExist()
136-
}
137-
138119
@Test
139120
fun checkbox_label_uses_link_brand_name_for_default_opt_in() {
140121
setContent(
@@ -162,13 +143,16 @@ internal class LinkInlineSignupViewTest {
162143
}
163144

164145
@Test
165-
fun inline_logo_content_description_uses_dynamic_brand_name() {
146+
fun terms_logo_content_description_uses_dynamic_brand_name() {
166147
setContent(
167148
expanded = true,
149+
signUpState = SignUpState.InputtingRemainingFields,
168150
linkBrand = LinkBrand.Onelink,
169151
)
170152

171-
onInlineLinkLogo().assertContentDescriptionContains("Onelink")
153+
composeTestRule
154+
.onNodeWithContentDescription("Onelink", useUnmergedTree = true)
155+
.assertExists()
172156
}
173157

174158
@Test
@@ -238,5 +222,4 @@ internal class LinkInlineSignupViewTest {
238222
private fun onPhoneField() = composeTestRule.onNodeWithText("Phone number")
239223
private fun onNameField() = composeTestRule.onNodeWithText("Full name")
240224
private fun onSaveMyInfo() = composeTestRule.onNodeWithText("Save my info", substring = true)
241-
private fun onInlineLinkLogo() = composeTestRule.onNodeWithTag("LinkLogoIcon", useUnmergedTree = true)
242225
}

0 commit comments

Comments
 (0)