MineSec Pay Application
White-label Integration
Theming & Branding

Theming & Branding

MSA Core ships with a complete design system but every part of it is overridable. You customize the look of your white-label app through a single entry point: a ThemeProvider class that you extend and pass into AppTheme.

This page covers:


Colors

Colors are defined by the MsaColors interface. The library provides MsaColorsLight and MsaColorsDark as defaults — override whichever properties you want to rebrand.

The MsaColors interface

interface MsaColors {
    val primary: Color
    val primaryForeground: Color
    val primaryGradient: Color
    val secondary: Color
    val secondaryForeground: Color
    val background: Color
    val foreground: Color
    val muted: Color
    val mutedForeground: Color
    val accent: Color
    val accentForeground: Color
    val approval: Color           // success / approved transaction
    val approvalForeground: Color
    val error: Color              // failed / declined transaction
    val errorForeground: Color
    val highlightCard: Color
    val input: Color              // text field borders and placeholders
    val ring: Color               // focus rings
    val statusYellow: Color       // warnings / pending states
    val processing: Color         // in-flight transactions
    val headerSurface: Color      // top bar background
    val headerForeground: Color   // top bar text/icons
}

Customizing the brand palette

Override MsaColorsLight (and optionally MsaColorsDark) with your brand colors:

@Immutable
data class MyBrandColorsLight(
    override val primary: Color = Color(0xFF0066CC),           // Your brand blue
    override val primaryForeground: Color = Color(0xFFFFFFFF),
    override val primaryGradient: Color = Color(0xFF3388DD),
    override val secondary: Color = Color(0xFF1A1A1A),
    override val secondaryForeground: Color = Color(0xFFFFFFFF),
    override val background: Color = Color(0xFFFFFFFF),
    override val foreground: Color = Color(0xFF0F172A),
    override val approval: Color = Color(0xFF10B981),
    override val approvalForeground: Color = Color(0xFFF0FDF4),
    override val error: Color = Color(0xFFEF4444),
    override val errorForeground: Color = Color(0xFFFEF2F2),
    override val headerSurface: Color = Color(0xFF0066CC),
    override val headerForeground: Color = Color(0xFFFFFFFF),
    // ...override remaining fields
) : MsaColors

Payment scheme colors

SchemeColors holds brand colors for payment networks (Visa, Mastercard, etc.). Override this only if your brand guidelines require non-standard scheme colors.

@Immutable
data class SchemeColors(
    val colorVisa: Color = Color(0xff1434CA),
    val colorMastercard: Color = Color(0xffF79E1B),
    val colorJcb: Color = Color(0xff40A737),
    val colorUnionpay: Color = Color(0xffE0002B),
    val colorAmex: Color = Color(0xff006FCF),
    val colorAlipay: Color = Color(0xff1677FF),
    val colorWechat: Color = Color(0xff09BB07),
    val colorFps: Color = Color(0xff56BBE9),
    val colorPayme: Color = Color(0xffDB0011),
    val colorOctopus: Color = Color(0xffF5911E),
    val colorCash: Color = Color(0xff00A590),
)

Typography

Typography uses Material3's Typography class. The library defaults to the Inter font family, but you can swap it out for any font shipped as a resource in your app.

Add your font files

Drop your font files under app/src/main/res/font/, for example:

app/src/main/res/font/
├── mybrand_regular.ttf
├── mybrand_medium.ttf
├── mybrand_semibold.ttf
└── mybrand_bold.ttf

Define the typography

fun myBrandTypography(): Typography {
    val brandFont = FontFamily(
        Font(R.font.mybrand_regular, FontWeight.Normal),
        Font(R.font.mybrand_medium, FontWeight.Medium),
        Font(R.font.mybrand_semibold, FontWeight.SemiBold),
        Font(R.font.mybrand_bold, FontWeight.Bold),
    )
 
    return Typography(
        bodySmall = TextStyle(fontFamily = brandFont, fontSize = 16.sp, fontWeight = FontWeight.Normal),
        bodyMedium = TextStyle(fontFamily = brandFont, fontSize = 16.sp, fontWeight = FontWeight.Medium),
        titleMedium = TextStyle(fontFamily = brandFont, fontSize = 20.sp, fontWeight = FontWeight.SemiBold),
        headlineSmall = TextStyle(fontFamily = brandFont, fontSize = 24.sp, fontWeight = FontWeight.SemiBold),
        // ...define other styles
    )
}
StyleTypical Use
labelSmall / labelMedium / labelLargeButtons, captions, tiny labels
bodySmall / bodyMedium / bodyLargeBody text, form inputs
titleSmall / titleMedium / titleLargeSection headers
headlineSmallScreen titles

