Skip to content

Commit

Permalink
Add dark mode to FC
Browse files Browse the repository at this point in the history
  • Loading branch information
tillh-stripe committed Feb 6, 2025
1 parent 2095d93 commit 8d14428
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 28 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.stripe.android.financialconnections.example.settings

import com.stripe.android.core.utils.FeatureFlags
import com.stripe.android.financialconnections.example.data.model.LinkAccountSessionBody
import com.stripe.android.financialconnections.example.data.model.PaymentIntentBody

data class DynamicAppearanceSetting(
override val selectedOption: Boolean = false,
override val key: String = "financial_connections_dynamic_appearance",
) : Saveable<Boolean>, SingleChoiceSetting<Boolean>(
displayName = "Dynamic appearance",
options = listOf(
Option("On", true),
Option("Off", false),
),
selectedOption = selectedOption
) {
override fun lasRequest(
body: LinkAccountSessionBody,
): LinkAccountSessionBody = body

override fun paymentIntentRequest(
body: PaymentIntentBody,
): PaymentIntentBody = body

override fun valueUpdated(currentSettings: List<Setting<*>>, value: Boolean): List<Setting<*>> {
FeatureFlags.financialConnectionsDarkMode.setEnabled(value)
return replace(currentSettings, this.copy(selectedOption = value))
}

override fun convertToValue(value: String): Boolean = value.toBoolean()

override fun convertToString(value: Boolean): String = value.toString()
}
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ internal data class PlaygroundSettings(
ConfirmIntentSetting(),
NativeSetting(),
PermissionsSetting(),
DynamicAppearanceSetting(),
EmailSetting(),
CustomerIdSetting(),
StripeAccountIdSetting().takeIf { BuildConfig.TEST_ENVIRONMENT != "edge" },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import androidx.activity.OnBackPressedDispatcher
import androidx.activity.compose.LocalOnBackPressedDispatcherOwner
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.foundation.Image
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
Expand All @@ -29,6 +30,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.geometry.CornerRadius
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
Expand Down Expand Up @@ -193,6 +195,11 @@ private fun Title(
Image(
modifier = Modifier.size(width = LOGO_WIDTH, height = LOGO_HEIGHT),
painter = painterResource(id = theme.icon),
colorFilter = if (isSystemInDarkTheme()) {
ColorFilter.tint(FinancialConnectionsTheme.colors.textDefault)
} else {
null
},
contentDescription = null // decorative element
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,30 +19,38 @@ import com.stripe.android.financialconnections.ui.theme.FinancialConnectionsThem

// Neutral
internal val Neutral0 = Color(0xFFFFFFFF)
internal val Neutral0Dark = Color(0xFF14171D)
internal val Neutral25 = Color(0xFFF5F6F8)
internal val Neutral25Dark = Color(0xFF1B1E25)
internal val Neutral50 = Color(0xFFF6F8FA)
internal val Neutral50Dark = Color(0xFF21252C)
internal val Neutral100 = Color(0xFFD8DEE4)
internal val Neutral100Dark = Color(0xFF2B3039)
internal val Neutral200 = Color(0xFFC0C8D2)
internal val Neutral600 = Color(0xFF596171)
internal val Neutral700 = Color(0xFF474E5A)
internal val Neutral800 = Color(0xFF353A44)
internal val Neutral800Dark = Color(0xFFC9CED8)
internal val Neutral900 = Color(0xff21252C)

// Attention
internal val Attention50 = Color(0xFFFEF9DA)
internal val Attention50Dark = Color(0xFF400A00)
internal val Attention300 = Color(0xFFF7870F)

// Feedback
internal val FeedbackCritical600 = Color(0xFFC0123C)

// Brand
internal val Brand25 = Color(0xFFF7F5FD)
internal val Brand25Dark = Color(0xFF1A1B2E)
internal val Brand400 = Color(0xff8D7FFA)
internal val Brand500 = Color(0xFF675DFF)
internal val Brand600 = Color(0xFF533AFD)

// Link
internal val LinkGreen50 = Color(0xFFE6FFED)
internal val LinkGreen50Dark = Color(0xFF16211F)
internal val LinkGreen200 = Color(0xFF00D66F)
internal val LinkGreen500 = Color(0xFF008545)
internal val LinkGreen900 = Color(0xFF011E0F)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import android.app.Activity
import android.content.Context
import android.content.ContextWrapper
import android.view.Window
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.text.selection.LocalTextSelectionColors
import androidx.compose.foundation.text.selection.TextSelectionColors
import androidx.compose.material.Colors
Expand All @@ -27,6 +28,7 @@ import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.DialogWindowProvider
import androidx.core.view.WindowCompat
import androidx.navigation.compose.rememberNavController
import com.stripe.android.core.utils.FeatureFlags
import com.stripe.android.financialconnections.R
import com.stripe.android.financialconnections.ui.LocalNavHostController
import com.stripe.android.uicore.R as StripeUiCoreR
Expand All @@ -36,9 +38,10 @@ internal enum class Theme {
LinkLight;

val colors: FinancialConnectionsColors
@Composable
get() = when (this) {
DefaultLight -> Colors
LinkLight -> InstantDebitsColors
DefaultLight -> if (useDarkMode) DarkThemeColors else Colors
LinkLight -> if (useDarkMode) InstantDebitsDarkModeColors else InstantDebitsColors
}

val icon: Int
Expand Down Expand Up @@ -75,6 +78,29 @@ private val Colors = FinancialConnectionsColors(
border = Brand600,
)

private val DarkThemeColors = FinancialConnectionsColors(
background = Neutral0Dark,
backgroundSecondary = Neutral25Dark,
backgroundHighlighted = Neutral50Dark,
textDefault = Neutral25,
textSubdued = Neutral800Dark,
textCritical = FeedbackCritical600,
icon = Neutral25,
borderNeutral = Neutral100Dark,
spinnerNeutral = Neutral200,
warningLight = Attention50Dark,
warning = Attention300,
primary = Brand500,
primaryAccent = Neutral0,
textAction = Brand500,
textFieldFocused = Brand600,
logo = Neutral0,
iconTint = Brand500,
iconBackground = Brand25Dark,
spinner = Brand500,
border = Brand600,
)

private val InstantDebitsColors = FinancialConnectionsColors(
background = Neutral0,
backgroundSecondary = Neutral25,
Expand All @@ -98,6 +124,29 @@ private val InstantDebitsColors = FinancialConnectionsColors(
border = LinkGreen200,
)

private val InstantDebitsDarkModeColors = FinancialConnectionsColors(
background = Neutral0Dark,
backgroundSecondary = Neutral25Dark,
backgroundHighlighted = Neutral50Dark,
textDefault = Neutral25,
textSubdued = Neutral800Dark,
textCritical = FeedbackCritical600,
icon = Neutral25,
borderNeutral = Neutral100Dark,
spinnerNeutral = Neutral200,
warningLight = Attention50Dark,
warning = Attention300,
primary = LinkGreen200,
primaryAccent = LinkGreen900,
textAction = LinkGreen200,
textFieldFocused = Brand600,
logo = Neutral0,
iconTint = LinkGreen500,
iconBackground = LinkGreen50Dark,
spinner = LinkGreen200,
border = LinkGreen200,
)

private val lineHeightStyle = LineHeightStyle(
alignment = LineHeightStyle.Alignment.Center,
trim = LineHeightStyle.Trim.None
Expand Down Expand Up @@ -218,11 +267,12 @@ internal fun FinancialConnectionsTheme(
val window = findWindow()
val barColor = FinancialConnectionsTheme.colors.borderNeutral
if (!view.isInEditMode) {
val lightNavBar = !useDarkMode
SideEffect {
window?.let { window ->
val insets = WindowCompat.getInsetsController(window, view)
window.navigationBarColor = barColor.toArgb()
insets.isAppearanceLightNavigationBars = true
insets.isAppearanceLightNavigationBars = lightNavBar
}
}
}
Expand All @@ -241,6 +291,10 @@ internal fun FinancialConnectionsTheme(
}
}

private val useDarkMode: Boolean
@Composable
get() = FeatureFlags.financialConnectionsDarkMode.isEnabled && isSystemInDarkTheme()

@Composable
private fun findWindow(): Window? =
(LocalView.current.parent as? DialogWindowProvider)?.window
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ object FeatureFlags {
val nativeLinkAttestationEnabled = FeatureFlag("Native Link Attestation")
val instantDebitsIncentives = FeatureFlag("Instant Bank Payments Incentives")
val enableDefaultPaymentMethods = FeatureFlag("Enable Default Payment Methods")
val financialConnectionsDarkMode = FeatureFlag("Financial Connections Dark Mode")
}

@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
Expand Down
48 changes: 23 additions & 25 deletions stripe-ui-core/res/drawable/stripe_link_logo_bw.xml
Original file line number Diff line number Diff line change
@@ -1,27 +1,25 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="72dp"
android:height="24dp"
android:viewportWidth="72"
android:viewportHeight="24">
<path
android:pathData="M36.12,3.677C36.12,2.549 37.07,1.632 38.189,1.632C39.307,1.632 40.258,2.554 40.258,3.677C40.258,4.8 39.341,5.746 38.189,5.746C37.037,5.746 36.12,4.829 36.12,3.677Z"
android:fillColor="#011E0F"/>
<path
android:pathData="M29.981,1.92H33.581V22.08H29.981V1.92Z"
android:fillColor="#011E0F"/>
<path
android:pathData="M40.008,7.68H36.379V22.08H40.008V7.68Z"
android:fillColor="#011E0F"/>
<path
android:pathData="M66.096,14.39C68.827,12.71 70.685,10.21 71.419,7.675H67.79C66.845,10.094 64.675,11.914 62.29,12.686V1.915H58.661V22.075H62.29V16.08C65.059,16.771 67.248,19.166 67.997,22.075H71.65C71.093,19.022 69.005,16.166 66.096,14.39Z"
android:fillColor="#011E0F"/>
<path
android:pathData="M46.44,9.293C47.39,8.03 49.243,7.296 50.746,7.296C53.549,7.296 55.867,9.346 55.872,12.442V22.075H52.243V13.243C52.243,11.971 51.677,10.502 49.838,10.502C47.678,10.502 46.435,12.418 46.435,14.659V22.085H42.806V7.69H46.44V9.293Z"
android:fillColor="#011E0F"/>
<path
android:pathData="M12,24C18.627,24 24,18.627 24,12C24,5.373 18.627,0 12,0C5.373,0 0,5.373 0,12C0,18.627 5.373,24 12,24Z"
android:fillColor="#011E0F"/>
<path
android:pathData="M11.448,4.8H7.747C8.467,7.81 10.569,10.382 13.2,12C10.565,13.618 8.467,16.19 7.747,19.2H11.448C12.365,16.416 14.904,13.997 18.024,13.502V10.493C14.899,10.003 12.36,7.584 11.448,4.8Z"
android:fillColor="#ffffff"/>
android:width="60dp"
android:height="20dp"
android:viewportWidth="60"
android:viewportHeight="20">
<path
android:pathData="M30.1,3.064C30.1,2.124 30.892,1.36 31.824,1.36C32.756,1.36 33.548,2.128 33.548,3.064C33.548,4 32.784,4.788 31.824,4.788C30.864,4.788 30.1,4.024 30.1,3.064Z"
android:fillColor="#011E0F"/>
<path
android:pathData="M24.984,1.6H27.984V18.4H24.984V1.6Z"
android:fillColor="#011E0F"/>
<path
android:pathData="M33.34,6.4H30.316V18.4H33.34V6.4Z"
android:fillColor="#011E0F"/>
<path
android:pathData="M55.08,11.992C57.356,10.592 58.904,8.508 59.516,6.396H56.492C55.704,8.412 53.896,9.928 51.908,10.572V1.596H48.884V18.396H51.908V13.4C54.216,13.976 56.04,15.972 56.664,18.396H59.708C59.244,15.852 57.504,13.472 55.08,11.992Z"
android:fillColor="#011E0F"/>
<path
android:pathData="M38.7,7.744C39.492,6.692 41.036,6.08 42.288,6.08C44.624,6.08 46.556,7.788 46.56,10.368V18.396H43.536V11.036C43.536,9.976 43.064,8.752 41.532,8.752C39.732,8.752 38.696,10.348 38.696,12.216V18.404H35.672V6.408H38.7V7.744Z"
android:fillColor="#011E0F"/>
<path
android:pathData="M20,10C20,15.523 15.523,20 10,20C4.477,20 0,15.523 0,10C0,4.477 4.477,0 10,0C15.523,0 20,4.477 20,10ZM6.456,4H9.54C10.3,6.32 12.416,8.336 15.02,8.744V11.252C12.42,11.664 10.304,13.68 9.54,16H6.456C7.056,13.492 8.804,11.348 11,10C8.808,8.652 7.056,6.508 6.456,4Z"
android:fillColor="#011E0F"
android:fillType="evenOdd"/>
</vector>

0 comments on commit 8d14428

Please sign in to comment.