The appearance of the SDK can be customized using the StorytellerTheme class. This class allows you to configure the visual appearance of all Storyteller content in your app.
Set the theme as early as possible in your application's lifecycle (for example, in your main() function after initializing the SDK).
It is also possible to apply a specific theme to an individual StorytellerListView instance or when opening content. For example:
finalrowTheme=StorytellerTheme(light:ThemeType(colors:ThemeColors(primary:'#FF0000'),),);// Apply to a list viewStorytellerStoriesRowView(categories:['news'],theme:rowTheme,);// Apply when opening a collectionawaitStoryteller.openCollection('collection-id',theme:rowTheme,);
For more information on setting a theme on an individual list, see StorytellerListViews.
The theme override on a direct collection open applies on iOS. The current
Android Flutter bridge ignores that argument; set a global theme with
Storyteller.setTheme for this Android path. Per-widget list themes are separate.
See Additional Methods for presentation-specific limits.
The Showcase ThemeManager.buildTheme clones the selected preset and adjusts tile typography or singleton layouts on the fly—use it as guidance when composing dynamic StorytellerTheme objects.
A StorytellerTheme consists of the following properties:
light - sets the ThemeType to apply for light mode.
dark - sets the ThemeType to apply for dark mode.
The native SDK selects the variant from the device appearance. Flutter's
ThemeData does not configure these native views. A supplied light variant
is not copied into dark; define both variants when your brand colors
must apply in both modes. Omitted fields are excluded from the Dart map and
resolved from native defaults, inheritance, and applicable tenant themes.
Calling setTheme sends a new theme configuration; include all overrides
you intend to retain rather than treating it as a patch to a previous theme.
The expanded Cards, player-icon, Clips, and Search mappings on this page are
available in Flutter 11.6.4 and later. Flutter 12.1.2 adds
Sheets, multi-stop gradients, the
modal Clips layout, clips.embeddedVideoSizing,
rectangularTile.titleGradient, and the Instructions button textSize and
lineHeight. Native properties not exported by
these Dart theme classes cannot be set through Flutter, even when they exist
in a newer native reference. Android core requires API 24 or later; the iOS
core supports iOS 13 or later, while your app or optional ads integration may
require a higher deployment target; see Getting Started.
The ThemeType object exposes the Flutter theme sections shown below.
Table defaults describe resolved native behavior, not Dart constructor values;
most Dart properties default to null and are omitted from toMap(). Layout
values use native logical units (Android dp/sp and iOS points); Android maps
numeric dimensions to integers, so fractional values can be truncated.
Some properties take their default value from others. For example, setting the primary color to #FF0000 will also result in the New Indicator for Rectangular Tiles being colored red. Such properties are indicated in the tables below.
Note that theme properties may be used for other situations in future.
The colors property on theme is used to establish a set of base colors for the SDK to use.
Property
Default Value
Data Type
Description
primary
#1C62EB
String
The default accent color used throughout the UI. In general, this should be the primary brand color. Color strings should be in hex format (e.g., #1C62EB).
success
#3BB327
String
Used to indicate correct answers in Quizzes.
alert
#E21219
String
Used to indicate incorrect answers in Quizzes.
white.primary
#FFFFFF
String
Used for white text
white.secondary
white.primary at 85% opacity
String
Used for light text
white.tertiary
white.primary at 70% opacity
String
Used for gray text
black.primary
#1A1A1A
String
Used for black text
black.secondary
black.primary at 85% opacity
String
Used for light black text
black.tertiary
black.primary at 70% opacity
String
Used for gray text
Use #RRGGBB for opaque colors and #AARRGGBB for alpha colors. For
example, #80FFFFFF is translucent white on both platforms.
Use the customFont property to set a custom font for use throughout the UI.
Create a ThemeCustomFont with the Flutter asset path for each weight. The
light path is optional for source compatibility; all other paths are required.
Package every referenced font in your app's pubspec.yaml. You can register
all weights under one Flutter font family; the native theme still uses the
individual asset paths rather than the Flutter family name:
On iOS, all six required font files must resolve and register successfully for
the custom font provider to apply. If the optional light file is omitted or
unavailable, iOS falls back to the regular font for that weight. Theme images
also use Flutter asset paths: declare their files under flutter.assets and
pass them using ThemeImage(filePath: ...). Native Lottie resources use the
separate packaging described under Player.
Required for outline on Live chip and fade to the side of the row
enablePlayerOpen
true
bool
Controls whether the SDK opens the player when a tile is tapped. When set to false, the SDK will not open the player and the app must handle tile taps via the onTileTapped callback.
animateTilesOnReorder
true
bool
When the reloadData() method is called to update lists, a reorder animation is added to visualize the updating process.
row.tileSpacing
8
double
The space between each Tile in a row
row.startInset
12
double
The space before the first Tile in a row
row.endInset
12
double
The space after the last Tile in a row
grid.tileSpacing
8
double
The space between each Tile in a grid, both vertically and horizontally
grid.columns
2
int
The number of columns in a grid.
grid.topInset
0
double
The space before the first row in a grid
grid.bottomInset
0
double
The space after the last row in a grid
title.font
null
ThemeCustomFont
Defines the font of the Title in Section
title.textSize
22
double
Size of the Title in Section
title.lineHeight
28
double
The line height of the Title in Section
title.textCase
default
String
Sets the text case for the Title in Section. Possible values are upper, lower and default
The ThemeGradient class allows for the creation of a color gradient, with options to customize both the colors and the positions at which the gradient starts and ends.
Property
Default Value
Data Type
Description
startColor
required
String
The color where the gradient begins (hex format).
endColor
required
String
The color where the gradient ends (hex format).
startPosition
required
int
The position indicating where the gradient starts (0-8).
endPosition
required
int
The position indicating where the gradient ends (0-8).
stops
null
List<ThemeGradientStop>
Ordered color stops for a gradient with more than two colors. If set, overrides startColor and endColor. See Multi-stop gradients.
ThemeGradient.withStops creates a gradient from two or more
ThemeGradientStop values. It sets startColor and endColor from the first
and last stops.
Property
Default Value
Data Type
Description
color
required
String
Stop color as #RRGGBB or #AARRGGBB
location
required
double
Position along the gradient, from 0 to 1
The constructors throw an ArgumentError for fewer than two stops, a location
outside 0 to 1, or locations that decrease. If the native SDK can't use a stop list, for example because
a stop color is invalid, it draws the two-color gradient from startColor and
endColor instead.
Flutter colors put alpha first (#AARRGGBB), while the Storyteller CMS puts it
last (#RRGGBBAA). Reorder the digits when you copy a transparent color from
the CMS.
Example:
ThemeGradient.withStops(stops:[ThemeGradientStop(color:'#00000000',location:0),ThemeGradientStop(color:'#66000000',location:0.6),ThemeGradientStop(color:'#CC000000',location:1),],startPosition:7,// Top centerendPosition:1,// Bottom center)
The tiles property can be used to customize the appearance of the Tiles.
Property
Default Value
Data Type
Description
chip.textSize
11
double
Text size for the New Indicator and Live Indicator.
chip.show
true
bool
Used to show/hide the new/live chip
title.textSize
11
double
Size of the Title on a Tile
title.lineHeight
13
double
The line height of the Title on a Tile
title.alignment
center
String
The alignment of the Title on a Tile. Possible values are left, center and right
circularTile.title.unreadTextColor
inherits colors.black.primary for light, colors.white.primary for dark
String
The text color of the Title for a circular tile when the story or the clip is unread
circularTile.title.readTextColor
inherits colors.black.tertiary for light, colors.white.tertiary for dark
String
The text color of the Tile for a circular tile when the story or the clip is read
circularTile.unreadIndicatorColor
inherits colors.primary
String
The color of the ring around a circular tile when the story or the clip is unread
circularTile.readIndicatorColor
#C1C1C1 (Android), #C5C5C5 (iOS)
String
The color of the ring around a circular tile when the story or the clip is read
circularTile.unreadIndicatorGradient
null
ThemeGradient
The gradient of the ring around a circular tile when the story or the clip is unread. If set, overrides circularTile.unreadIndicatorColor
circularTile.unreadIndicatorBorderColor
null
String
The border color of the ring around a circular tile when the story or the clip is unread
circularTile.readIndicatorBorderColor
null
String
The border color of the ring around a circular tile when the story or the clip is read
circularTile.unreadBorderWidth
2
double
The width of Circular Tile ring border in unread state
circularTile.readBorderWidth
1
double
The width of Circular Tile ring border in read state
circularTile.liveChip.readImage
null
ThemeImage
Image to be used in place of default read Live Indicator.
circularTile.liveChip.unreadImage
null
ThemeImage
Image to be used in place of default unread Live Indicator
circularTile.liveChip.unreadBackgroundColor
colors.alert
String
Background color of the Live Indicator when the story contains unread pages or the clip has not been viewed.
circularTile.liveChip.readBackgroundColor
colors.black.tertiary
String
Background color of the Live Indicator when all story pages have been read or the clip has been viewed.
circularTile.liveChip.unreadBackgroundGradient
null
ThemeGradient
The gradient of the ring around a live tile and background of the Live Indicator. If set, overrides circularTile.liveChip.unreadBackgroundColor
circularTile.liveChip.unreadTextColor
colors.white.primary
String
Text color of the Live Indicator when the story contains unread pages or the clip has not been viewed.
circularTile.liveChip.readTextColor
colors.white.primary
String
Text color of the Live Indicator when all story pages have been read or the clip has been viewed.
circularTile.liveChip.unreadBorderColor
null
String
Border color of the Live Indicator when the story contains unread pages or the clip has not been viewed.
circularTile.liveChip.readBorderColor
null
String
Border color of the Live Indicator when all story pages have been read or the clip has been viewed.
rectangularTile.padding
8
double
The internal padding for a rectangular story or the clip tile
rectangularTile.title.textColor
inherits colors.white.primary
String
The text color of the Title for a rectangular tile
rectangularTile.titleGradient
native default
ThemeGradient
Readability gradient behind the Title of a rectangular tile. If set, replaces the native title scrim
rectangularTile.chip.alignment
right
String
The alignment of the New Indicator and Live Indicator in Rectangular Tiles. Possible values are left, center or right
rectangularTile.unreadIndicator.image
null
ThemeImage
An image which can be used in place of the default unread indicator for a rectangular tile. If set, overrides rectangularTile.unreadIndicator.gradient
rectangularTile.unreadIndicator.gradient
null
ThemeGradient
iOS-only gradient for the rectangular unread indicator; Android ignores this Dart field. If set on iOS, overrides rectangularTile.unreadIndicator.backgroundColor
rectangularTile.unreadIndicator.backgroundColor
inherits colors.primary
String
The background color of the unread indicator for a rectangular tile
rectangularTile.unreadIndicator.textColor
inherits colors.white.primary
String
The text color of the unread indicator for a rectangular tile
rectangularTile.unreadIndicator.borderColor
null
String
Border color of the unread indicator for a rectangular tile
rectangularTile.liveChip.readImage
null
ThemeImage
Image to be used in place of default read Live Indicator.
rectangularTile.liveChip.unreadImage
null
ThemeImage
Image to be used in place of default unread Live Indicator. If set, overrides rectangularTile.liveChip.unreadBackgroundGradient
rectangularTile.liveChip.unreadBackgroundGradient
null
ThemeGradient
Gradient background to be used for the Live Indicator. If set, overrides rectangularTile.liveChip.unreadBackgroundColor
rectangularTile.liveChip.unreadBackgroundColor
colors.alert
String
Background color of the Live Indicator when the story contains unread pages or the clip has not been viewed.
rectangularTile.liveChip.readBackgroundColor
colors.black.tertiary
String
Background color of the Live Indicator when all pages have been read or the clip has been viewed
rectangularTile.liveChip.unreadTextColor
colors.white.primary
String
Text color of the Live Indicator when the story contains unread pages or the clip has not been viewed.
rectangularTile.liveChip.readTextColor
colors.white.primary
String
Text color of the Live Indicator when all story pages have been read or the clip has been viewed.
rectangularTile.liveChip.unreadBorderColor
null
String
Border color of the Live Indicator when the story contains unread pages or the clip has not been viewed.
rectangularTile.liveChip.readBorderColor
null
String
Border color of the Live Indicator when all story pages have been read or the clip has been viewed.
The player property is used to customize properties relating to the Story and Clips Player.
Property
Default Value
Data Type
Description
showStoryIcon
false
bool
Shows the round story icon before the Story Title in the Player
showTimestamp
true
bool
Shows the timestamp after the Story Title in the Player, indicating how long ago a story was published
showShareButton
true
bool
Shows the share button in the Player. Setting this to false entirely disables sharing in Storyteller
showLikeButton
true
bool
Shows the like button in the Clips Player. Setting this to false entirely disables liking in Storyteller
showMoreButton
native default
bool
Android-only visibility control for the Clips more button; iOS ignores it
enableFollowableCategorySwipeFromRightEdge
native default
bool
Enables or disables the right-edge swipe that opens a followable category
liveChip.image
null
ThemeImage
Image used in place of Live Chip before Live Story or Clip Titles. If set, it overrides liveChip.backgroundGradient
liveChip.textColor
inherits colors.white.primary
String
Text color used for badge label for Live Story or Clip
liveChip.backgroundGradient
null
ThemeGradient
Background gradient of the badge for Live Story or Clip. If set, it overrides liveChip.backgroundColor
liveChip.backgroundColor
theme.colors.alert
String
Background color of the badge for Live Story or Clip
liveChip.borderColor
null
String
Border color of the badge for Live Story or Clip
icons.share
null
ThemeImage
An image to be used in place of the default share icon
icons.refresh
null
ThemeImage
Refresh button image to be used in place of refresh share icon, used in the error state
icons.back
null
ThemeImage
Back button image used by the native player
icons.close
null
ThemeImage
Android-only close button image; iOS ignores it
icons.more
null
ThemeImage
Android-only more button image; iOS ignores it
icons.likeInitial
null
ThemeImage
An image to be used in place of the default like icon when the clip is not liked
icons.likeLiked
null
ThemeImage
An image to be used in place of the default like icon when the clip is liked
icons.likeAnimation.liked
null
ThemeLottieAnimationResource
Lottie animation used when a clip changes to liked
icons.likeAnimation.unliked
null
ThemeLottieAnimationResource
Lottie animation used when a clip changes to unliked
icons.mute.muted
null
ThemeImage
Mute button image for the muted state
icons.mute.unmuted
null
ThemeImage
Mute button image for the unmuted state
icons.captions.enabled
null
ThemeImage
Captions button image for the enabled state
icons.captions.disabled
null
ThemeImage
Captions button image for the disabled state
clips.showButtonBackgrounds
native default
bool
Controls native action-button backgrounds in the Clips Player
clips.actionIconSize
native default
double
Requested Clips action-icon size; the native SDK applies its supported size rules
clips.eyebrow.*
native defaults
ThemePlayerClipsEyebrow
Font, text size, line height, and color for the Clips eyebrow
clips.title.*
native defaults
ThemePlayerClipsTitle
Font, weight, text size, line height, and color for the Clips title
clips.feedSwitcher.selected.*
native defaults
ThemePlayerClipsFeedSwitcherState
Weight, text size, and line height for the selected Following-feed label
clips.feedSwitcher.unselected.*
native defaults
ThemePlayerClipsFeedSwitcherState
Weight, text size, and line height for an unselected Following-feed label
clips.categoryNavigation.*
native defaults
ThemePlayerClipsCategoryNavigation
Weight, text size, and line height for category-navigation labels
clips.topGradient
native default
ThemeGradient
Readability gradient at the top of the Clips Player
clips.bottomGradient
native default
ThemeGradient
Readability gradient at the bottom of the Clips Player
clips.embeddedVideoSizing
Storyteller CMS setting
String
Video sizing in Embedded Clips: legacy keeps the existing layout; widthConstrained fits the video to the available width, keeps its aspect ratio, and centers any vertical overflow. If set, overrides the CMS setting. Modal Clips are not affected
clips.modal.*
null
ThemePlayerClipsModal
Layout overrides for full-screen Clips; see Modal Clips layout. When unset, the existing modal layout is kept
clips.progressBar.position
native default
String
bottom or aboveAction; native layout remains authoritative
clips.progressBar.playedColor
native default
String
Played-track color
clips.progressBar.remainingColor
native default
String
Remaining-track color
clips.progressBar.active.*
native defaults
ThemePlayerClipsProgressBarActive
Played, remaining, current-time, and total-time colors while scrubbing
clips.spacing.*
native defaults
ThemePlayerClipsSpacing
Insets and gaps: backButtonStartInset, contentInsetHorizontal, contentInsetBottom, actionSpacing, eyebrowToTitleSpacing, titleToActionSpacing, titleToCategoriesSpacing, categoriesToMoreSpacing, metadataToProgressBarSpacing, and progressBarToActionSpacing
On Android, add each Lottie JSON file to android/app/src/main/res/raw and
provide its filename without .json in androidRawResourceName (or name as
a fallback). On iOS, add the JSON file to the app target's Copy Bundle
Resources phase and provide its bundled resource name in name. Use
iosBundlePath when the resource belongs to a bundle other than the main app
bundle.
ThemePlayerClips.modal takes a ThemePlayerClipsModal, which overrides the
layout of full-screen (modal) Clips. It doesn't affect Embedded Clips. Leave
it unset to keep the existing modal layout. On Android, any valid value that
differs from the default switches to the configurable modal layout; defaults and
values Android rejects don't. Set modal only when you want to change it.
Property
Default Value
Data Type
Description
drawBehindStatusBar
false
bool
Extends the video behind the status bar; controls stay in the safe area
feedSwitcherItemSpacing
native default
double
Total horizontal gap between the For You and Following labels
titleToCategoriesSpacing
native default
double
Gap between the title or description and the category labels
categoriesToMoreSpacing
native default
double
Gap between the category labels and the more/less control
metadataToProgressBarSpacing
native default
double
Gap between the metadata and the resting progress track
progressBarToActionSpacing
native default
double
Minimum gap between the progress track and the primary action
progressBarPosition
native default
String
bottom or aboveAction. aboveAction falls back to bottom when the Clip has no call to action
topGradientHeight
native default
double
Height of the top readability gradient, including any status-bar area behind the video
bottomGradientHeight
native default
double
Height of the bottom readability gradient
progressBarHeight
native default
double
Height of the resting progress track
progressBarActiveHeight
native default
double
Height of the progress track while scrubbing; the drag target stays at least 48 high
progressBarInsetHorizontal
native default
double
Horizontal inset of the progress track from the video edges
navigationIconSize
native default
double
Size of the Back and Search icons; their tap targets stay at least 48
navigationInsetHorizontal
native default
double
Horizontal inset of the Back and Search buttons from the safe edges
navigationInsetTop
native default
double
Additional top inset for navigation below the status bar
navigationHeight
native default
double
Height of the navigation row. Android uses at least 48
searchIcon
null
ThemeImage
Replaces the built-in Search icon
Spacing, inset and gradient-height values must be zero or more, and sizes must
be greater than zero. Android ignores values outside these ranges.
Use the instructions property to customize the appearance of the instructions screen.
Property
Default Value
Data Type
Description
show
true
bool
Determines whether the Instructions Screen is shown the first time a user opens the Story Player. Set to false to completely disable the instructions screen.
headingColor
inherits colors.black.primary for light, colors.white.primary for dark
String
The color of the heading text on the Instructions Screen
headingTextCase
default
String
Determines the text case of the heading on the Instructions Screen. Possible values are upper, lower and default
headingFont
inherits global custom font
ThemeCustomFont
Defines the font of the heading text on the Instructions Screen
subHeadingColor
inherits colors.black.secondary for light, colors.white.secondary for dark
String
The color of the subheading text on the Instructions Screen
backgroundColor
inherits colors.white.primary for light, colors.black.primary for dark
String
The color of the background of the Instructions Screen
icons
null
ThemeInstructionIcons
Custom instruction images on Android and iOS
button.backgroundColor
inherits colors.black.primary for light, colors.white.primary for dark
String
The background color of the button used on the Instructions Screen
button.textColor
inherits colors.white.primary for light, colors.black.primary for dark
String
The text color of the button used on the Instructions Screen
button.textSize
16
double
Android-only text size of the button label on the Clips Instructions Screen; iOS ignores it
button.lineHeight
21
double
Android-only line height of the button label on the Clips Instructions Screen; iOS ignores it
The icons property replaces the instruction images on Android and iOS. The icons should be 48x48 PNGs or appropriate asset images. An example of using this property is shown below:
Search filter availability (Sort, Date, and Content Type) is controlled
by the tenant's native Search settings. Local Flutter themes change appearance,
not which filters are enabled. The Following-feed selection mechanism, modal
Clips bottom anchoring, followable-category profile content, and remote theme
precedence are also resolved by native/tenant configuration. Omitted Flutter
theme fields continue to inherit those native values.
Start with an obvious accent color, supply both light and dark variants, and
open a published Story/Clip from the placement you styled. Test both device
appearances and the relevant list/player/Search screen: a Clips-only property
does not restyle Stories, and a per-list theme can override the global theme
for that placement. Set the global theme before mounting content.
If a value appears unchanged, check its applicable surface and platform,
the placement's own theme, and any tenant or collection remote overrides.
Native/tenant settings can override supported host values. Confirm that icon
and font assets are packaged and paths match their case; missing iOS font
weights prevent the provider from applying. Reopening content is a useful
check after changing appearance or resources; rebuilding is required after
changing native resource packaging. Continue with
Storyteller List Views, Search, or
Troubleshooting for the surface you are integrating.
{"slug": "themes", "page_title": "Themes", "page_url": "Themes/", "canonical_url": "/flutter/Themes/", "markdown": "# Themes\n\nThe appearance of the SDK can be customized using the `StorytellerTheme` class. This class allows you to configure the visual appearance of all Storyteller content in your app.\n\n```dart\nfinal theme = StorytellerTheme(\n light: ThemeType(\n colors: ThemeColors(primary: '#1C62EB'),\n ),\n);\n\nawait Storyteller.setTheme(theme);\n```\n\nSet the theme as early as possible in your application's lifecycle (for example, in your `main()` function after initializing the SDK).\n\nIt is also possible to apply a specific theme to an individual [StorytellerListView](StorytellerListViews.md) instance or when opening content. For example:\n\n```dart\nfinal rowTheme = StorytellerTheme(\n light: ThemeType(\n colors: ThemeColors(primary: '#FF0000'),\n ),\n);\n\n// Apply to a list view\nStorytellerStoriesRowView(\n categories: ['news'],\n theme: rowTheme,\n);\n\n// Apply when opening a collection\nawait Storyteller.openCollection(\n 'collection-id',\n theme: rowTheme,\n);\n```\n\n> For more information on setting a theme on an individual list, see [StorytellerListViews](StorytellerListViews.md).\n\nThe `theme` override on a direct collection open applies on iOS. The current\nAndroid Flutter bridge ignores that argument; set a global theme with\n`Storyteller.setTheme` for this Android path. Per-widget list themes are separate.\nSee [Additional Methods](AdditionalMethods.md) for presentation-specific limits.\n\nThe Showcase [`ThemeManager.buildTheme`](https://github.com/getstoryteller/storyteller-showcase-flutter/blob/main/lib/services/theme_manager.dart#L117) clones the selected preset and adjusts tile typography or singleton layouts on the fly\u2014use it as guidance when composing dynamic `StorytellerTheme` objects.\n\n## Configuring a StorytellerTheme\n\nA `StorytellerTheme` consists of the following properties:\n\n- `light` - sets the `ThemeType` to apply for light mode.\n- `dark` - sets the `ThemeType` to apply for dark mode.\n\nThe native SDK selects the variant from the device appearance. Flutter's\n`ThemeData` does not configure these native views. A supplied `light` variant\nis **not** copied into `dark`; define both variants when your brand colors\nmust apply in both modes. Omitted fields are excluded from the Dart map and\nresolved from native defaults, inheritance, and applicable tenant themes.\nCalling `setTheme` sends a new theme configuration; include all overrides\nyou intend to retain rather than treating it as a patch to a previous theme.\n\nThe expanded Cards, player-icon, Clips, and Search mappings on this page are\navailable in Flutter 11.6.4 and later. Flutter 12.1.2 adds\n[Sheets](#sheets), [multi-stop gradients](#multi-stop-gradients), the\n[modal Clips layout](#modal-clips-layout), `clips.embeddedVideoSizing`,\n`rectangularTile.titleGradient`, and the Instructions button `textSize` and\n`lineHeight`. Native properties not exported by\nthese Dart theme classes cannot be set through Flutter, even when they exist\nin a newer native reference. Android core requires API 24 or later; the iOS\ncore supports iOS 13 or later, while your app or optional ads integration may\nrequire a higher deployment target; see [Getting Started](getting-started/index.md).\n\n## Creating Themes\n\nThe `ThemeType` object exposes the Flutter theme sections shown below.\nTable defaults describe resolved native behavior, not Dart constructor values;\nmost Dart properties default to null and are omitted from `toMap()`. Layout\nvalues use native logical units (Android dp/sp and iOS points); Android maps\nnumeric dimensions to integers, so fractional values can be truncated.\n\nSome properties take their default value from others. For example, setting the `primary` color to `#FF0000` will also result in the New Indicator for Rectangular Tiles being colored red. Such properties are indicated in the tables below.\n\nNote that theme properties may be used for other situations in future.\n\n### Colors\n\nThe `colors` property on theme is used to establish a set of base colors for the SDK to use.\n\n| Property | Default Value | Data Type | Description |\n|----------|---------------|-----------|-------------|\n| `primary` | `#1C62EB` | `String` | The default accent color used throughout the UI. In general, this should be the primary brand color. Color strings should be in hex format (e.g., `#1C62EB`). |\n| `success` | `#3BB327` | `String`| Used to indicate correct answers in Quizzes. |\n| `alert` | `#E21219` | `String`| Used to indicate incorrect answers in Quizzes. |\n| `white.primary` | `#FFFFFF`| `String` | Used for white text |\n| `white.secondary` | `white.primary` at 85% opacity | `String` | Used for light text |\n| `white.tertiary` | `white.primary` at 70% opacity | `String` | Used for gray text |\n| `black.primary` | `#1A1A1A`| `String` | Used for black text |\n| `black.secondary` | `black.primary` at 85% opacity | `String` | Used for light black text |\n| `black.tertiary` | `black.primary` at 70% opacity | `String` | Used for gray text |\n\nUse `#RRGGBB` for opaque colors and `#AARRGGBB` for alpha colors. For\nexample, `#80FFFFFF` is translucent white on both platforms.\n\n**Example:**\n```dart\nThemeColors(\n primary: '#1C62EB',\n success: '#3BB327',\n alert: '#E21219',\n white: ThemeTextColors(\n primary: '#FFFFFF',\n secondary: '#D9FFFFFF',\n tertiary: '#B3FFFFFF',\n ),\n black: ThemeTextColors(\n primary: '#1A1A1A',\n secondary: '#D91A1A1A',\n tertiary: '#B31A1A1A',\n ),\n)\n```\n\n---\n\n### Font\n\nUse the `customFont` property to set a custom font for use throughout the UI.\n\nCreate a `ThemeCustomFont` with the Flutter asset path for each weight. The\nlight path is optional for source compatibility; all other paths are required.\n\n```dart\nThemeCustomFont(\n lightFilePath: 'fonts/MyCustomFont-Light.ttf',\n regularFilePath: 'fonts/MyCustomFont-Regular.ttf',\n mediumFilePath: 'fonts/MyCustomFont-Medium.ttf',\n semiboldFilePath: 'fonts/MyCustomFont-SemiBold.ttf',\n boldFilePath: 'fonts/MyCustomFont-Bold.ttf',\n heavyFilePath: 'fonts/MyCustomFont-Heavy.ttf',\n blackFilePath: 'fonts/MyCustomFont-Black.ttf',\n)\n```\n\nPackage every referenced font in your app's `pubspec.yaml`. You can register\nall weights under one Flutter font family; the native theme still uses the\nindividual asset paths rather than the Flutter family name:\n\n```yaml\nflutter:\n fonts:\n - family: MyCustomFont\n fonts:\n - asset: fonts/MyCustomFont-Light.ttf\n weight: 300\n - asset: fonts/MyCustomFont-Regular.ttf\n weight: 400\n - asset: fonts/MyCustomFont-Medium.ttf\n weight: 500\n - asset: fonts/MyCustomFont-SemiBold.ttf\n weight: 600\n - asset: fonts/MyCustomFont-Bold.ttf\n weight: 700\n - asset: fonts/MyCustomFont-Heavy.ttf\n weight: 800\n - asset: fonts/MyCustomFont-Black.ttf\n weight: 900\n```\n\nOn iOS, all six required font files must resolve and register successfully for\nthe custom font provider to apply. If the optional light file is omitted or\nunavailable, iOS falls back to the regular font for that weight. Theme images\nalso use Flutter asset paths: declare their files under `flutter.assets` and\npass them using `ThemeImage(filePath: ...)`. Native Lottie resources use the\nseparate packaging described under [Player](#player).\n\n\n---\n\n### Primitives\n\nThe `primitives` object contains base values which are used throughout the UI.\n\n| Property | Default Value | Data Type | Description |\n|----------|---------------|-----------|-------------|\n| `cornerRadius` | `8` | `double` | The corner radius used for rectangular tiles, buttons and poll/quiz answers |\n\n**Example:**\n```dart\nThemePrimitives(\n cornerRadius: 12.0,\n)\n```\n\n---\n\n### Lists\n\nThe `lists` property customizes properties of the various list types available from the SDK.\n\n| Property | Default Value | Data Type | Description |\n| ------------------ | ---------------------- | --------- | -------------------------------------------------------------------------------- |\n| `backgroundColor` | `colors.white.primary` (light), `colors.black.primary` (dark) | `String` | Required for outline on Live chip and fade to the side of the row |\n| `enablePlayerOpen` | `true` | `bool` | Controls whether the SDK opens the player when a tile is tapped. When set to `false`, the SDK will not open the player and the app must handle tile taps via the `onTileTapped` callback. |\n| `animateTilesOnReorder` | `true` | `bool` | When the `reloadData()` method is called to update lists, a reorder animation is added to visualize the updating process. |\n| `row.tileSpacing` | `8` | `double` | The space between each Tile in a row |\n| `row.startInset` | `12` | `double` | The space before the first Tile in a row |\n| `row.endInset` | `12` | `double` | The space after the last Tile in a row |\n| `grid.tileSpacing` | `8` | `double` | The space between each Tile in a grid, both vertically and horizontally |\n| `grid.columns` | `2` | `int` | The number of columns in a grid. |\n| `grid.topInset` | `0` | `double` | The space before the first row in a grid |\n| `grid.bottomInset` | `0` | `double` | The space after the last row in a grid |\n| `title.font` | `null` | `ThemeCustomFont` | Defines the font of the Title in Section |\n| `title.textSize` | `22` | `double` | Size of the Title in Section |\n| `title.lineHeight` | `28` | `double` | The line height of the Title in Section |\n| `title.textCase` | `default` | `String` | Sets the text case for the Title in Section. Possible values are `upper`, `lower` and `default` |\n| `title.textColor` | `colors.black.primary` (light), `colors.white.primary` (dark) | `String` | Color of Title in Section |\n\n**Example:**\n```dart\nThemeLists(\n backgroundColor: '#FFFFFF',\n enablePlayerOpen: true,\n animateTilesOnReorder: true,\n row: ThemeListRow(\n tileSpacing: 8.0,\n startInset: 12.0,\n endInset: 12.0,\n ),\n grid: ThemeListGrid(\n tileSpacing: 8.0,\n columns: 2,\n topInset: 12.0,\n bottomInset: 12.0,\n ),\n title: ThemeTitle(\n textSize: 22.0,\n lineHeight: 28.0,\n textCase: 'default',\n textColor: '#000000',\n ),\n)\n```\n\n---\n\n### Gradient\n\nThe `ThemeGradient` class allows for the creation of a color gradient, with options to customize both the colors and the positions at which the gradient starts and ends.\n\n| Property | Default Value | Data Type | Description |\n|----------------|---------------|---------------------|------------------------------------------------------|\n| `startColor` | required | `String` | The color where the gradient begins (hex format). |\n| `endColor` | required | `String` | The color where the gradient ends (hex format). |\n| `startPosition`| required | `int` | The position indicating where the gradient starts (0-8). |\n| `endPosition` | required | `int` | The position indicating where the gradient ends (0-8). |\n| `stops` | `null` | `List<ThemeGradientStop>` | Ordered color stops for a gradient with more than two colors. If set, overrides `startColor` and `endColor`. See [Multi-stop gradients](#multi-stop-gradients). |\n\n#### Gradient Positions\n\nGradient positions are represented as integers from 0-8:\n\n| Value | Position |\n|-------|----------|\n| `0` | Bottom left corner |\n| `1` | Bottom center edge |\n| `2` | Bottom right corner |\n| `3` | Center left edge |\n| `4` | Center |\n| `5` | Center right edge |\n| `6` | Top left corner |\n| `7` | Top center edge |\n| `8` | Top right corner |\n\n**Example:**\n```dart\nThemeGradient(\n startColor: '#FF0000',\n endColor: '#0000FF',\n startPosition: 6, // Top left\n endPosition: 2, // Bottom right\n)\n```\n\n#### Multi-stop gradients\n\n`ThemeGradient.withStops` creates a gradient from two or more\n`ThemeGradientStop` values. It sets `startColor` and `endColor` from the first\nand last stops.\n\n| Property | Default Value | Data Type | Description |\n|------------|---------------|-----------|-------------|\n| `color` | required | `String` | Stop color as `#RRGGBB` or `#AARRGGBB` |\n| `location` | required | `double` | Position along the gradient, from `0` to `1` |\n\nThe constructors throw an `ArgumentError` for fewer than two stops, a location\noutside `0` to `1`, or locations that decrease. If the native SDK can't use a stop list, for example because\na stop color is invalid, it draws the two-color gradient from `startColor` and\n`endColor` instead.\n\nFlutter colors put alpha first (`#AARRGGBB`), while the Storyteller CMS puts it\nlast (`#RRGGBBAA`). Reorder the digits when you copy a transparent color from\nthe CMS.\n\n**Example:**\n```dart\nThemeGradient.withStops(\n stops: [\n ThemeGradientStop(color: '#00000000', location: 0),\n ThemeGradientStop(color: '#66000000', location: 0.6),\n ThemeGradientStop(color: '#CC000000', location: 1),\n ],\n startPosition: 7, // Top center\n endPosition: 1, // Bottom center\n)\n```\n\n---\n\n### Tiles\n\nThe `tiles` property can be used to customize the appearance of the Tiles.\n\n| Property | Default Value | Data Type | Description |\n| ------------------------------------------------- | -------------------------------------------------------------------------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------- |\n| `chip.textSize` | `11` | `double` | Text size for the New Indicator and Live Indicator. |\n| `chip.show` | `true` | `bool` | Used to show/hide the new/live chip |\n| `title.textSize` | `11` | `double` | Size of the Title on a Tile |\n| `title.lineHeight` | `13` | `double` | The line height of the Title on a Tile |\n| `title.alignment` | `center` | `String` | The alignment of the Title on a Tile. Possible values are `left`, `center` and `right` |\n| `circularTile.title.unreadTextColor` | inherits `colors.black.primary` for `light`, `colors.white.primary` for `dark` | `String` | The text color of the Title for a circular tile when the story or the clip is unread |\n| `circularTile.title.readTextColor` | inherits `colors.black.tertiary` for `light`, `colors.white.tertiary` for `dark` | `String` | The text color of the Tile for a circular tile when the story or the clip is read |\n| `circularTile.unreadIndicatorColor` | inherits `colors.primary` | `String` | The color of the ring around a circular tile when the story or the clip is unread |\n| `circularTile.readIndicatorColor` | `#C1C1C1` (Android), `#C5C5C5` (iOS) | `String` | The color of the ring around a circular tile when the story or the clip is read |\n| `circularTile.unreadIndicatorGradient` | `null` | `ThemeGradient` | The gradient of the ring around a circular tile when the story or the clip is unread. If set, overrides `circularTile.unreadIndicatorColor` |\n| `circularTile.unreadIndicatorBorderColor` | `null` | `String` | The border color of the ring around a circular tile when the story or the clip is unread |\n| `circularTile.readIndicatorBorderColor` | `null` | `String` | The border color of the ring around a circular tile when the story or the clip is read |\n| `circularTile.unreadBorderWidth` | `2` | `double` | The width of Circular Tile ring border in unread state |\n| `circularTile.readBorderWidth` | `1` | `double` | The width of Circular Tile ring border in read state |\n| `circularTile.liveChip.readImage` | `null` | `ThemeImage` | Image to be used in place of default read Live Indicator. |\n| `circularTile.liveChip.unreadImage` | `null` | `ThemeImage` | Image to be used in place of default unread Live Indicator |\n| `circularTile.liveChip.unreadBackgroundColor` | `colors.alert` | `String` | Background color of the Live Indicator when the story contains unread pages or the clip has not been viewed. |\n| `circularTile.liveChip.readBackgroundColor` | `colors.black.tertiary` | `String` | Background color of the Live Indicator when all story pages have been read or the clip has been viewed. |\n| `circularTile.liveChip.unreadBackgroundGradient` | `null` | `ThemeGradient` | The gradient of the ring around a live tile and background of the Live Indicator. If set, overrides `circularTile.liveChip.unreadBackgroundColor` |\n| `circularTile.liveChip.unreadTextColor` | `colors.white.primary` | `String` | Text color of the Live Indicator when the story contains unread pages or the clip has not been viewed. |\n| `circularTile.liveChip.readTextColor` | `colors.white.primary` | `String` | Text color of the Live Indicator when all story pages have been read or the clip has been viewed. |\n| `circularTile.liveChip.unreadBorderColor` | `null` | `String` | Border color of the Live Indicator when the story contains unread pages or the clip has not been viewed. |\n| `circularTile.liveChip.readBorderColor` | `null` | `String` | Border color of the Live Indicator when all story pages have been read or the clip has been viewed. |\n| `rectangularTile.padding` | `8` | `double` | The internal padding for a rectangular story or the clip tile |\n| `rectangularTile.title.textColor` | inherits `colors.white.primary` | `String` | The text color of the Title for a rectangular tile |\n| `rectangularTile.titleGradient` | native default | `ThemeGradient` | Readability gradient behind the Title of a rectangular tile. If set, replaces the native title scrim |\n| `rectangularTile.chip.alignment` | `right` | `String` | The alignment of the New Indicator and Live Indicator in Rectangular Tiles. Possible values are `left`, `center` or `right` |\n| `rectangularTile.unreadIndicator.image` | `null` | `ThemeImage` | An image which can be used in place of the default unread indicator for a rectangular tile. If set, overrides `rectangularTile.unreadIndicator.gradient` |\n| `rectangularTile.unreadIndicator.gradient` | `null` | `ThemeGradient` | iOS-only gradient for the rectangular unread indicator; Android ignores this Dart field. If set on iOS, overrides `rectangularTile.unreadIndicator.backgroundColor` |\n| `rectangularTile.unreadIndicator.backgroundColor` | inherits `colors.primary` | `String` | The background color of the unread indicator for a rectangular tile |\n| `rectangularTile.unreadIndicator.textColor` | inherits `colors.white.primary` | `String` | The text color of the unread indicator for a rectangular tile |\n| `rectangularTile.unreadIndicator.borderColor` | `null` | `String` | Border color of the unread indicator for a rectangular tile |\n| `rectangularTile.liveChip.readImage` | `null` | `ThemeImage` | Image to be used in place of default read Live Indicator. |\n| `rectangularTile.liveChip.unreadImage` | `null` | `ThemeImage` | Image to be used in place of default unread Live Indicator. If set, overrides `rectangularTile.liveChip.unreadBackgroundGradient` |\n| `rectangularTile.liveChip.unreadBackgroundGradient` | `null` | `ThemeGradient` | Gradient background to be used for the Live Indicator. If set, overrides `rectangularTile.liveChip.unreadBackgroundColor` |\n| `rectangularTile.liveChip.unreadBackgroundColor` | `colors.alert` | `String` | Background color of the Live Indicator when the story contains unread pages or the clip has not been viewed. |\n| `rectangularTile.liveChip.readBackgroundColor` | `colors.black.tertiary` | `String` | Background color of the Live Indicator when all pages have been read or the clip has been viewed |\n| `rectangularTile.liveChip.unreadTextColor` | `colors.white.primary` | `String` | Text color of the Live Indicator when the story contains unread pages or the clip has not been viewed. |\n| `rectangularTile.liveChip.readTextColor` | `colors.white.primary` | `String` | Text color of the Live Indicator when all story pages have been read or the clip has been viewed. |\n| `rectangularTile.liveChip.unreadBorderColor` | `null` | `String` | Border color of the Live Indicator when the story contains unread pages or the clip has not been viewed. |\n| `rectangularTile.liveChip.readBorderColor` | `null` | `String` | Border color of the Live Indicator when all story pages have been read or the clip has been viewed. |\n\n\n\n\n\n**Example:**\n```dart\nThemeTiles(\n chip: ThemeTileChip(\n textSize: 11.0,\n show: true,\n ),\n title: ThemeTileTitle(\n textSize: 11.0,\n lineHeight: 13.0,\n alignment: 'center',\n ),\n circularTile: ThemeCircularTile(\n unreadIndicatorColor: '#1C62EB',\n readIndicatorColor: '#C5C5C5',\n unreadBorderWidth: 2.0,\n readBorderWidth: 2.0,\n ),\n rectangularTile: ThemeRectangularTile(\n padding: 8.0,\n title: ThemeRectangularTileTitle(\n textColor: '#FFFFFF',\n ),\n ),\n)\n```\n\n---\n\n### Cards\n\nThe `cards` property customizes controls rendered inside native Cards\ncollections.\n\n| Property | Default Value | Data Type | Description |\n|----------|---------------|-----------|-------------|\n| `audio.mutedIcon` | native icon | `ThemeImage` | Audio-control image shown while a video Card is muted |\n| `audio.unmutedIcon` | native icon | `ThemeImage` | Audio-control image shown while a video Card is unmuted |\n| `audio.unavailableIcon` | native icon | `ThemeImage` | Android-only image shown when a video Card has no audio; iOS ignores this optional field |\n\n```dart\nThemeCards(\n audio: ThemeCardsAudio(\n mutedIcon: ThemeImage(filePath: 'assets/icons/card_muted.png'),\n unmutedIcon: ThemeImage(filePath: 'assets/icons/card_unmuted.png'),\n unavailableIcon: ThemeImage(\n filePath: 'assets/icons/card_audio_unavailable.png',\n ),\n ),\n)\n```\n\n---\n\n### Player\n\nThe `player` property is used to customize properties relating to the Story and Clips Player.\n\n| Property | Default Value | Data Type | Description |\n|----------|---------------|-----------|-------------|\n| `showStoryIcon` | `false` | `bool` | Shows the round story icon before the Story Title in the Player |\n| `showTimestamp` | `true` | `bool` | Shows the timestamp after the Story Title in the Player, indicating how long ago a story was published |\n| `showShareButton` | `true` | `bool` | Shows the share button in the Player. Setting this to `false` entirely disables sharing in Storyteller |\n| `showLikeButton` | `true` | `bool` | Shows the like button in the Clips Player. Setting this to `false` entirely disables liking in Storyteller |\n| `showMoreButton` | native default | `bool` | Android-only visibility control for the Clips more button; iOS ignores it |\n| `enableFollowableCategorySwipeFromRightEdge` | native default | `bool` | Enables or disables the right-edge swipe that opens a followable category |\n| `liveChip.image` | `null` | `ThemeImage` | Image used in place of Live Chip before Live Story or Clip Titles. If set, it overrides `liveChip.backgroundGradient` |\n| `liveChip.textColor` | inherits `colors.white.primary` | `String` | Text color used for badge label for Live Story or Clip |\n| `liveChip.backgroundGradient` | `null` | `ThemeGradient` | Background gradient of the badge for Live Story or Clip. If set, it overrides `liveChip.backgroundColor` |\n| `liveChip.backgroundColor` | `theme.colors.alert` | `String` | Background color of the badge for Live Story or Clip |\n| `liveChip.borderColor` | `null` | `String` | Border color of the badge for Live Story or Clip |\n| `icons.share` | `null` | `ThemeImage` | An image to be used in place of the default share icon |\n| `icons.refresh` | `null` | `ThemeImage` | Refresh button image to be used in place of refresh share icon, used in the error state |\n| `icons.back` | `null` | `ThemeImage` | Back button image used by the native player |\n| `icons.close` | `null` | `ThemeImage` | Android-only close button image; iOS ignores it |\n| `icons.more` | `null` | `ThemeImage` | Android-only more button image; iOS ignores it |\n| `icons.likeInitial` | `null` | `ThemeImage` | An image to be used in place of the default like icon when the clip is not liked |\n| `icons.likeLiked` | `null` | `ThemeImage` | An image to be used in place of the default like icon when the clip is liked |\n| `icons.likeAnimation.liked` | `null` | `ThemeLottieAnimationResource` | Lottie animation used when a clip changes to liked |\n| `icons.likeAnimation.unliked` | `null` | `ThemeLottieAnimationResource` | Lottie animation used when a clip changes to unliked |\n| `icons.mute.muted` | `null` | `ThemeImage` | Mute button image for the muted state |\n| `icons.mute.unmuted` | `null` | `ThemeImage` | Mute button image for the unmuted state |\n| `icons.captions.enabled` | `null` | `ThemeImage` | Captions button image for the enabled state |\n| `icons.captions.disabled` | `null` | `ThemeImage` | Captions button image for the disabled state |\n| `clips.showButtonBackgrounds` | native default | `bool` | Controls native action-button backgrounds in the Clips Player |\n| `clips.actionIconSize` | native default | `double` | Requested Clips action-icon size; the native SDK applies its supported size rules |\n| `clips.eyebrow.*` | native defaults | `ThemePlayerClipsEyebrow` | Font, text size, line height, and color for the Clips eyebrow |\n| `clips.title.*` | native defaults | `ThemePlayerClipsTitle` | Font, weight, text size, line height, and color for the Clips title |\n| `clips.feedSwitcher.selected.*` | native defaults | `ThemePlayerClipsFeedSwitcherState` | Weight, text size, and line height for the selected Following-feed label |\n| `clips.feedSwitcher.unselected.*` | native defaults | `ThemePlayerClipsFeedSwitcherState` | Weight, text size, and line height for an unselected Following-feed label |\n| `clips.categoryNavigation.*` | native defaults | `ThemePlayerClipsCategoryNavigation` | Weight, text size, and line height for category-navigation labels |\n| `clips.topGradient` | native default | `ThemeGradient` | Readability gradient at the top of the Clips Player |\n| `clips.bottomGradient` | native default | `ThemeGradient` | Readability gradient at the bottom of the Clips Player |\n| `clips.embeddedVideoSizing` | Storyteller CMS setting | `String` | Video sizing in [Embedded Clips](EmbeddedClips.md): `legacy` keeps the existing layout; `widthConstrained` fits the video to the available width, keeps its aspect ratio, and centers any vertical overflow. If set, overrides the CMS setting. Modal Clips are not affected |\n| `clips.modal.*` | `null` | `ThemePlayerClipsModal` | Layout overrides for full-screen Clips; see [Modal Clips layout](#modal-clips-layout). When unset, the existing modal layout is kept |\n| `clips.progressBar.position` | native default | `String` | `bottom` or `aboveAction`; native layout remains authoritative |\n| `clips.progressBar.playedColor` | native default | `String` | Played-track color |\n| `clips.progressBar.remainingColor` | native default | `String` | Remaining-track color |\n| `clips.progressBar.active.*` | native defaults | `ThemePlayerClipsProgressBarActive` | Played, remaining, current-time, and total-time colors while scrubbing |\n| `clips.spacing.*` | native defaults | `ThemePlayerClipsSpacing` | Insets and gaps: `backButtonStartInset`, `contentInsetHorizontal`, `contentInsetBottom`, `actionSpacing`, `eyebrowToTitleSpacing`, `titleToActionSpacing`, `titleToCategoriesSpacing`, `categoriesToMoreSpacing`, `metadataToProgressBarSpacing`, and `progressBarToActionSpacing` |\n\nOn Android, add each Lottie JSON file to `android/app/src/main/res/raw` and\nprovide its filename without `.json` in `androidRawResourceName` (or `name` as\na fallback). On iOS, add the JSON file to the app target's Copy Bundle\nResources phase and provide its bundled resource name in `name`. Use\n`iosBundlePath` when the resource belongs to a bundle other than the main app\nbundle.\n\n\n\n**Example:**\n```dart\nThemePlayer(\n showStoryIcon: false,\n showTimestamp: true,\n showShareButton: true,\n showLikeButton: true,\n enableFollowableCategorySwipeFromRightEdge: true,\n icons: ThemePlayerIcons(\n share: ThemeImage(filePath: 'assets/icons/share.png'),\n back: ThemeImage(filePath: 'assets/icons/back.png'),\n likeInitial: ThemeImage(filePath: 'assets/icons/like.png'),\n likeLiked: ThemeImage(filePath: 'assets/icons/like_filled.png'),\n mute: ThemePlayerMuteIcons(\n muted: ThemeImage(filePath: 'assets/icons/muted.png'),\n unmuted: ThemeImage(filePath: 'assets/icons/unmuted.png'),\n ),\n captions: ThemePlayerCaptionsIcons(\n enabled: ThemeImage(filePath: 'assets/icons/captions_on.png'),\n disabled: ThemeImage(filePath: 'assets/icons/captions_off.png'),\n ),\n likeAnimation: ThemePlayerLikeAnimation(\n liked: ThemeLottieAnimationResource(\n name: 'like_lottie',\n androidRawResourceName: 'like_lottie',\n ),\n unliked: ThemeLottieAnimationResource(\n name: 'unlike_lottie',\n androidRawResourceName: 'unlike_lottie',\n ),\n ),\n ),\n clips: ThemePlayerClips(\n showButtonBackgrounds: true,\n actionIconSize: 34,\n title: ThemePlayerClipsTitle(\n fontWeight: 'bold',\n textSize: 18,\n lineHeight: 22,\n textColor: '#FFFFFF',\n ),\n progressBar: ThemePlayerClipsProgressBar(\n position: 'aboveAction',\n playedColor: '#1C62EB',\n remainingColor: '#80FFFFFF',\n ),\n spacing: ThemePlayerClipsSpacing(\n contentInsetHorizontal: 16,\n contentInsetBottom: 20,\n actionSpacing: 12,\n ),\n ),\n)\n```\n\n#### Modal Clips layout\n\n`ThemePlayerClips.modal` takes a `ThemePlayerClipsModal`, which overrides the\nlayout of full-screen (modal) Clips. It doesn't affect Embedded Clips. Leave\nit unset to keep the existing modal layout. On Android, any valid value that\ndiffers from the default switches to the configurable modal layout; defaults and\nvalues Android rejects don't. Set `modal` only when you want to change it.\n\n| Property | Default Value | Data Type | Description |\n|----------|---------------|-----------|-------------|\n| `drawBehindStatusBar` | `false` | `bool` | Extends the video behind the status bar; controls stay in the safe area |\n| `feedSwitcherItemSpacing` | native default | `double` | Total horizontal gap between the For You and Following labels |\n| `titleToCategoriesSpacing` | native default | `double` | Gap between the title or description and the category labels |\n| `categoriesToMoreSpacing` | native default | `double` | Gap between the category labels and the more/less control |\n| `metadataToProgressBarSpacing` | native default | `double` | Gap between the metadata and the resting progress track |\n| `progressBarToActionSpacing` | native default | `double` | Minimum gap between the progress track and the primary action |\n| `progressBarPosition` | native default | `String` | `bottom` or `aboveAction`. `aboveAction` falls back to `bottom` when the Clip has no call to action |\n| `topGradientHeight` | native default | `double` | Height of the top readability gradient, including any status-bar area behind the video |\n| `bottomGradientHeight` | native default | `double` | Height of the bottom readability gradient |\n| `progressBarHeight` | native default | `double` | Height of the resting progress track |\n| `progressBarActiveHeight` | native default | `double` | Height of the progress track while scrubbing; the drag target stays at least 48 high |\n| `progressBarInsetHorizontal` | native default | `double` | Horizontal inset of the progress track from the video edges |\n| `navigationIconSize` | native default | `double` | Size of the Back and Search icons; their tap targets stay at least 48 |\n| `navigationInsetHorizontal` | native default | `double` | Horizontal inset of the Back and Search buttons from the safe edges |\n| `navigationInsetTop` | native default | `double` | Additional top inset for navigation below the status bar |\n| `navigationHeight` | native default | `double` | Height of the navigation row. Android uses at least `48` |\n| `searchIcon` | `null` | `ThemeImage` | Replaces the built-in Search icon |\n\nSpacing, inset and gradient-height values must be zero or more, and sizes must\nbe greater than zero. Android ignores values outside these ranges.\n\n---\n\n### Buttons\n\nThe `buttons` property applies customizations to buttons which appear throughout the UI.\n\n| Property | Default Value | Data Type | Description |\n|----------|---------------|-----------|-------------|\n| `backgroundColor` | inherits `colors.white.primary` | `String` | The background color of buttons throughout the UI |\n| `textColor` | inherits `colors.black.primary` | `String` | The text color of buttons throughout the SDK |\n| `textCase` | `default` | `String` | Sets the text case for buttons throughout the UI. Possible values are `upper`, `lower` and `default` |\n| `cornerRadius` | inherits `primitives.cornerRadius` | `double` | The corner radius for all buttons throughout the UI |\n\n**Example:**\n```dart\nThemeButtons(\n backgroundColor: '#000000',\n textColor: '#FFFFFF',\n textCase: 'upper',\n cornerRadius: 8.0,\n)\n```\n\n---\n\n### Instructions\n\nUse the `instructions` property to customize the appearance of the instructions screen.\n\n| Property | Default Value | Data Type | Description |\n|----------|---------------|-----------|-------------|\n| `show` | `true` | `bool` | Determines whether the Instructions Screen is shown the first time a user opens the Story Player. Set to `false` to completely disable the instructions screen. |\n| `headingColor` | inherits `colors.black.primary` for `light`, `colors.white.primary` for `dark` | `String` | The color of the heading text on the Instructions Screen |\n| `headingTextCase` | `default` | `String` | Determines the text case of the heading on the Instructions Screen. Possible values are `upper`, `lower` and `default` |\n| `headingFont` | inherits global custom font | `ThemeCustomFont` | Defines the font of the heading text on the Instructions Screen |\n| `subHeadingColor` | inherits `colors.black.secondary` for `light`, `colors.white.secondary` for `dark` | `String` | The color of the subheading text on the Instructions Screen |\n| `backgroundColor` | inherits `colors.white.primary` for `light`, `colors.black.primary` for `dark` | `String` | The color of the background of the Instructions Screen |\n| `icons` | `null` | `ThemeInstructionIcons` | Custom instruction images on Android and iOS |\n| `button.backgroundColor` | inherits `colors.black.primary` for `light`, `colors.white.primary` for `dark` | `String` | The background color of the button used on the Instructions Screen |\n| `button.textColor` | inherits `colors.white.primary` for `light`, `colors.black.primary` for `dark` | `String` | The text color of the button used on the Instructions Screen |\n| `button.textSize` | `16` | `double` | Android-only text size of the button label on the Clips Instructions Screen; iOS ignores it |\n| `button.lineHeight` | `21` | `double` | Android-only line height of the button label on the Clips Instructions Screen; iOS ignores it |\n\nThe `icons` property replaces the instruction images on Android and iOS. The icons should be 48x48 PNGs or appropriate asset images. An example of using this property is shown below:\n\n```dart\nThemeInstructionIcons(\n forward: ThemeImage(filePath: 'assets/icons/forward.png'),\n pause: ThemeImage(filePath: 'assets/icons/pause.png'),\n back: ThemeImage(filePath: 'assets/icons/back.png'),\n move: ThemeImage(filePath: 'assets/icons/move.png'),\n)\n```\n\n\n\n**Example:**\n```dart\nThemeInstructions(\n show: true,\n headingColor: '#000000',\n headingTextCase: 'default',\n subHeadingColor: '#666666',\n backgroundColor: '#FFFFFF',\n button: ThemeInstructionButton(\n backgroundColor: '#000000',\n textColor: '#FFFFFF',\n ),\n)\n```\n\n---\n\n### Engagement Units\n\nThe `engagementUnits` property can be used to customize properties relating to Polls and Quizzes.\n\n| Property | Default Value | Data Type | Description |\n|----------|---------------|-----------|-------------|\n| `poll.answerTextColor` | inherits `colors.black.primary` | `String` | The text color used for Poll Answers |\n| `poll.percentBarColor` | `#CDD0DC` | `String` | The background color of the percentage bar in Poll Answers |\n| `poll.selectedAnswerBorderColor` | inherits `colors.primary` | `String` | The border color applied to the selected Poll Answer |\n| `poll.answeredMessageTextColor` | inherits `colors.white.primary` | `String` | The color of the vote count shown to users after they select a Poll Answer |\n| `poll.selectedAnswerBorderImage` | `null` | `ThemeImage` | A border image which can be used for the selected Poll Answer. If set, the native selected-answer border uses the supplied image. |\n| `poll.showImageAnswerGradientOverlay` | `true` | `bool` | Controls whether image poll answers show the native gradient overlay |\n| `triviaQuiz.correctColor` | inherits `colors.success` | `String` | The color used to show correct answers in Trivia Quizzes |\n| `triviaQuiz.incorrectColor` | inherits `colors.alert` | `String` | The color used to show incorrect answers in Trivia Quizzes |\n\n\n\n\n\n**Example:**\n```dart\nThemeEngagementUnits(\n poll: ThemePoll(\n answerTextColor: '#000000',\n percentBarColor: '#CDD0DC',\n selectedAnswerBorderColor: '#1C62EB',\n showImageAnswerGradientOverlay: true,\n ),\n triviaQuiz: ThemeTriviaQuiz(\n correctColor: '#3BB327',\n incorrectColor: '#E21219',\n ),\n)\n```\n\n---\n\n### Search\n\nThe `search` property applies customizations to the Search component.\n\n| Property | Default Value | Data Type | Description |\n|----------|---------------|-----------|-------------|\n| `backIcon` | default back icon | `ThemeImage` | Image to be used as a back icon in the Search UI |\n| `backgroundColor` | native default | `String` | Search screen background color |\n| `heading.font` | inherits global custom font | `ThemeCustomFont` | Defines the styling of the Filters title in the Filter View |\n| `heading.textSize` | `22` | `double` | Size of the Filter View title |\n| `heading.lineHeight` | `28` | `double` | The line height of the Filter View title |\n| `heading.textCase` | `default` | `String` | Sets the text case for Filter View title. Possible values are `upper`, `lower` and `default` |\n| `heading.textColor` | appearance foreground (Android), `lists.title.textColor` (iOS) | `String` | Color of Filter View title |\n| `input.*` | native defaults | `ThemeSearchInput` | Input background, text, placeholder, icon, corner radius, text size, and line height |\n| `filterButton.*` | native defaults | `ThemeSearchFilterButton` | Filter-button background, icon color, and corner radius |\n| `suggestions.*` | native defaults | `ThemeSearchSuggestions` | Suggestion text/icon colors, icon background, text size, and line height |\n| `noResults.iconColor` | native default | `String` | No-results icon color |\n| `noResults.title.*` | native defaults | `ThemeSearchTextStyle` | No-results title color, size, line height, and case |\n| `noResults.message.*` | native defaults | `ThemeSearchTextStyle` | No-results message color, size, line height, and case |\n| `filters.backgroundColor` | native default | `String` | Filter-sheet background color |\n| `filters.handleColor` | native default | `String` | Filter-sheet drag-handle color |\n| `filters.sectionHeading.*` | native defaults | `ThemeSearchTextStyle` | Filter-section heading color, size, line height, and case |\n| `filters.option.*` | native defaults | `ThemeSearchFilterOption` | Normal/selected option colors and borders, corner radius, text size, and line height |\n| `filters.applyButton.*` | native defaults | `ThemeButtons` | Apply-button background, text color, text case, and corner radius |\n\n**Example:**\n```dart\nThemeSearch(\n backgroundColor: '#F7F9FC',\n backIcon: ThemeImage(filePath: 'assets/icons/back.png'),\n input: ThemeSearchInput(\n backgroundColor: '#FFFFFF',\n textColor: '#172033',\n placeholderTextColor: '#667085',\n iconColor: '#1C62EB',\n cornerRadius: 12,\n ),\n filterButton: ThemeSearchFilterButton(\n backgroundColor: '#E8EEFF',\n iconColor: '#1C62EB',\n cornerRadius: 12,\n ),\n heading: ThemeTitle(\n textSize: 22.0,\n lineHeight: 28.0,\n textCase: 'default',\n textColor: '#000000',\n ),\n filters: ThemeSearchFilters(\n backgroundColor: '#FFFFFF',\n handleColor: '#98A2B3',\n option: ThemeSearchFilterOption(\n selectedBackgroundColor: '#1C62EB',\n selectedTextColor: '#FFFFFF',\n cornerRadius: 8,\n ),\n applyButton: ThemeButtons(\n backgroundColor: '#1C62EB',\n textColor: '#FFFFFF',\n ),\n ),\n)\n```\n\nSearch filter availability (`Sort`, `Date`, and `Content Type`) is controlled\nby the tenant's native Search settings. Local Flutter themes change appearance,\nnot which filters are enabled. The Following-feed selection mechanism, modal\nClips bottom anchoring, followable-category profile content, and remote theme\nprecedence are also resolved by native/tenant configuration. Omitted Flutter\ntheme fields continue to inherit those native values.\n\n---\n\n### Home\n\nThe `home` property can be used to customize properties related to the Storyteller Home component.\n\n| Property | Default Value | Data Type | Description |\n|----------|---------------|-----------|-------------|\n| `headerTitle.font` | `null` | `ThemeCustomFont` | Defines the font for the heading |\n| `headerTitle.textSize` | `22` | `double` | Size of the title in section |\n| `headerTitle.lineHeight` | `25` (Android), `28` (iOS) | `double` | The line height of the title in section |\n| `headerTitle.textCase` | `default` | `String` | Sets the text case for the title. Possible values are `upper`, `lower` and `default` |\n| `headerTitle.textColor` | `null` | `String` | Color of heading text in Storyteller Home |\n| `circularTitle.textSize` | inherits `lists.title.textSize` (Android), `11` (iOS) | `double` | Size of the circular title in section |\n| `circularTitle.lineHeight` | inherits `lists.title.lineHeight` (Android), `13` (iOS) | `double` | The line height of the circular title in section |\n| `singletonTitle.textSize` | `22` | `double` | Size of the singleton title in section |\n| `singletonTitle.lineHeight` | `28` | `double` | The line height of the singleton title in section |\n| `gridTitle.textSize` | `16` | `double` | Size of the grid title in section |\n| `gridTitle.lineHeight` | `22` | `double` | The line height of the grid title in section |\n\n**Example:**\n```dart\nThemeHome(\n headerTitle: ThemeTitle(\n textSize: 22.0,\n lineHeight: 28.0,\n textCase: 'default',\n textColor: '#000000',\n ),\n circularTitle: ThemeHomeTitle(\n textSize: 11.0,\n lineHeight: 13.0,\n ),\n)\n```\n\n### Sheets\n\nThe `sheets` property can be used to customize the sheets that Storyteller presents.\n\n| Property | Default Value | Data Type | Description |\n|----------|---------------|-----------|-------------|\n| `cornerRadius` | native default for each sheet | `double` | Top corner radius of Storyteller sheets |\n\n## Checking a Theme Change\n\nStart with an obvious accent color, supply both light and dark variants, and\nopen a published Story/Clip from the placement you styled. Test both device\nappearances and the relevant list/player/Search screen: a Clips-only property\ndoes not restyle Stories, and a per-list theme can override the global theme\nfor that placement. Set the global theme before mounting content.\n\nIf a value appears unchanged, check its applicable surface and platform,\nthe placement's own theme, and any tenant or collection remote overrides.\nNative/tenant settings can override supported host values. Confirm that icon\nand font assets are packaged and paths match their case; missing iOS font\nweights prevent the provider from applying. Reopening content is a useful\ncheck after changing appearance or resources; rebuilding is required after\nchanging native resource packaging. Continue with\n[Storyteller List Views](StorytellerListViews.md), [Search](Search.md), or\n[Troubleshooting](Troubleshooting.md) for the surface you are integrating.\n", "copy_markdown_include_header": false, "base_path": "", "ai_dir": "ai", "missing_payload_behavior": "empty"}