Skip to content

Custom Themes#

The appearance of the SDK can be customized by setting the Storyteller.theme global property or StorytellerListView.theme view property. This requires a UiTheme configuration object.

Note: global theme should be set before any of the Storyteller list views are inflated. Note: this property will be used as fallback theming style used to render Story items in lists and activities launched from list. See StorytellerLists or StorytellerListViews (legacy).

Showcase examples#

UiTheme is a data structure containing tree of the parameters. While it's possible to manually declare a whole structure of this data object, for convenience it's recommended to use UiTheme DSL for that purpose.

Defining a Theme#

A Theme contains various settings which change visual aspects of the Storyteller SDK. All properties are optional. In general, it should be possible to obtain a custom look by only using the colors properties - however, if you require more fine-grained control, that is also available.

Colors#

The colors property on theme is used to establish a set of base colors for the SDK to use.

Colors Description Default Value Dark Value
theme.colors.primary Default accent color used throughout the UI. Usually the primary brand color. Used for: Unread Indicators, loading progress bars and spinners on Android. #1C62EB
theme.colors.success Used to indicate correct answers in Quizzes. #3BB327
theme.colors.alert Used to indicate wrong answers in Quizzes and for the 'Live' indicator on Live Stories. #E21219
theme.colors.white.primary Used for Story names on rectangular tiles and in the player. Also used for all primary text in dark mode by default. #ffffff
theme.colors.white.secondary Used for secondary text in dark mode. rgba({theme.colors.white.primary}, 85%)
theme.colors.white.tertiary Used for tertiary text in dark mode, e.g. the time stamp in the player header. Also used for the selected Poll option border. rgba({theme.colors.white.primary}, 70%)
theme.colors.black.primary Used for primary text in light mode by default. #1A1A1A
theme.colors.black.secondary Used for secondary text in light mode. rgba({theme.colors.black.primary}, 85%)
theme.colors.black.tertiary Used for tertiary text and minor UI elements in light mode. rgba({theme.colors.black.primary}, 70%)

Font#

Use the font property to set a custom font for use throughout the UI.

Font Description Default Value Dark Value
theme.font Font to be used throughout the UI, defaults to the system font on each platform or inherits the container font on web. Font definition requires access to different weights to work properly. System Font

Primitives#

The primitives object contains base values which are used throughout the UI.

Primitives Description Default Value Dark Value
theme.primitives.cornerRadius Default corner radius used for Rectangular Tiles, Buttons and Poll/Quiz answers. 8 dp

Lists#

The lists customize properties of the various list types available from the SDK.

Lists Description Default Value Dark Value
theme.lists.title The style of the title on Story or Clip tile. 8 dp
theme.lists.row.tileSpacing The space between each Story and Clip Tile in a row. 8 dp
theme.lists.row.startInset The space before the first tile in a row. 12 dp
theme.lists.row.endInset The space after the last tile in a row. 12 dp
theme.lists.grid.tileSpacing The space between Story and Clip Tiles in a grid, both vertically and horizontally. 8 dp
theme.lists.grid.columns Number of columns in the grid. 2 dp
theme.lists.grid.topInset The space at the top of the first row in a grid. 0 dp
theme.lists.grid.bottomInset The space at the bottom of the last row in a grid. 0 dp
theme.lists.backgroundColor Required for outline on Live chip and fade to the side of the row {theme.colors.white.primary} {theme.colors.black.primary}
theme.lists.animateTilesOnReorder This option allows you to enable animation in lists when updating items true true
theme.lists.enablePlayerOpen 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 StorytellerDelegates.onTileTapped(tileType: StorytellerTileType) true true

Gradient#

The Gradient data 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 null ColorInt The color where the gradient begins.
endColor null ColorInt The color where the gradient ends.
startPosition null GradientPosition The position indicating where the gradient starts.
endPosition null GradientPosition The position indicating where the gradient ends.

Enum: GradientPosition#

Defines positions for starting and ending points of the gradient.

Value Data Type Description
GradientPosition.BottomLeft enum Bottom left corner of the gradient area.
GradientPosition.BottomCenter enum Bottom center edge of the gradient area.
GradientPosition.BottomRight enum Bottom right corner of the gradient area.
GradientPosition.CenterLeft enum Center left edge of the gradient area.
GradientPosition.CenterCenter enum Center of the gradient area.
GradientPosition.CenterRight enum Center right edge of the gradient area.
GradientPosition.TopLeft enum Top left corner of the gradient area.
GradientPosition.TopCenter enum Top center edge of the gradient area.
GradientPosition.TopRight enum Top right corner of the gradient area.

Story and Clip Tiles#

The tiles property can be used to customize the appearance of the Story and Clip Tiles.

