Skip to content

feat: declare the module's settings with settingsSchema() - #28

Merged
pierrejochem merged 1 commit into
mainfrom
feat/plugin-settings-schema
Oct 4, 2026
Merged

pierrejochem merged 1 commit into
mainfrom
feat/plugin-settings-schema

Conversation

@pierrejochem

@pierrejochem pierrejochem commented Oct 4, 2026 •

Copy link
Copy Markdown
Owner

Change

Mirrors pierrejochem/SpeculumSmartMirror#83 on the reference module.

The Speculum admin console used to render every module option as a raw key/value text row, because nothing told it what a module understands. Modules now declare their own options through ModuleFactory.settingsSchema(), and the console renders typed controls from that declaration.

ExampleModuleFactory declares the two keys the module reads:

override fun settingsSchema(): List<SettingSpec> =
    listOf(
        SettingSpec(
            key = "greeting",
            label = "Greeting",
            default = "Hello, Speculum!",
            help = "Headline text shown at the top of the module.",
        ),
        SettingSpec(
            key = "tickStep",
            label = "Tick step",
            type = SettingType.INT,
            default = "1",
            min = 1,
            max = 100,
            help = "How much the refresh counter advances on each refresh.",
        ),
    )

Each default is the fallback ExampleModule itself reads, which is what the console shows as a hint while a key is unset — deliberately not the same as the starting value defaultConfig() ships. The README gains a Module settings section explaining that distinction and listing the available types.

API version

This needs SettingSpec, SettingType and ModuleFactory.settingsSchema(), so mirrorApi moves from 1.2.2 to 1.3.0 in gradle/libs.versions.toml.

That version is not published yet. CI will fail to resolve org.speculum:mirror-api:1.3.0 until a Speculum release tag publishes it to GitHub Packages. If the next release is numbered differently, that one line is the only change needed.

settingsSchema() has a default empty implementation upstream, so declaring nothing stays valid for modules that do not want typed controls — this PR adopts the new SPI because the example module is the reference for how to write one.

Verification

./gradlew build green — compile, ktlint, detekt and tests — against mirror-api:1.3.0 published to the local Maven repository from the companion branch. Re-run after rebasing onto main (Kotlin 2.4.20, Compose 1.12.1, Gradle 9.8.0), all 16 tasks executed from clean.

ExampleModuleFactoryTest goes from 3 tests to 6: the schema covers every key defaultConfig() ships, the declared types/defaults/bounds match the documented ones, and every entry carries a label and help text.

The Speculum admin console used to render every module option as a raw
key/value text row, because nothing told it what a module understands. Modules
now declare their own options, and the console renders controls from that
declaration.

`ExampleModuleFactory` implements `settingsSchema()` for the two keys the module
reads: `greeting` as a string and `tickStep` as a bounded int, each with the
default the module code itself falls back to and a line of help text. Being the
reference module, it should demonstrate the current shape of the SPI.

This needs `SettingSpec`, `SettingType` and `ModuleFactory.settingsSchema()`,
added in mirror-api 1.3.0, so `mirrorApi` moves from 1.2.2 to 1.3.0. The method
has a default empty implementation upstream, so declaring nothing stays valid
for modules that do not want typed controls.
@pierrejochem
pierrejochem force-pushed the feat/plugin-settings-schema branch from 3450b4e to 463fcf4 Compare October 4, 2026 11:32
@pierrejochem
pierrejochem merged commit bb4b8aa into main Oct 4, 2026
1 of 2 checks passed
@pierrejochem
pierrejochem deleted the feat/plugin-settings-schema branch October 4, 2026 11:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant