Skip to main content

Theming the SDK screens

The ui module ships ready-made screens — currently the Wearing Optimization flow. They are drawn with the SDK's own palette so they stay readable inside any host app, and every colour and style they use can be replaced by your app.

implementation "com.corsano.sdk:ui:$corsanoSdkVersion"

Re-skinning the flow takes no code inside the screens: pin the palette if you need to, then redeclare the resources you want to change.

Light and dark mode

The SDK ships two palettes, light and dark. Which one applies is decided by the system UI mode, exactly like any Android resource — not by your app's theme.

Warning: An app that only has a light theme, but does not opt out of night mode, still gets the dark SDK palette as soon as the phone is switched to dark mode. This is the usual cause of unreadable SDK screens.

There are two ways to opt out. App-wide:

AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)

Or, if your app cannot or does not want to change its own night-mode handling, for the SDK screens only:

CorsanoUiTheme.nightMode = CorsanoUiTheme.NightMode.LIGHT

Both are supported. CorsanoUiTheme.nightMode affects only the SDK screens and their dialogs, and leaves the rest of your app alone.

CorsanoUiTheme

object CorsanoUiTheme — the theming entry point.

MemberTypeDescription
nightModeNightModeWhich palette the SDK screens use. Defaults to FOLLOW_SYSTEM
wrap(context)ContextReturns a context resolving resources with the UI mode forced to nightMode
wrap(inflater)LayoutInflaterThe same, applied to a LayoutInflater
enum class NightMode {
FOLLOW_SYSTEM, // default: follow the system dark mode setting
LIGHT, // always the light palette
DARK // always the dark palette
}

Set it once, before any SDK screen is openedApplication.onCreate() is the natural place:

class MyApp : Application() {
override fun onCreate() {
super.onCreate()
CorsanoSdk.initialize(this, config)
// The SDK screens stay light even when the phone is switched to dark mode.
CorsanoUiTheme.nightMode = CorsanoUiTheme.NightMode.LIGHT
}
}

Note: wrap() is only needed if you host SDK views yourself. The shipped screens call it internally. When nightMode is FOLLOW_SYSTEM, wrap() returns the context unchanged.

Colours

Declaring a colour with the same name in your app module replaces the SDK one, throughout the whole flow. Put it in any file under res/values/ — the file name does not matter, only the resource names do. Add a res/values-night/ variant too if your app supports dark mode.

ResourceUsed for
colorAppBarMain accent: filled buttons, progress bar, image borders, links
colorAppBarTextText drawn on colorAppBar (filled buttons)
mainBackgroundBackground of the screens
main_background_opacity_12Cards and other raised blocks, disabled button background
text_high_emphasisTitles, values, icons
text_medium_emphasisDescriptions
text_disable_emphasisDisabled text
errorError state: mandatory field not filled, wrong wearing instruction
colorGreenOk / wearing_opt_instruction_ok_colorCorrect wearing instruction
menuArrowChevron of the selectable rows
skin_type_fitzpatrick_1_6Skin-type picker swatches

Warning: mainBackground and the text_* colours are a set. Overriding one without the others can leave text unreadable — for example dark text on a dark background.

Styles

Same principle: redeclaring a style with the same name in your app module replaces the SDK one.

StyleUsed for
ConfirmButtonPrimary button (Next, Confirm)
SecondaryButtonSecondary button (Back)
TextLinkButtonInline link-like button
ProgressBarThemeHorizontal progress bar of the flow
RoundedImageCorner shape of the illustrations
TextAdaptableAuto-sizing labels of the selectable rows

Warning: An overriding style replaces the SDK one entirely — it does not merge. Repeat every item you want to keep.

The buttons take their enabled and disabled colours from the colour state lists confirm_button_background_tint, confirm_button_text and secondary_button_text, which are themselves built from the palette above. Overriding colorAppBar, colorAppBarText and text_disable_emphasis is usually enough, without touching the styles at all.

Worked example: a light-only app

An app with a single light theme that wants the SDK flow in its own brand colours. Two steps.

1. Pin the palette, once, before any SDK screen is opened:

class MyApp : Application() {
override fun onCreate() {
super.onCreate()
CorsanoSdk.initialize(this, config)
CorsanoUiTheme.nightMode = CorsanoUiTheme.NightMode.LIGHT
}
}

2. Override the palette in your app module:

<!-- app/src/main/res/values/colors_corsano_sdk.xml -->
<resources>
<!-- Accent: filled buttons, progress bar, links, image borders -->
<color name="colorAppBar">#0B4F6C</color>
<color name="colorAppBarText">#FFFFFF</color>

<!-- Surfaces and text, to keep as one consistent set -->
<color name="mainBackground">#FFFFFF</color>
<color name="main_background_opacity_12">#14000000</color>
<color name="text_high_emphasis">#DE000000</color>
<color name="text_medium_emphasis">#99000000</color>
<color name="text_disable_emphasis">#61000000</color>

<!-- States -->
<color name="error">#C62828</color>
<color name="colorGreenOk">#2E7D32</color>
</resources>

That covers the whole flow: buttons, progress bar, cards, titles, descriptions, the red highlight of a missing wrist or skin type, and the wearing instructions all follow from these.

Because night mode is pinned to LIGHT, a values-night/ variant is not needed. Add one only if the app later supports dark mode and switches back to FOLLOW_SYSTEM.

Changing the button shape

<!-- app/src/main/res/values/styles_corsano_sdk.xml -->
<resources>
<style name="ConfirmButton" parent="Widget.MaterialComponents.Button">
<item name="android:textAllCaps">false</item>
<item name="android:textSize">15sp</item>
<item name="android:minHeight">48dp</item>
<item name="cornerRadius">24dp</item> <!-- pill shaped -->
<item name="backgroundTint">@color/confirm_button_background_tint</item>
<item name="android:textColor">@color/confirm_button_text</item>
</style>
</resources>

Warning: Keep backgroundTint and android:textColor pointing at the SDK colour state lists. They preserve the disabled state — the Next button on the confirm-setup page is disabled until wrist and skin type are filled in, and a flat colour there makes a disabled button look enabled.

Host app requirements

The SDK screens are hosted in your own activity, so your app theme still supplies the ripples, dialogs and text appearances. A Theme.MaterialComponents.* or Theme.Material3.* theme is expected.