Story and Clip Tiles Description Default Value Dark Value
theme.tiles.chip.textSize Text size for the New Indicator and Live Indicator. 11 sp
theme.tiles.chip.borderColor Border color for the New Indicator and Live Indicator. null
theme.tiles.chip.show Show or hide the New/Live chip indicator on tiles. true
theme.tiles.title.textSize Size of the Story Title on a Tile. 11 sp
theme.tiles.title.lineHeight Line height of the Story Title on a Tile. 13 sp
theme.tiles.title.alignment Alignment of the text in a tile, can be Gravity.START/CENTER/END center
theme.tiles.circularTile.title.unreadTextColor Text color of Circular Story and Clip Tile Titles in unread state {theme.colors.black.primary} {theme.colors.white.primary}
theme.tiles.circularTile.title.readTextColor Text color of Circular Story and Clip Tile Titles in read state {theme.colors.black.tertiary} {theme.colors.white.tertiary}
theme.tiles.circularTile.unreadIndicatorColor The color of the ring around Circular Story and Clip Tiles. {theme.colors.primary}
theme.tiles.circularTile.readIndicatorColor The color of the ring around Circular Story and Clip Tiles in read state #C5C5C5 (taken from app layout)
theme.tiles.circularTile.unreadIndicatorBorderColor The color of the border of the ring around Circular Story and Clip Tiles null
theme.tiles.circularTile.readIndicatorBorderColor The color of the border of the ring around Circular Story and Clip Tiles in read state null
theme.tiles.circularTile.unreadBorderWidth Width of Circular Story and Clip Tile ring border in unread state 2dp
theme.tiles.circularTile.readBorderWidth Width of Circular Story and Clip Tile ring border in read state 2dp
theme.tiles.circularTile.unreadIndicatorGradient The gradient of the ring around a circular tile when the story or the clip is unread. If set, overrides circularTile.unreadIndicatorColor. null
theme.tiles.circularTile.liveChip.unreadImage Image resource to be used in place of default unread Live Indicator. If set, overrides theme.tiles.circularTile.liveChip.unreadBackgroundGradient. null
theme.tiles.circularTile.liveChip.unreadBackgroundGradient The gradient of the ring around a live tile and background of the Live Indicator. If set, overrides circularTile.liveChip.unreadBackgroundColor. null
theme.tiles.circularTile.liveChip.unreadBackgroundColor Background color of the Live Indicator when the story contains unread pages or the clip has not been viewed. {theme.colors.alert}
theme.tiles.circularTile.liveChip.unreadBorderColor Border color of the Live Indicator when the story contains unread pages or the clip has not been viewed. null
theme.tiles.circularTile.liveChip.unreadTextColor Text color of the Live Indicator when the story contains unread pages or the clip has not been viewed. {theme.colors.white.primary}
theme.tiles.circularTile.liveChip.readImage Image resource to be used in place of default read Live Indicator. null
theme.tiles.circularTile.liveChip.readBackgroundColor Background color of the Live Indicator when all pages have been read or the clip has been viewed. {theme.colors.black.tertiary}
theme.tiles.circularTile.liveChip.readBorderColor Border color of the Live Indicator when all pages have been read or the clip has been viewed. null
theme.tiles.circularTile.liveChip.readTextColor Text color of the Live Indicator when all story pages have been read or the clip has been viewed. {theme.colors.white.primary}
theme.tiles.rectangularTile.title.textColor Text color of the Story Title in Rectangular Tiles. {theme.colors.white.primary}
theme.tiles.rectangularTile.chip.alignment Alignment of the New Indicator and Live Indicator in Rectangular Tiles, can be start, center or end. end
theme.tiles.rectangularTile.padding Internal padding for Rectangular Story and Clip Tiles, creates space between Story Name or New Indicator and tile edge. 8 dp
theme.tiles.rectangularTile.unreadIndicator.image Image resource to be used in place of default New Indicator on Rectangular Tiles. null
theme.tiles.rectangularTile.unreadIndicator.backgroundColor Background color of the New Indicator. {theme.colors.primary}
theme.tiles.rectangularTile.unreadIndicator.borderColor Border color of the New Indicator. null
theme.tiles.rectangularTile.unreadIndicator.textColor The text color of the unread indicator for a rectangular tile. {theme.colors.white.primary}
theme.tiles.rectangularTile.unreadIndicator.textSize Text size for the New Indicator. 11 sp
theme.tiles.rectangularTile.liveChip.unreadImage Image resource to be used in place of default unread Live Indicator. If set, overrides theme.tiles.circularTile.liveChip.unreadBackgroundGradient. null
theme.tiles.rectangularTile.liveChip.unreadBackgroundGradient The gradient of the ring around a live tile and background of the Live Indicator. If set, overrides circularTile.liveChip.unreadBackgroundColor. null
theme.tiles.rectangularTile.liveChip.unreadBackgroundColor Background color of the Live Indicator when the story contains unread pages or the clip has not been viewed. {theme.colors.alert}
theme.tiles.rectangularTile.liveChip.unreadTextColor Text color of the Live Indicator when the story contains unread pages or the clip has not been viewed. {theme.colors.white.primary}
theme.tiles.rectangularTile.liveChip.readImage Image resource to be used in place of default read Live Indicator. null
theme.tiles.rectangularTile.liveChip.readBackgroundColor Background color of the Live Indicator when all pages have been read or the clip has been viewed. {theme.colors.black.tertiary}
theme.tiles.rectangularTile.liveChip.readBorderColor Border color of the Live Indicator when all pages have been read or the clip has been viewed. null
theme.tiles.rectangularTile.liveChip.unreadBorderColor Border color of the Live Indicator when the story contains unread pages or the clip has not been viewed. null
theme.tiles.rectangularTile.liveChip.readTextColor Text color of the Live Indicator when all story pages have been read or the clip has been viewed. {theme.colors.white.primary}

Diagram illustrating tiles theming

Diagram illustrating live tiles theming

Player#

The player property is used to customize properties relating to the Stories and Clips Player.

