Livery Server-driven Remote Compose templates GitHub

Live content#

In one line: the app pushes its own live values (a thermostat, a score, a timer) into a template, and people can install skins that draw the same data differently.

This is the Home Assistant case: cards are templates, entity states are the data, and skins are designs people install.

How it fits#

1. Draw with live data#

val state by viewModel.kitchen.collectAsState()
var chosenSkin by rememberSaveable { mutableStateOf<String?>(null) }
// The key is everything the plan reads: new data or a newly chosen skin replans the slot.
LiverySlot(key = state to chosenSkin, host = host, fallback = { NativeTile(state) }) {
  planner.forAppData(
    TemplateQuery("live/status-tile@1", inApp, designId = chosenSkin),
    buildJsonObject { put("name", state.name); put("state", state.label); put("is_on", state.on) },
  )
}

2. Let people pick a skin#

val designs = rememberDesigns(repository, "live/status-tile@1") // refreshes after installs
DesignPicker(designs, onChoose = { d ->
  scope.launch { if (d.installed || repository.install(d.design.id)) chosenSkin = d.design.id }
}, preview = { d -> AsyncImage(d.previews.firstOrNull()?.url, null) })

repository.preview(designId, query) plays a design once without installing it, so the picker can show it live with the person's own data.

3. A design for one item#

A design can be tagged for one item or group (a keynote, a track) and drawn only there. Pass the queries most specific first: the first that has a template decides, in one pass over the catalog, and the plain query draws everything else.

planner.forAppData(
  listOf(
    query.copy(tags = mapOf("session" to session.id)),
    query.copy(tags = mapOf("track" to session.track)),
    query,
  ),
  data,
)

Give each tagged design a variant of its own (variant = "track"), so the plain query's default design still wins for every other item. See PROTOCOL.md §5.4.

4. Bundle a fallback catalog#

Build the same catalog into the app's assets with the ee.schimke.composeai.livery.catalog Gradle plugin, and pass AndroidBundled.fromAssets(context) as the repository's bundled. A first launch with no network then still draws the built-in design. See Hosting.

Deployment checklist#

Edit this page