All posts
Paweł Drojecki

ConnectIQComponents: reusable UI components for Garmin

I built a UI library in Monkey C for Garmin Connect IQ, extracting reusable elements from my watch apps. The library is used in TeaStop and Knitting Counter Pro, with shared components and a customizable theme.

  • Garmin
  • Connect IQ
  • Monkey C
  • Open source
GitHub repository

8 components, one theme

I was repeating code for drawing buttons, cards and indicators in Knitting Counter Pro and TeaStop. I moved these elements into a separate repository called ConnectIQComponents. Version 0.2.0 includes:

Button / OutlineButton
Filled or outlined button with an onPress callback.
Panel / Label
Rounded surface and text truncated to fit the available width.
Badge / Divider
Text badge and a horizontal or vertical separator.
ProgressBar / ProgressRing
Progress from 0 to 1, displayed as a bar or segmented ring.

Each component accepts a position, dimensions, visibility and local styles. The theme defines colors, fonts, spacing and corner radius. Components do not depend on application data or storage.

React inspired props and composition

I pass props in a Monkey C dictionary. The add(child) method nests child components, while setProps() updates their content and appearance. Individual components can override the shared theme using :style props.

A themed button with a text updateMonkey C
var theme = new ConnectIQComponents.Theme({
    :accent => 0xB3DFAC
});
var button = new ConnectIQComponents.Button({
    :text => "Brew tea",
    :x => 80, :y => 220,
    :width => 200, :height => 50,
    :style => {:radius => 25},
    :onPress => method(:startBrewing)
}, theme);

// In the view’s onUpdate(dc):
button.draw(dc, 0, 0);

// After updating application state:
button.setProps({:text => "Done"});
WatchUi.requestUpdate();

startBrewing is an application method. Touch input is forwarded through press() or the ComponentDelegate adapter. Rendering uses Garmin Graphics and WatchUi, and I explicitly request a redraw after state changes. Layout dimensions are in pixels, so the application is responsible for adapting to each screen.

What changed in TeaStop

I added the library as a Git submodule pinned to v0.2.0. The adapter TeaComponents.mc maps TeaStop colors to the library theme and reuses component instances during rendering.

  • The “+ Add”, “Brew tea”, “Options” and time adjustment buttons use Button or OutlineButton.
  • Tea list cards use Panel, and the name editor separator uses Divider.
  • The segmented brewing indicator uses ProgressRing.

TeaStop delegates still handle actions and touch hit testing. Timers, alarms and session storage remain in the app. The integration changes the drawing layer.

Integration checks

Builds passed for Venu 3, fēnix 7S, Venu Sq 2 and Forerunner 965. All 9 simulator tests passed, covering 7 application regression tests and 2 UI adapter tests. I also checked that TeaStop launches in the Venu 3 simulator. Testing on physical watches is still pending.

Using it in another project

The repository is public and licensed under MIT. You can include the source files or build a Monkey Barrel package. For source integration, I add the repository as a submodule, pin a tag and extend monkey.jungle:

base.sourcePath = source;vendor/ConnectIQComponents/source

The library includes documentation, an example app and tests. The API is still experimental, so I pin a specific version and update the dependency deliberately.