Player Description Default Value Dark Value
theme.player.showStoryIcon Shows the circular Story icon before the Story Name in the Player. FALSE
theme.player.showTimestamp Shows a timestamp after the Story Name in the Player, eg "2h" to show the Story was published 2 hours ago. TRUE
theme.player.showShareButton Shows the Share button in the Player, applies to all Page types and Engagement Units. Setting to FALSE entirely disables sharing in Storyteller. TRUE
theme.player.liveChip.image Image used in place of Live Chip before Live Story or Clip Titles. If set, it overrides liveChip.backgroundGradient null
theme.player.liveChip.backgroundGradient Background gradient of the badge for Live Story or Clip. If set, it overrides liveChip.backgroundColor null
theme.player.liveChip.backgroundColor Background color of the Live chip Story or Clip {theme.colors.alert}
theme.player.liveChip.textColor Text color used for badge label for Live Story or Clip {theme.colors.white.primary}
theme.player.liveChip.borderColor Color used for border of badge label for Live Story or Clip null
theme.player.icons.share Share button image to be used in place of default share icon. default icon
theme.player.icons.refresh Refresh button image to be used in place of default refresh icon. default icon
theme.player.icons.close Close button image to be used in place of default close icon. default icon
theme.player.icons.back Back button image to be used in place of default Clips back icon. default icon
theme.player.icons.like.initial Initial like button image to be used in place of default initial like icon. default icon
theme.player.icons.like.liked Liked button image to be used in place of default liked icon. default icon
theme.player.icons.like.animation.liked Raw Lottie animation played for the Clips like button when the state changes from unliked to liked. If unset, the SDK falls back to the static liked icon. null
theme.player.icons.like.animation.unliked Raw Lottie animation played for the Clips like button when the state changes from liked to unliked. If unset, the SDK falls back to the static initial icon. null
theme.player.icons.mute.muted Muted-state icon for the player mute toggle. If mute.unmuted is not set, the packaged Storyteller unmuted icon remains in use. default icon
theme.player.icons.mute.unmuted Unmuted-state icon for the player mute toggle. If mute.muted is not set, the packaged Storyteller muted icon remains in use. default icon
theme.player.icons.captions.enabled Enabled-state icon for the player captions toggle. If captions.disabled is not set, the packaged Storyteller disabled icon remains in use. default icon
theme.player.icons.captions.disabled Disabled-state icon for the player captions toggle. If captions.enabled is not set, the packaged Storyteller enabled icon remains in use. default icon
theme.player.showLikeButton Shows the Like button on Clips. TRUE
theme.player.clips.showButtonBackgrounds Shows the default circular button backgrounds on Clips action buttons. Set to FALSE to render the themed icon assets without SDK-drawn backers. TRUE
theme.player.clips.actionIconSize Size in dp for clip player action icons (like, share, mute, captions). Null means use the default size (32 dp). null
theme.player.clips.topGradient Two-colour paint for the existing top readability scrim. The gradient keeps the current top-chrome bounds. A fully transparent gradient is a valid visual opt-out. 80% black at TopCenter to transparent at BottomCenter
theme.player.clips.bottomGradient Two-colour paint for the existing bottom readability scrim. The gradient keeps its current 120 dp long-screen or 200 dp compact bounds. A fully transparent gradient is a valid visual opt-out. transparent at TopCenter to opaque black at BottomCenter
theme.player.clips.feedSwitcher.selected.fontWeight Font weight for the selected For You / Following label. Null preserves the Settings selectionStyle weight: semi-bold for underline, heavy for textWeight. null (selection style default)
theme.player.clips.feedSwitcher.selected.textSize Text size in SP for the selected For You / Following label. 15
theme.player.clips.feedSwitcher.selected.lineHeight Line height in SP for the selected For You / Following label. 20
theme.player.clips.feedSwitcher.unselected.fontWeight Font weight for the unselected For You / Following label. Null preserves the Settings selectionStyle weight: semi-bold for underline, medium for textWeight. null (selection style default)
theme.player.clips.feedSwitcher.unselected.textSize Text size in SP for the unselected For You / Following label. 15
theme.player.clips.feedSwitcher.unselected.lineHeight Line height in SP for the unselected For You / Following label. 20
theme.player.clips.progressBar.position Progress-bar position for Embedded Clips. BOTTOM keeps the progress bar at the bottom of the media. ABOVE_ACTION keeps separate 16dp clearances from the title/side actions above and a visible primary action below while moving the full scrub target. Clips without a primary action, modal Clips, and ads keep the bottom position. BOTTOM
theme.player.clips.progressBar.playedColor Played-track colour outside active scrubbing. state-specific legacy colour
theme.player.clips.progressBar.remainingColor Remaining-track colour outside active scrubbing. state-specific legacy colour
theme.player.clips.progressBar.active.playedColor Played-track colour while the user is scrubbing. If unset, an explicit base playedColor is inherited. state-specific legacy colour
theme.player.clips.progressBar.active.remainingColor Remaining-track colour while the user is scrubbing. If unset, an explicit base remainingColor is inherited. state-specific legacy colour
theme.player.clips.progressBar.active.currentTimeColor Current-time and separator colour while the user is scrubbing. {theme.colors.white.primary}
theme.player.clips.progressBar.active.totalTimeColor Total-duration colour while the user is scrubbing. {theme.colors.white.secondary}
theme.player.clips.title.font Custom font for the Clips player title. Falls back to the global theme font if null. null (global theme font)
theme.player.clips.title.fontWeight Font weight for the Clips player title. black (900)
theme.player.clips.title.textSize Text size in SP for the Clips player title. 16
theme.player.clips.title.lineHeight Line height in SP for the Clips player title. Null means use the default font line spacing. null (font default)
theme.player.clips.title.textColor Text color for the Clips player title. {theme.colors.white.primary}
theme.player.clips.categoryNavigation.fontWeight Font weight for each Clips category label and its delimiter. regular (400)
theme.player.clips.categoryNavigation.textSize Text size in SP for each Clips category label and its delimiter. 16
theme.player.clips.categoryNavigation.lineHeight Line height in SP for each Clips category label and its delimiter. Null means use the default font line spacing. null (font default)
theme.player.clips.eyebrow.font Custom font for the Clips player eyebrow. Falls back to the global theme font if null. null (global theme font)
theme.player.clips.eyebrow.textSize Text size in SP for the Clips player eyebrow. 15
theme.player.clips.eyebrow.lineHeight Line height in SP for the Clips player eyebrow. Null means use the default font line spacing. 20
theme.player.clips.eyebrow.textColor Text color for the Clips player eyebrow. rgba({theme.colors.white.secondary}, 85%)
theme.player.clips.spacing.backButtonStartInset Left inset in dp for the Clips player back/close button. 0
theme.player.clips.spacing.contentInsetHorizontal Horizontal (start/end) and top padding in dp for the description and action content areas. 16
theme.player.clips.spacing.contentInsetBottom Bottom padding in dp for the description and action content areas. 16
theme.player.clips.spacing.actionSpacing Vertical spacing in dp between action icons (follow, like, share, mute, caption). 12
theme.player.clips.spacing.eyebrowToTitleSpacing Spacing in dp between the eyebrow text and the clip title. 4
theme.player.clips.spacing.titleToActionSpacing Horizontal gap in dp between the title/description text and the action icons column. 16
theme.player.clips.spacing.titleToCategoriesSpacing Embedded Clips minimum vertical gap in dp from the rendered title/description block to categories when both are present. null (current Android layout)
theme.player.clips.spacing.categoriesToMoreSpacing Embedded Clips minimum vertical gap in dp from categories to the existing expansion/collapse affordance when both are present. This does not add a literal More label. null (current Android layout)
theme.player.clips.spacing.metadataToProgressBarSpacing Embedded Clips minimum vertical gap in dp from the metadata block to the visible progress track. null (current Android layout)
theme.player.clips.spacing.progressBarToActionSpacing Embedded Clips minimum vertical gap in dp between the visible progress track and primary-action region. Its meaning is independent of progress/action ordering. null (current Android layout)
theme.player.enableFollowableCategorySwipeFromRightEdge Enables opening the Followable Category screen with a right-edge swipe on Clips. Set to false to disable this gesture. TRUE

Some Clips player behavior is controlled by the tenant Settings theme returned by the Storyteller API rather than by the local SDK UiTheme DSL:

Remote Clips appearance must be nested under the active theme.light.player.clips or theme.dark.player.clips branch. Typography resolves independently for every field in this order: feed Settings, tenant Settings, the host app's local UiTheme, then the existing Android compatibility default. Missing, null, malformed, unknown, or non-positive typography values inherit the next layer. Supported fontWeight names match StorytellerFontWeight, including LIGHT (300).

