Skip to content

Add WinUI 3 and .NET MAUI clients backed by kotlin-native-nuget - #503

Draft
xxfast wants to merge 15 commits into
joreilly:mainfrom
xxfast:ir/winui
Draft

Add WinUI 3 and .NET MAUI clients backed by kotlin-native-nuget#503
xxfast wants to merge 15 commits into
joreilly:mainfrom
xxfast:ir/winui

Conversation

@xxfast

@xxfast xxfast commented Aug 1, 2026

Copy link
Copy Markdown

Summary

Adds first-class .NET clients for People in Space:

  • An unpackaged WinUI 3 application for Windows x64
  • A .NET MAUI host for Windows and Apple-silicon Mac Catalyst
  • A shared, UI-independent C# view-model layer
  • Consumption of the Kotlin Multiplatform data layer through a locally generated PeopleInSpace.Kotlin NuGet package

The MAUI application also lets us build and visually verify the native NuGet integration on macOS without requiring a Windows machine.

Out of scope (for now)

  • Other Windows architectures
  • Intel Macs
  • Graphical ISS map
1 Aug 2026, 14_35_49

xxfast and others added 15 commits August 1, 2026 14:39
0.3.0 maps `kotlin.time.Instant` to `DateTimeOffset` over a single `Int64`,
so `IssState.timestamp` crosses as a scalar and the managed adapter drops its
`FromUnixTimeSeconds` conversion. Still AOT-safe: no handle, no reflection.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KJAtfQDQ9HpwMLh9xPMeRK
`withAndroidTarget()` matches the legacy `KotlinAndroidTarget`, which
`com.android.kotlin.multiplatform.library` never creates, so androidMain sat
outside the group and lost the shared sources. `:common:compileAndroidMain`
and `:app` have been failing on unresolved `dev.johnoreilly.common.viewmodel`
since the source set split; only the Windows and macOS workflows run in CI, so
nothing caught it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KJAtfQDQ9HpwMLh9xPMeRK
Brings back annotation-driven definitions and their compile-time graph check,
undoing the hand-written module DSL this branch had switched to. Every DI file
is byte-identical to main again except `Koin.kt`, which loses the two view
model helpers to `KoinViewModels.kt` because the view models moved source set.

The plugin cannot run on mingwX64 or macosArm64: Kotlin/Native's C adapter
generation NPEs on its generated IR when linking a sharedLib (KT-62984), so it
is excluded from those two compiler plugin classpaths. Neither target uses
Koin, and `PeopleInSpaceClient` already owns its dependencies.

Pinned to 1.0.2. 1.1.0's graph verifier does not follow providers declared on
an `expect` class through to the `actual` and reports them missing.

`KoinGraphTest` resolves the graph at runtime, since the compile-time check
only covers the targets the plugin runs on.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KJAtfQDQ9HpwMLh9xPMeRK
The Windows and macOS clients were duplicated line for line apart from the
ktor engine, which is exactly the kind of copy that drifts. Both now depend on
a `nativeClientMain` source set holding the single client, with
`createPlatformHttpClientEngine` as the only platform seam. macosArm64 keeps
its place under apple; this is a second parent, not a replacement.

The exported C# surface is unchanged: all 23 members still generate.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KJAtfQDQ9HpwMLh9xPMeRK
`Dispatches_state_changes_and_surfaces_refresh_errors` failed about one run in
three. The fake dispatcher, not the view model: it runs the action inline on
the calling thread, so the people and ISS watch loops can both be inside
`InvokeAsync` at once and one loop's exit cleared the shared `IsInvoking` flag
while the other was still dispatching. The real dispatcher serialises onto the
UI thread, so production was never affected.

Depth is now per-thread and the counters interlocked. 0 failures in 25 runs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KJAtfQDQ9HpwMLh9xPMeRK
`LIMITATIONS.md` now opens with the consolidated list of upstream gaps, seven
items ordered by how much of this integration each one deletes, so the plugin
has one place to work from and the rest of the document can shrink as they
land. Each item says what the generator does today, what it costs here, and
whether it is already tracked upstream. The detailed sections below now point
at that list instead of restating the mechanics.

The AOT items were re-verified against the 0.3.0 output rather than the
changelog: `Activator.CreateInstance` and `GetFunctionPointerForDelegate` are
both still there, so the polling adapter stays.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KJAtfQDQ9HpwMLh9xPMeRK
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