Shiny Wonderland

April 30, 2026 · View on GitHub

A production-quality .NET MAUI reference application for Canada's Wonderland that delivers real-time ride wait times, AI-powered park assistance, GPS-based parking, meal-time tracking, and intelligent background notifications — all built on the Shiny ecosystem.

Live ride data is sourced from ThemeParks.wiki.

Note

This app is under active development and serves as both a functional park companion and a living showcase for best practices across the Shiny .NET libraries.


Features

  • Real-Time Ride Wait Times — View current standby and paid wait times for every ride, with distance-based sorting when inside the park
  • Interactive Map — Browse ride locations on a native map with live wait-time pins
  • AI Assistant — Voice-driven AI assistant powered by Microsoft.Extensions.AI with animated phase feedback (listening, thinking, speaking)
  • Parking Locator — Save your parking location via GPS, capture a photo of your spot with zoomable image viewer, and clear it when you leave
  • Meal-Time Tracking — Track food and drink pass usage with countdown timers
  • Park Hours — View daily hours of operation at a glance
  • Ride History — Log rides you've been on and review your history across visits
  • Smart Caching — Cross-session persistent caching keeps the app functional when connectivity drops
  • Background Notifications — GPS-driven alerts when ride wait times drop, geofence reminders on park entry/exit, and automatic GPS shutdown outside the park to save battery
  • Light & Dark Mode — Fully themed UI across all screens

Screenshots

Ride TimesMapAI Assistant
Ride TimesMapAI
ParkingMeal TimesSettings
ParkingMeal TimesSettings

Technology Stack

Libraries

LibraryDescriptionLinks
Shiny.Mediator.MauiIn-process mediator with middleware pipeline, caching, offline support, and MAUI lifecycle integrationGitHub · Docs
Shiny.LocationsBackground GPS tracking and geofencing with automatic lifecycle managementGitHub · Docs
Shiny.JobsPeriodic background jobs that survive app restartsGitHub · Docs
Shiny.NotificationsCross-platform local notificationsGitHub · Docs
Shiny.Extensions.ConfigurationMobile-friendly appsettings.json for Microsoft.Extensions.ConfigurationGitHub · Docs
Shiny.Maui.ShellStrongly-typed Shell navigation with ViewModel lifecycle and route source generationGitHub
Shiny.Maui.ControlsMAUI controls including zoomable ImageViewer and floating panelsGitHub
Shiny.Extensions.MauiHostingStreamlined DI registration and saved-state helpersGitHub
Shiny.Extensions.Localization.GeneratorSource generator for strongly-typed IStringLocalizer accessGitHub
Shiny.DocumentDb.SqliteLightweight SQLite-backed document store for local persistenceGitHub
Shiny.ReflectorSource-generated reflection metadata for settings and configuration bindingGitHub
Microsoft.Extensions.AIUnified AI abstraction layer for model integrationDocs
Microsoft.Extensions.AI.OpenAIOpenAI provider for Microsoft.Extensions.AINuGet
CommunityToolkit.MauiEssential MAUI controls, converters, and behaviorsGitHub · Docs
CommunityToolkit.MvvmSource-generated MVVM infrastructure (ObservableProperty, RelayCommand)GitHub · Docs
Sentry.MauiCrash reporting and performance monitoringGitHub · Docs
Microsoft.Maui.Controls.MapsNative map controls for iOS, Android, and Mac CatalystDocs

Dev & Test

LibraryDescriptionLinks
Redth.MauiDevFlow.AgentIn-app agent for UI automation, visual tree inspection, and CLI-driven testingGitHub
TUnitModern .NET test framework with source-generated test discoveryGitHub
ShouldlyHuman-readable assertion libraryGitHub
ImposterLightweight HTTP mocking for integration testsNuGet

Key Architectural Patterns

Source-Generated HTTP Client — The ThemeParks.wiki API client is generated at compile time from the OpenAPI spec via Shiny Mediator:

<MediatorHttp Include="OpenApiRemote"
              Uri="https://api.themeparks.wiki/docs/v1.yaml"
              Namespace="ShinyWonderland.ThemeParksApi"
              ContractPostfix="HttpRequest"
              Visible="false" />

Mediator-Driven Architecture — All data calls, GPS events, connectivity changes, and AI interactions flow through Shiny Mediator. Caching, offline support, and error handling are applied via middleware configuration in appsettings.json — no manual wiring required.

Composable ViewModel Services — Shared services (navigation, dialogs, mediator, localization) are bundled into ViewModelServices to reduce constructor injection noise across ViewModels.


Getting Started

Run for Your Own Park

  1. Open themepark.http and run the ALL PARKS endpoint
  2. Find your park's entityId and coordinates
  3. Update appsettings.json with those values
  4. Build and run

Prerequisites

  • .NET 10 SDK
  • Xcode 26+ (iOS/Mac Catalyst) or Android SDK 36+ (Android)

UI Testing with MauiDevFlow

This project includes automated UI tests powered by MauiDevFlow.

# Install the CLI
dotnet tool install --global Redth.MauiDevFlow.CLI

# Boot simulator & deploy
xcrun simctl boot <UDID>
dotnet build src/ShinyWonderland/ShinyWonderland.csproj -f net10.0-ios -t:Run -p:_DeviceName=:v2:udid=<UDID>

# Wait for agent & run tests
maui devflow wait
dotnet test tests/ShinyWonderland.UITests/

The test suite covers startup, tab navigation, ride times, map, settings, parking, meal times, hours, and ride history.


Known Issues

  • Android maps require manual API key configuration
  • ThemeParks API may return data when the park is closed

FAQ

Can I run this for a different park? Yes — find your park via the ThemeParks.wiki API, copy the entityId and coordinates into appsettings.json, and you're set.

Why route GPS, connectivity, and data refreshes through Mediator? Mediator handles subscription lifecycle automatically — no manual event hookup or cleanup. Everything is managed with near-zero boilerplate.

Why use Mediator for data calls? Mediator enables persistent caching, offline fallback, and middleware pipelines through configuration alone — no service layers or DI complexity.