Settings Theme Description Default Value
theme.behavior.player.clips.enableProfileScreen Enables the newer Clips profile screen for followable-category OpenScreen entries. Missing or null values resolve to false, which keeps the legacy Followable Category screen behavior. Follow/unfollow controls and followable action buttons continue to use their existing behavior. FALSE
theme.behavior.player.clips.modalContentBottomAnchor Controls where lower UI in the modal Clips player is anchored. video keeps the existing video-bottom layout. screen keeps the 9:16 media top-aligned while anchoring the title/metadata, side actions, primary action, and progress/scrubber to the safe screen bottom on taller viewports. Embedded Clips and ads keep their existing layout. Missing, null, malformed, or unknown values resolve to video. video
theme.light.player.clips.progressBar.position / theme.dark.player.clips.progressBar.position Server-delivered Embedded Clips progress position. Supported values are bottom and aboveAction; aboveAction keeps 16dp clearances above and below progress, and invalid values fall back to the local theme. Clips without a primary action, modal Clips, and ads keep the bottom position. local theme, then bottom
theme.light.player.clips.progressBar.playedColor / theme.dark.player.clips.progressBar.playedColor Server-delivered played-track colour outside active scrubbing. local theme, then legacy colour
theme.light.player.clips.progressBar.remainingColor / theme.dark.player.clips.progressBar.remainingColor Server-delivered remaining-track colour outside active scrubbing. local theme, then legacy colour
theme.light.player.clips.progressBar.active.playedColor / theme.dark.player.clips.progressBar.active.playedColor Server-delivered played-track colour while scrubbing. active local theme, explicit base colour, then legacy colour
theme.light.player.clips.progressBar.active.remainingColor / theme.dark.player.clips.progressBar.active.remainingColor Server-delivered remaining-track colour while scrubbing. active local theme, explicit base colour, then legacy colour
theme.light.player.clips.progressBar.active.currentTimeColor / theme.dark.player.clips.progressBar.active.currentTimeColor Server-delivered current-time and separator colour while scrubbing. local theme, then {theme.colors.white.primary}
theme.light.player.clips.progressBar.active.totalTimeColor / theme.dark.player.clips.progressBar.active.totalTimeColor Server-delivered total-duration colour while scrubbing. local theme, then {theme.colors.white.secondary}
theme.light.player.clips.topGradient / theme.dark.player.clips.topGradient Server-delivered override for the top Clips readability gradient using startColor, endColor, startPosition, and endPosition. Inherit
theme.light.player.clips.bottomGradient / theme.dark.player.clips.bottomGradient Server-delivered override for the bottom Clips readability gradient using startColor, endColor, startPosition, and endPosition. Inherit
theme.light.player.clips.spacing.* / theme.dark.player.clips.spacing.* Server-delivered overrides for the four embedded spacing relationships documented above. Values are non-negative dp. Inherit
theme.light.player.clips.feedSwitcher.selected.fontWeight / theme.dark.player.clips.feedSwitcher.selected.fontWeight Server-delivered selected For You / Following label weight. This changes typography only; theme.behavior.following.feedSwitcher.selectionStyle still controls the configured selection mechanism. Inherit
theme.light.player.clips.feedSwitcher.selected.textSize / theme.dark.player.clips.feedSwitcher.selected.textSize Server-delivered selected For You / Following label size in SP. Inherit
theme.light.player.clips.feedSwitcher.selected.lineHeight / theme.dark.player.clips.feedSwitcher.selected.lineHeight Server-delivered selected For You / Following label line height in SP. Inherit
theme.light.player.clips.feedSwitcher.unselected.fontWeight / theme.dark.player.clips.feedSwitcher.unselected.fontWeight Server-delivered unselected For You / Following label weight. Inherit
theme.light.player.clips.feedSwitcher.unselected.textSize / theme.dark.player.clips.feedSwitcher.unselected.textSize Server-delivered unselected For You / Following label size in SP. Inherit
theme.light.player.clips.feedSwitcher.unselected.lineHeight / theme.dark.player.clips.feedSwitcher.unselected.lineHeight Server-delivered unselected For You / Following label line height in SP. Inherit
theme.light.player.clips.title.fontWeight / theme.dark.player.clips.title.fontWeight Server-delivered Clips title weight. The title continues to use the local theme.player.clips.title.font or global theme font. Inherit
theme.light.player.clips.title.textSize / theme.dark.player.clips.title.textSize Server-delivered Clips title size in SP. Inherit
theme.light.player.clips.title.lineHeight / theme.dark.player.clips.title.lineHeight Server-delivered Clips title line height in SP. Inherit
theme.light.player.clips.categoryNavigation.fontWeight / theme.dark.player.clips.categoryNavigation.fontWeight Server-delivered weight shared by every category label and its existing delimiter. Inherit
theme.light.player.clips.categoryNavigation.textSize / theme.dark.player.clips.categoryNavigation.textSize Server-delivered size in SP shared by every category label and its existing delimiter. Inherit
theme.light.player.clips.categoryNavigation.lineHeight / theme.dark.player.clips.categoryNavigation.lineHeight Server-delivered line height in SP shared by every category label and its existing delimiter. Inherit
theme.light.profileScreen.contentAvailability.clips / theme.dark.profileScreen.contentAvailability.clips Enables the existing Latest/Popular Clips grid on the Profile Screen. When Clips and Stories are both enabled, Android waits for both enabled feeds and renders the horizontal Stories row before Clips. If either availability value is missing, null, or both values are false, Android resolves the pair to the defaults. TRUE
theme.light.profileScreen.contentAvailability.stories / theme.dark.profileScreen.contentAvailability.stories Enables the legacy category-details Stories source as a horizontal row on the Profile Screen, with relevance ordering and no Stories Latest/Popular control. A disabled feed is not requested or awaited; if one enabled feed has no content, Android renders only the other enabled feed. FALSE
theme.light.profileScreen.displayTitle.textSize / theme.dark.profileScreen.displayTitle.textSize Profile Screen display-title size in sp. 22
theme.light.profileScreen.displayTitle.lineHeight / theme.dark.profileScreen.displayTitle.lineHeight Profile Screen display-title line height in sp. 28
theme.light.profileScreen.displayTitle.textCase / theme.dark.profileScreen.displayTitle.textCase Profile Screen display-title case: default, lower, or upper. default
theme.light.profileScreen.displayTitle.textColor / theme.dark.profileScreen.displayTitle.textColor Profile Screen display-title color. {theme.colors.white.primary}
theme.light.profileScreen.description.textSize / theme.dark.profileScreen.description.textSize Profile Screen description size in sp. 16
theme.light.profileScreen.description.lineHeight / theme.dark.profileScreen.description.lineHeight Profile Screen description line height in sp. 20
theme.light.profileScreen.description.textCase / theme.dark.profileScreen.description.textCase Profile Screen description case: default, lower, or upper. default
theme.light.profileScreen.description.textColor / theme.dark.profileScreen.description.textColor Profile Screen description color. rgba({theme.colors.white.primary}, 70%)
theme.light.profileScreen.followButton.cornerRadius / theme.dark.profileScreen.followButton.cornerRadius Follow/Unfollow button corner radius in dp. 8
theme.light.profileScreen.followButton.title.textSize / theme.dark.profileScreen.followButton.title.textSize Follow/Unfollow button-label size in sp. 14
theme.light.profileScreen.followButton.title.lineHeight / theme.dark.profileScreen.followButton.title.lineHeight Follow/Unfollow button-label line height in sp. 20
theme.light.profileScreen.followButton.title.textCase / theme.dark.profileScreen.followButton.title.textCase Follow/Unfollow button-label case: default, lower, or upper. default
theme.light.profileScreen.followButton.followed.textColor / theme.dark.profileScreen.followButton.followed.textColor Followed-state label color. {theme.colors.white.primary}
theme.light.profileScreen.followButton.followed.backgroundColor / theme.dark.profileScreen.followButton.followed.backgroundColor Followed-state background color. rgba({theme.colors.white.primary}, 20%)
theme.light.profileScreen.followButton.unfollowed.textColor / theme.dark.profileScreen.followButton.unfollowed.textColor Unfollowed-state label color. {theme.colors.white.primary}
theme.light.profileScreen.followButton.unfollowed.backgroundColor / theme.dark.profileScreen.followButton.unfollowed.backgroundColor Unfollowed-state background color. {theme.colors.primary}
theme.light.profileScreen.tabs.title.textSize / theme.dark.profileScreen.tabs.title.textSize Latest/Popular tab-label size in sp. 20
theme.light.profileScreen.tabs.title.lineHeight / theme.dark.profileScreen.tabs.title.lineHeight Latest/Popular tab-label line height in sp. 24
theme.light.profileScreen.tabs.title.textCase / theme.dark.profileScreen.tabs.title.textCase Latest/Popular tab-label case: default, lower, or upper. default
theme.light.profileScreen.tabs.selectedTextColor / theme.dark.profileScreen.tabs.selectedTextColor Selected tab-label color. The active underline uses {theme.colors.primary}. {theme.colors.white.primary}
theme.light.profileScreen.tabs.unselectedTextColor / theme.dark.profileScreen.tabs.unselectedTextColor Unselected tab-label color. rgba({theme.colors.white.primary}, 70%)

The active light or dark branch is selected from the resolved SDK theme. Clips progress colours accept #RRGGBB and Android alpha-first #AARRGGBB. Each configured value is the final RGBA output and is not multiplied by the legacy progress-state opacity. Feed-specific server fields take precedence over tenant-global server fields, then local UiTheme values. Missing, null, malformed, and invalid-type server values fall back per field without discarding valid siblings. An absent active track colour inherits an explicitly configured base track colour before using the legacy active-state visual. A missing or invalid server position falls back to the local UiTheme; an unset local position resolves to StorytellerClipsProgressBarPosition.BOTTOM.

For Profile Screen fields, missing, null, unknown, non-positive typography values, negative corner radii, and malformed colours also fall back independently, so one invalid value does not discard valid sibling settings.

Clips gradients and the four new embedded spacing fields resolve independently from the active feed-specific server branch, then the tenant/global server branch, then the host UiTheme, and finally the Android compatibility default. An incomplete gradient, unknown position, malformed color, or negative spacing value falls through without discarding valid siblings. Server gradient colors accept #RRGGBB and Android alpha-first #AARRGGBB; all nine GradientPosition values are supported. Explicit zero spacing and transparent-to-transparent gradients are preserved. Integrators remain responsible for choosing gradients that provide sufficient contrast for controls and text.

If you override only one mute or captions state, the missing state falls back to the bundled Storyteller drawable for that control.

Like animations are loaded from res/raw Lottie JSON files via animationRes(R.raw.your_animation). If an animation is not configured for a given transition, the Clips player keeps using the existing static icon swap.

Feed-switcher and category-navigation text inherit theme.font; only the Clips title has its own optional font override. Explicit feed-switcher weights replace the weight selected by the remote selectionStyle without changing underline, crossfade, alpha, or selection behavior. Category typography applies uniformly to every category label and delimiter; the delimiter setting continues to control spacing only. StorytellerFontWeight.LIGHT maps to weight 300.

Example:

theme.light.player {
  clips {
    showButtonBackgrounds = false
    actionIconSize = 38
    topGradient = UiTheme.Theme.Gradient(
      startColor = ofHexCode("#CC001F3F"),
      endColor = ofHexCode("#00001F3F"),
      startPosition = UiTheme.Theme.Gradient.GradientPosition.TopLeft,
      endPosition = UiTheme.Theme.Gradient.GradientPosition.BottomRight,
    )
    bottomGradient = UiTheme.Theme.Gradient(
      startColor = ofHexCode("#00001F3F"),
      endColor = ofHexCode("#FF001F3F"),
      startPosition = UiTheme.Theme.Gradient.GradientPosition.TopCenter,
      endPosition = UiTheme.Theme.Gradient.GradientPosition.BottomCenter,
    )
    feedSwitcher {
      selected {
        fontWeight = StorytellerFontWeight.REGULAR
        textSize = 15
        lineHeight = 20
      }
      unselected {
        fontWeight = StorytellerFontWeight.LIGHT
        textSize = 15
        lineHeight = 20
      }
    }
    progressBar {
      position = StorytellerClipsProgressBarPosition.ABOVE_ACTION
      playedColor = ofHexCode("#CC00C2FF")
      remainingColor = ofHexCode("#663DFFB5")
      active {
        playedColor = ofHexCode("#FFFFD54F")
        remainingColor = ofHexCode("#994C6FFF")
        currentTimeColor = ofHexCode("#FFFFD54F")
        totalTimeColor = ofHexCode("#FF80DEEA")
      }
    }
    title {
      font = fontRes(R.font.my_custom_font)
      fontWeight = StorytellerFontWeight.REGULAR
      textSize = 15
      lineHeight = 20
      textColor = ofHexCode("#FF0000")
    }
    categoryNavigation {
      fontWeight = StorytellerFontWeight.REGULAR
      textSize = 13
      lineHeight = 16
    }
    spacing {
      backButtonStartInset = 12
      contentInsetHorizontal = 16
      contentInsetBottom = 20
      actionSpacing = 20
      eyebrowToTitleSpacing = 6
      titleToActionSpacing = 16
      titleToCategoriesSpacing = 8
      categoriesToMoreSpacing = 4
      metadataToProgressBarSpacing = 16
      progressBarToActionSpacing = 16
    }
  }
  icons {
    back = drawableRes(R.drawable.custom_clips_back)
    like {
      initial = drawableRes(R.drawable.custom_like_initial)
      liked = drawableRes(R.drawable.custom_like_liked)
      animation {
        liked = animationRes(R.raw.custom_like_liked_animation)
        unliked = animationRes(R.raw.custom_like_unliked_animation)
      }
    }
    mute {
      muted = drawableRes(R.drawable.custom_player_mute_muted)
      unmuted = drawableRes(R.drawable.custom_player_mute_unmuted)
    }
    captions {
      enabled = drawableRes(R.drawable.custom_player_captions_enabled)
      disabled = drawableRes(R.drawable.custom_player_captions_disabled)
    }
  }
}

