ui

Ready-made Jetpack Compose screens, the blocks to build your own, and the design system that themes them.

Every screen is self-contained: give it what to show and a callback, and it fetches, paginates and renders on its own. It never navigates: downloads, saving for later and its own menus are handled in place, and the taps that lead elsewhere are reported through a sealed event type, the destination left to you.

CgsTheme(colorScheme = cgsColorScheme(isSystemInDarkTheme())) {
PublicationScreen(publicationId = id) { event ->
when (event) {
is PublicationEvent.ClickOnIssue -> CGS.reader().open(activity, event.issue.id, event.page)
is PublicationEvent.ClickOnArticle -> CGS.reader().open(activity, event.articles.map { it.id }, event.index)
is PublicationEvent.ClickOnSeeAllArticles -> navigateToArticleList(event.publication.id)
is PublicationEvent.ClickOnSeeAllArchives -> navigateToArchives(event.publication.id)
}
}
}
PublicationScreenA publication: its latest issue with that issue's first articles and its add-ins, then a preview of its archives.
ArticleListScreenEvery article of a publication's latest issue, paginated.
ArchivesScreenEvery archived issue of a publication, year by year.
LibraryScreenThe current profile's downloads, finished or not.
CorporateMediaScreenA corporate media's documents.
VideoMediaScreenVideos across a set of publications.

Blocks

When no screen fits, build your own from blocks. IssuesBlock and ArticlesBlock are sections you drop into your own layout, and BlockPage stacks several of them, with sections of your own, into one scrolling screen. Like a screen, a block fetches, paginates and recovers on its own and never navigates; unlike one, you choose what it shows — its source — and how it is laid out.

BlockPage {
issues(
source = IssuesBlockSource.ofPublications(listOf(publicationId)),
title = "Latest issues",
onEvent = { event ->
if (event is IssuesBlockEvent.ItemClick) CGS.reader().open(activity, event.issue.id, event.page)
}
)
articles(
source = ArticlesBlockSource.ofPublications(listOf(publicationId)),
title = "Latest articles",
limit = 5,
onEvent = { event ->
if (event is ArticlesBlockEvent.ItemClick) {
CGS.reader().open(activity, event.articles.map { it.id }, event.position.index)
}
}
)
}

A page scrolls as one, so a grid or a vertical list in it must be capped with limit, and the page throws for one that is not; a carousel, the issues block's default, needs no cap.

Theming

Wrap anything from this module in CgsTheme. Out of the box it uses the SDK's own palette and type scale; above that:

  • Your brand color — cgsColorScheme(darkTheme, brand, accent) derives a complete scheme from two colors: the other brand tones are rebuilt from the brand's hue and saturation, and the neutral and status tokens stay the SDK's own. Only the text on the accent is picked for contrast, so check how the result reads with your brand.

  • Group by group — lightColorScheme and darkColorScheme take a replacement for any group of the palette. A group is replaced whole, and a replaced brand group does not re-tint the brand tokens of the other groups.

  • The type scale — CgsTheme's typography takes a CgsTypography, whose constructors default every style to the SDK's own, so you can replace one style at a time.

LibraryScreen, CorporateMediaScreen and VideoMediaScreen also take a colors parameter, to re-colour that screen alone without touching the theme. Its constructor takes every color: the defaults are not exposed to start from.

Permissions

This module declares one permission, which the reader engine behind core already brings into your merged manifest:

ACCESS_NETWORK_STATEA block — a section of the publication, article-list or archives screen, or of a BlockPage — that failed for want of a connection reloads itself the moment the connection is back, instead of waiting for the user to hit retry.

It is an install-time permission: the manifest merger adds it to your app, it is never requested at runtime, and the user is never prompted. An app that must not declare it can strip it with tools:node="remove" — the blocks keep working, they simply stop recovering on their own and fall back to the retry they already offer, and the reader stops reloading failed images when the connection comes back.

Packages

Link copied to clipboard

Self-contained sections of content — a shelf of issues, a list of articles — for building a screen of your own. A source says what a block shows and a layout how it is arranged; the block loads, paginates, retries and collapses on its own, and reports taps through a sealed event type without ever navigating. BlockPage stacks several blocks into one scrolling screen, with a single retry, empty state and pull-to-refresh across them.

Link copied to clipboard

Individual pieces — a document row and its list, a video card and its grid — for building a screen the SDK does not already provide. Unlike the screens, these are stateless: you pass the data in and handle the clicks yourself.

Link copied to clipboard

The color sets the components and screens accept. A component left alone reads its set from the current CgsTheme; to re-colour one, build a set with its constructor. Every color is required: the SDK's defaults are not exposed to start from.

Link copied to clipboard

What the stateless components render. Map your own data into these before handing it over.

Link copied to clipboard

The library screen: the current profile's downloads, and the selection mode that deletes them.

The corporate media screen, listing a media's documents.

Link copied to clipboard

The video screen, listing videos across a set of publications.

Link copied to clipboard

The three publication screens: the publication itself, the article list of its latest issue, and its archives. What they report is in co.cafeyn.cgs.api.features.publication.event.

What the three publication screens report, one sealed type per screen: the taps that lead elsewhere, the destination left to you.

Link copied to clipboard

The design system: CgsTheme, the color palette, and the type scale. This is what you touch to make the SDK's screens look like your app.