Spacing, Icons, Radius, Touch Targets

MSA Core uses an adaptive sizing system — values scale based on window width (Compact / Medium / Expanded). You rarely need to override these, but you can.

The interfaces

interface Spacing {
    val xs3: Dp   // 2dp
    val xs2: Dp   // 4dp
    val xs: Dp    // 8dp
    val sm: Dp    // 12dp
    val md: Dp    // 16dp
    val lg: Dp    // 24dp
    val xl: Dp    // 32dp
    val xl2: Dp   // 48dp
    val xl3: Dp   // 64dp
    val xl4: Dp   // 80dp
    val xl5: Dp   // 96dp
}
 
interface IconSize {
    val xs2: Dp   // 12dp
    val xs: Dp    // 16dp
    val sm: Dp    // 20dp
    val md: Dp    // 24dp
    val lg: Dp    // 28dp
    val xl: Dp    // 36dp
    val xl2: Dp   // 48dp
    val xl3: Dp   // 64dp
}
 
interface Radius {
    val xs: Dp    // 2dp
    val sm: Dp    // 4dp
    val md: Dp    // 6dp
    val lg: Dp    // 8dp
    val xl: Dp    // 12dp
    val xl2: Dp   // 16dp
}
 
interface MinTouchSize {
    val sm: Dp    // 40dp
    val md: Dp    // 56dp
    val lg: Dp    // 60dp
    val xl: Dp    // 72dp
    val xl2: Dp   // 88dp
    val xl3: Dp   // 100dp
}

Adaptive scaling

Values automatically scale by 1.0× on Compact, 1.2× on Medium, and 1.4× on Expanded windows. If you want different scaling for your brand, override the provider methods in your ThemeProvider.

Accessing in your UI

Column(
    modifier = Modifier.padding(MsaTheme.spacing.md)
) {
    Icon(
        imageVector = Icons.Default.CheckCircle,
        modifier = Modifier.size(MsaTheme.iconSize.lg)
    )
}

Shapes

Shapes control rounded corners for surfaces (buttons, cards, text fields).

@Composable
fun myBrandShapes(): Shapes {
    return Shapes(
        extraSmall = RoundedCornerShape(2.dp),
        small = RoundedCornerShape(4.dp),
        medium = RoundedCornerShape(8.dp),
        large = RoundedCornerShape(12.dp),
        extraLarge = RoundedCornerShape(20.dp),
    )
}

Access in UI:

Box(
    modifier = Modifier
        .clip(MsaTheme.shapes.large)
        .background(MsaTheme.colors.primary)
)

Drawables & Images

MSA Core expects certain drawable resources to exist in your host app. To rebrand, drop your images into app/src/main/res/drawable/ using the same resource names.

Commonly customized drawables

Resource NamePurpose
ic_launcher / ic_launcher_roundApp icon on the launcher
fingerprint_icon_buttonBiometric login button
ic_bio_face_icon / ic_bio_loginBiometric enrollment dialog
ms_activation_qrQR scan icon on login
Your brand logoUsed in splash, landing, receipts

Wiring It All Together

Bundle your customizations into a single ThemeProvider. Override only the methods you care about — defaults are used otherwise.

1. Create your ThemeProvider

class MyBrandThemeProvider : ThemeProvider() {
 
    @ReadOnlyComposable
    override fun provideMsaColors(darkTheme: Boolean): MsaColors {
        return if (darkTheme) MyBrandColorsDark() else MyBrandColorsLight()
    }
 
    @ReadOnlyComposable
    override fun provideSchemeColors(): SchemeColors = SchemeColors(
        colorVisa = Color(0xff1434CA),
        // ...your overrides
    )
 
    @Composable
    override fun provideTypography(): Typography = myBrandTypography()
 
    @Composable
    override fun provideShapes(): Shapes = myBrandShapes()
 
    // Spacing, IconSize, Radius, MinTouchSize all have sensible adaptive defaults —
    // only override if you need custom sizing.
}

2. Apply it in your App entry point

Wrap App() with AppTheme and pass your provider:

class MainActivity : BaseMsaActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            AppTheme(themeProvider = MyBrandThemeProvider()) {
                App(screenProviders = providers)
            }
        }
    }
 
    override fun provideAdditionalKoinModules(): List<Module> {
        return listOf(provideNFCManager())
    }
}

3. Use the theme in your screens

From anywhere inside AppTheme, access tokens via the MsaTheme object:

Text(
    text = "Welcome",
    color = MsaTheme.colors.foreground,
    style = MsaTheme.typography.headlineSmall,
    modifier = Modifier.padding(MsaTheme.spacing.md)
)

Next Steps