Diagram illustrating player theming

Cards#

The cards property customizes app-side Cards visuals. Cards audio availability is still controlled by the settings endpoint behavior documented in Cards; these theme fields only replace local SDK icons.

Cards Description Default Value Dark Value
theme.cards.audio.mutedIcon Icon used when an audio-capable Card is muted. default muted icon
theme.cards.audio.unmutedIcon Icon used when an audio-capable Card is unmuted. default unmuted icon
theme.cards.audio.unavailableIcon Compatibility-only field. Current Cards UI hides the audio control when a video Card has no available audio, so this icon is not rendered. default no-audio icon

These icons affect only Cards audio controls. Stories and Clips player mute icons still use theme.player.icons.mute. Custom Cards audio icons replace the whole 48 x 48 button visual; the SDK-drawn circular background is only used for packaged default icons.

Example:

theme.light.cards {
  audio {
    mutedIcon = drawableRes(R.drawable.custom_cards_audio_muted)
    unmutedIcon = drawableRes(R.drawable.custom_cards_audio_unmuted)
  }
}

Buttons#

The buttons property applies customizations to buttons which appear throughout the UI.

Buttons Description Default Value Dark Value
theme.buttons.backgroundColor Background color of buttons including: share buttons at the end of Quizzes, primary action buttons in Clips, and action buttons in the Following empty state. {theme.colors.white.primary}
theme.buttons.textColor Text color of buttons including: share buttons at the end of Quizzes, primary action buttons in Clips, and action buttons in the Following empty state. {theme.colors.black.primary}
theme.buttons.textCase Sets the text case for the button on the Instructions Screen, share buttons at the end of Quizzes, primary action buttons in Clips, and action buttons in the Following empty state (TextCase.UPPER/DEFAULT/LOWER). default
theme.buttons.cornerRadius Sets the corner radius for buttons including: Instructions Screen button, share buttons at the end of Quizzes, primary action buttons in Clips, and action buttons in the Following empty state. Any value greater than half the height of the button will create a pill shape. {theme.primitives.cornerRadius}

Instructions#

Use the instructions property to customize the appearance of the instructions screen.

Instructions Description Default Value Dark Value
theme.instructions.show Show the Instructions Screen the first time a user opens Storyteller. Set to FALSE to entirely hide the Instructions screen. TRUE
theme.instructions.headingColor Heading color of the text used on the Instructions Screen. {theme.colors.black.primary} {theme.colors.white.primary}
theme.instructions.headingTextCase Sets the text case for the heading on the Instructions Screen. (TextCase.UPPER/DEFAULT/LOWER). TextCaseTheme.DEFAULT
theme.instructions.headingFont Font to be used on the Instuctions Screen for headers, defaults to the system font System font
theme.instructions.subHeadingColor Subheading color of the text used on the Instructions Screen. {theme.colors.black.secondary} {theme.colors.white.secondary}
theme.instructions.backgroundColor Background color of the Instructions Screen. {theme.colors.white.primary} {theme.colors.black.primary}
theme.instructions.icons A set of icons used for each instruction on the Instructions Screen default set of icons
theme.instructions.button.backgroundColor Background color of the button used on the Instructions Screen. {theme.colors.black.primary} {theme.colors.white.primary}
theme.instructions.button.textColor Text color of the button used on the Instructions Screen. {theme.colors.white.primary} {theme.colors.black.primary}

Diagram illustrating instructions theming

Engagement Units#

The engagementUnits property can be used to customize properties relating to Polls and Quizzes.

Engagement Units Description Default Value Dark Value
theme.engagementUnits.poll.answerTextColor Answer text color used in Poll Answers. {theme.colors.black.primary}
theme.engagementUnits.poll.percentBarColor Background color of the Percentage Bar in Poll Answers. #CDD0DC
theme.engagementUnits.poll.selectedAnswerBorderColor Border color added to the selected Poll Answer. Inherits colors.primary {theme.colors.primary}
theme.engagementUnits.poll.answeredMessageTextColor Color of the vote count or "Thanks for Voting!" message shown to users. {theme.colors.white.primary}
theme.engagementUnits.poll.selectedAnswerBorderImage Border image used for the selected Poll Answer. Overwrites selectedAnswerBorderColor and can be used to create a shimmer animation as the border image is rotated in when an answer is selected. null
theme.engagementUnits.poll.showImageAnswerGradientOverlay Shows the default bottom gradient overlay on image poll answers. Applies only to image polls. TRUE
theme.engagementUnits.poll.showPercentBarBackground Adds a striped background under the percentage bar in Poll Answers. FALSE
theme.engagementUnits.triviaQuiz.correctColor Color used for correct answers in Trivia Quizzes. {theme.colors.success}
theme.engagementUnits.triviaQuiz.incorrectColor Color used for incorrect answers in Trivia Quizzes. {theme.colors.alert}

Diagram illustrating poll theming Diagram illustrating quiz theming

The search property customizes Search suggestions, no-results, results, the Filters sheet, and its Apply button. Every Search typography group except heading.font inherits theme.font; matching suggestion text and section headings retain their existing emphasized semantic weight. Search result headings continue to use theme.lists.title, with theme.font as the font fallback when theme.lists.title.font is not set. Search opened from a Story or Clip player inherits that player's active theme and UI style; Storyteller.openSearch() uses the global theme.

Search property Description Light default Dark default
theme.search.backgroundColor Search screen background. theme.colors.white.primary theme.colors.black.primary
theme.search.backIcon Back icon in Search. bundled icon bundled icon
theme.search.heading.font Font for the Filters sheet title. theme.font theme.font
theme.search.heading.textColor Filters sheet title color. theme.colors.black.primary theme.colors.white.primary
theme.search.heading.textSize Filters sheet title size. 22sp 22sp
theme.search.heading.lineHeight Filters sheet title line height. 28sp 28sp
theme.search.heading.textCase Filters sheet title case. TextCaseTheme.DEFAULT TextCaseTheme.DEFAULT
theme.search.input.backgroundColor Search input background. #EBEBEB #555555
theme.search.input.textColor Entered Search text color. theme.colors.black.primary theme.colors.white.primary
theme.search.input.placeholderTextColor Search placeholder color. theme.colors.black.tertiary theme.colors.white.tertiary
theme.search.input.iconColor Search, clear, and back icon tint. #888888 #EBEBEB
theme.search.input.cornerRadius Search input corner radius. 4dp 4dp
theme.search.input.textSize Search input text size. 18sp 18sp
theme.search.input.lineHeight Search input line height. 24sp 24sp
theme.search.filterButton.backgroundColor Filters icon-button background. transparent transparent
theme.search.filterButton.iconColor Filters icon color. theme.colors.black.primary theme.colors.white.primary
theme.search.filterButton.cornerRadius Filters icon-button corner radius. 4dp 4dp
theme.search.suggestions.textColor Suggestion label color. theme.colors.black.primary theme.colors.white.primary
theme.search.suggestions.iconColor Suggestion leading/trailing icon color. #888888 #EBEBEB
theme.search.suggestions.iconBackgroundColor Suggestion leading-icon background. #EBEBEB #555555
theme.search.suggestions.textSize Suggestion label size. 16sp 16sp
theme.search.suggestions.lineHeight Suggestion label line height. 20sp 20sp
theme.search.noResults.iconColor No-results illustration color. #C5C5C5 #C5C5C5
theme.search.noResults.title.textColor No-results title color. theme.colors.black.primary theme.colors.white.primary
theme.search.noResults.title.textSize No-results title size. 22sp 22sp
theme.search.noResults.title.lineHeight No-results title line height. 28sp 28sp
theme.search.noResults.title.textCase No-results title case. TextCaseTheme.DEFAULT TextCaseTheme.DEFAULT
theme.search.noResults.message.textColor No-results message color. theme.colors.black.tertiary theme.colors.white.tertiary
theme.search.noResults.message.textSize No-results message size. 16sp 16sp
theme.search.noResults.message.lineHeight No-results message line height. 21sp 21sp
theme.search.noResults.message.textCase No-results message case. TextCaseTheme.DEFAULT TextCaseTheme.DEFAULT
theme.search.filters.backgroundColor Filters sheet background. Search background Search background
theme.search.filters.handleColor Filters sheet drag-handle color. #EBEBEB #EBEBEB
theme.search.filters.sectionHeading.textColor Sort/Content Type/Date Posted heading color. theme.colors.black.primary theme.colors.white.primary
theme.search.filters.sectionHeading.textSize Filters section-heading size. 16sp 16sp
theme.search.filters.sectionHeading.lineHeight Filters section-heading line height. 20sp 20sp
theme.search.filters.sectionHeading.textCase Filters section-heading case. TextCaseTheme.DEFAULT TextCaseTheme.DEFAULT
theme.search.filters.option.backgroundColor Unselected option background. #EBEBEB #555555
theme.search.filters.option.textColor Unselected option text color. theme.colors.black.primary theme.colors.white.primary
theme.search.filters.option.borderColor Unselected option border color. transparent transparent
theme.search.filters.option.selectedBackgroundColor Selected option background. option background option background
theme.search.filters.option.selectedTextColor Selected option text color. option text color option text color
theme.search.filters.option.selectedBorderColor Selected option border color. theme.colors.black.primary theme.colors.white.primary
theme.search.filters.option.cornerRadius Option corner radius. 4dp 4dp
theme.search.filters.option.textSize Option text size. 16sp 16sp
theme.search.filters.option.lineHeight Option line height. 20sp 20sp
theme.search.filters.applyButton.backgroundColor Apply-button background. theme.colors.black.primary theme.colors.white.primary
theme.search.filters.applyButton.textColor Apply-button text color. theme.colors.white.primary theme.colors.black.primary
theme.search.filters.applyButton.textCase Apply-button text case. theme.buttons.textCase, then TextCaseTheme.DEFAULT theme.buttons.textCase, then TextCaseTheme.DEFAULT
theme.search.filters.applyButton.cornerRadius Apply-button corner radius. theme.buttons.cornerRadius, then theme.primitives.cornerRadius theme.buttons.cornerRadius, then theme.primitives.cornerRadius

Host-app and server-delivered light/dark Search appearances resolve independently. A valid server field wins over its matching host field; missing, null, malformed, and invalid fields fall back individually, so a partial override does not discard valid siblings. Server colors accept #RRGGBB or Android alpha-first #AARRGGBB values.

Storyteller.theme = buildTheme {
  light {
    search {
      backgroundColor = ofHexCode("#F6F7FB")
      input {
        backgroundColor = ofHexCode("#E8ECF7")
        iconColor = ofHexCode("#305CDE")
        cornerRadius = 4
      }
      filterButton {
        backgroundColor = ofHexCode("#305CDE")
        iconColor = ofHexCode("#FFFFFF")
      }
      suggestions {
        textColor = ofHexCode("#00071B")
        iconBackgroundColor = ofHexCode("#305CDE")
      }
      filters {
        option {
          selectedBackgroundColor = ofHexCode("#305CDE")
          selectedTextColor = ofHexCode("#FFFFFF")
        }
      }
    }
  }
  dark from light
}

Home#

Title Description Default Value Dark Value
theme.home.headerTitle.font Font to be used throughout the UI, defaults to the system font System font
theme.home.headerTitle.textSize Size of the Home Header Title 22sp
theme.home.headerTitle.lineHeight Line height of the Home Header Title 25sp
theme.home.headerTitle.textCase Sets the text case for the Home Header Title. (TextCase.UPPER/DEFAULT/LOWER). TextCaseTheme.DEFAULT
theme.home.headerTitle.textColor Text color of the Home Title colors.black.primary
theme.home.circularTitle.textSize The size of the title for Circular tiles lists.title
theme.home.circularTitle.lineHeight The line height of the title for Circular tiles lists.title
theme.home.gridTitle.textSize The size of the title for tiles in Grid 16sp
theme.home.gridTitle.lineHeight The line height of the title for Grid tiles 22sp
theme.home.singletonTitle.textSize The size of the title for Singleton tile 22sp
theme.home.singletonTitle.lineHeight The line height of the title for Singleton tiles 28sp
theme.home.rectangularTitle.smallTitle.textSize The size of the title for small Rectangular row tiles lists.title
theme.home.rectangularTitle.smallTitle.lineHeight The title line height for the small Rectangular row tiles lists.title
theme.home.rectangularTitle.mediumTitle.textSize The size of the title for medium Rectangular row tiles 16sp
theme.home.rectangularTitle.mediumTitle.lineHeight The title line height for the medium Rectangular row tiles 22sp
theme.home.rectangularTitle.largeTitle.textSize The size of the title for large Rectangular row tiles 18sp
theme.home.rectangularTitle.largeTitle.lineHeight The title line height for the large Rectangular row tiles 24sp

Theme Builder Initialization#

Theme builder is initialized by the buildTheme method lambda passed after the method acts in the builder scope.

import com.storyteller.domain.theme.builders.buildTheme
import com.storyteller.domain.theme.builders.ofHexCode

Storyteller.theme = buildTheme {
  light.colors.primary = ofHexCode("#FF00FF")
}

Accessing Properties in the Builder Scope#

There are 2 equivalent ways of accessing builder properties:

  • By scopes
  buildTheme {
  light {
    instructions {
      button {
        backgroundColor = ofHexCode("#00FF00")
      }
    }
  }
}
  • By properties
  buildTheme {
  light.instructions.button.backgroundColor = ofHexCode("#00FF00")
}

Both approaches produce the same effect.

Light and Dark Builder Variants#

In the builder context two variants are present:

  • light
  • dark

Although they have an identical structure, they are build with the different set of fallbacks. For instance, default theme.tiles.circularTile.title.unreadTextColor will fallback to the default value of theme.colors.black.primary in the light mode or theme.colors.white.primary in the dark mode.

The selection of active themes will be done using current phone UI mode and StorytellerListView.uiStyle property value. See StorytellerListViews for more details.

For coding convenience, if you do not intent use light and dark mode and relay on default fallback you can use from inline method to copy already set values from one theme to the other.

buildTheme {
  light {
    colors {
      primary = ofHexCode("#FF00FF")
      success = ofHexCode("#00FF00")
    }
  }
  dark from light
}

The above code will set all properties of dark to the current state of the light builder. This method is useful to avoid lengthy typing - a common parameter can be assigned one and copied to the other variant.

Setting Properties of Particular Type#

Colors#

Color properties are expected to be Android @ColorInt. They can be initialized with anything that return such type e.g they can be resolved color from resources, Color.argb() Color.BLUE and so on. For convenience, ofHexColor(string) method is provided - it accepts 6 or 8 hex digits prefixed by the #

val red = ofHexColor("#FF0000")
val semiTransparentRed = ofHexColor("#55FF0000")

Note: when using resources colors mind that they are resolved at the moment of building theme, NOT at the moment of accessing.

Drawables#

For the properties accepting StorytellerDrawable type. You can use drawableRes helper method to set a drawable resource.

val myTheme = buildTheme {
  light.engagementUnits.poll.selectedAnswerBorderImage = drawableRes(R.drawable.gradient_border)
}

To disable the default overlay on image poll answers:

val myTheme = buildTheme {
  light.engagementUnits.poll.showImageAnswerGradientOverlay = false
}

Fonts#

To support multiple weights for fonts, a font family xml resource is required. The SDK will automatically select a font for the appropriate weight when needed.

  • Creating a font family resource custom_font.xml
<?xml version="1.0" encoding="utf-8"?>
<font-family xmlns:android="http://schemas.android.com/apk/res/android">
  <font android:fontWeight="200" android:font="@font/my_font_regular" />
  <font android:fontWeight="700" android:font="@font/my_font_bold" />
</font-family>
  • Setting the font family as custom font property theme.font using the helper method fontRes
font = fontRes(R.font.custom_font)

Example#

val storyRowView = StoryRowView(context)

storyRowView.theme = buildTheme {
  light {
    colors {
      primary = ofHexCode("#FF0000")
      success = ofHexCode("#00FF00")
      alert = ofHexCode("#C50511")
    }

    font = fontRes(R.font.custom_font)

    lists {
      row {
        tileSpacing = 8
        startInset = 12
        endInset = 12
      }
      grid {
        tileSpacing = 8
        columns = 2
      }
      enablePlayerOpen = false // Handle tile taps manually via StorytellerDelegates
    }

    tiles {
      title {
        textSize = 11
        lineHeight = 13
        alignment = Gravity.START
      }
      circularTile {
        unreadIndicatorGradient = UiTheme.Theme.Gradient(
          startColor = getColor(R.color.gradient_start),
          endColor = getColor(R.color.gradient_end),
          startPosition = UiTheme.Theme.Gradient.GradientPosition.CenterLeft,
          endPosition = UiTheme.Theme.Gradient.GradientPosition.CenterRight,
        )

        liveChip {
          unreadBackgroundGradient = UiTheme.Theme.Gradient(
            startColor = getColor(R.color.gradient_start),
            endColor = getColor(R.color.gradient_end),
            startPosition = UiTheme.Theme.Gradient.GradientPosition.CenterLeft,
            endPosition = UiTheme.Theme.Gradient.GradientPosition.CenterRight,
          )
          readTextColor = getColor(R.color.read_live_text)
          unreadTextColor = getColor(R.color.unread_live_text)
        }
      }
      rectangularTile {
        padding = 8
        unreadIndicator.alignment = Gravity.END
        unreadIndicator.textColor = ofHexCode("#000FF")
        unreadIndicator.textSize = 11

        liveChip {
          readTextColor = getColor(R.color.read_live_text)
          unreadTextColor = getColor(R.color.unread_live_text)
        }
      }
    }
    buttons.cornerRadius = 24
    buttons.textCase = TextCase.UPPER
    instructions {
      icons {
        forward = drawableRes(R.drawable.ic_forward_light)
        pause = drawableRes(R.drawable.ic_pause_light)
        back = drawableRes(R.drawable.ic_back_light)
        move = drawableRes(R.drawable.ic_move_light)
      }
    }

    home {
      title {
        font = fontRes(R.font.font)
        textCase = TextCaseTheme.LOWER
        textSize = 28
        lineHeight = 28
        textColor = getColor(R.color.rams_storyteller_primary)
      }
    }
  }
  dark from light
}