This app does serve a functional purpose in that it shows available ride times to Canada's Wonderland
The code within this application is used to show best practices using .NET MAUI & many of the Shiny .NET Libraries.
This data is pulled from ThemeParks WIKI
Note
This app is under constant evolution. I use it as a test ground for many new features I'm creating for my libraries!
This app uses several .NET open source technologies from Shiny
- Shiny Mediator - Documentation
- Shiny Mobile Libraries - Documentation
- Periodic Background Jobs using Shiny.Jobs
- Background GPS using Shiny.Locations
- Geofencing using Shiny.Locations
- Local Notifications using Shiny.Notifications
- Mobile Centric AppSettings.json for Microsoft.Extensions.Configuration using Shiny.Extensions.Configuration
- Shiny MAUI Shell Extensions using Shiny.Maui.Shell - Shell navigation made pleasant
- Shiny Extensions - Tools for making dependency injection and save state easy
- Shiny SqliteDocumentDb - Lightweight SQLite-backed document store for local persistence
- Strongly Typed Localization for IStringLocalizer
The HTTP API to themeparks wiki is generated using Shiny Mediators OpenAPI source generator. Look in the csproj for the following
<ItemGroup>
<MediatorHttp Include="OpenApiRemote"
Uri="https://api.themeparks.wiki/docs/v1.yaml"
Namespace="ShinyWonderland.ThemeParksApi"
ContractPostfix="HttpRequest"
Visible="false" />
</ItemGroup>- Decent AI Generated .NET MAUI pure control set with light & dark modes
- Show ride times (including paid times if available) for Canada's Wonderland whether you are inside the park or now
- Ability to filter out closed rides, & rides that don't have an estimated time
- Smart & Cross Session Persistent Cache for those time your phone goes offline
- Basic parking locator
- Park Hours of Operation
- Geofence notification reminder for entering to remind user to open app (so GPS is enabled) and to set parking area
- GPS based notifications while in the park notifying you if ride times have been reduced - GPS shuts off once outside of park
- Easy example of a navigation service based on Shell without ViewModel lifecycle Shiny MAUI Shell
- Track Ride History
- Distance - Sorting and Display
- Meal Time (Notify on timer passed?) - use Notification Timer (what about distance)
- Link in tabs IF enabled?
- Separate drink & food passes
- Maybe turn this option on in settings instead
- Android maps not setup - users need to setup their own keys and stuff
- Theme park API returns data even park is closed
- Peak times - requires server
- Need weather at current time request
- Wonderland Map
- Restaurant Points with Menu & Prices
- This data does not come back
- Could do manual pins?
Can I run this for my own local
Yessir - open themepark.http and run "ALL PARKS" endpoint. Find your park (if available), copy/paste the entityID and location into the appsettings.json. VOILA
Why broadcast GPS, connectivity, & data refreshes through Mediator
Mediator doesn't need to hook events and then clean them up. Everything is managed with almost zero code
Why use mediator for data calls?
Mediator can cache data with nothing more than configuration in appsettings.json. No layers, no DI hell... just a contract and a single service
What is the purpose of CoreServices? This is over complicated dependency injection stuff!
Is it? Those services are used in pretty much every major class in the app. This helps alleviate the pain of injecting a TON of services in every constructor
This project includes UI automated tests powered by MauiDevFlow, which provides an in-app agent that exposes a CLI for inspecting and interacting with the running app.
- Install the CLI tool:
dotnet tool install --global Redth.MauiDevFlow.CLI- The NuGet package is already integrated -
Redth.MauiDevFlow.Agentis added to the main app project (Debug only) and registered inMauiProgram.cs:
#if DEBUG
builder.AddMauiDevFlowAgent();
#endif- AutomationId attributes are set on all key UI elements across every page for stable element targeting.
- Boot a simulator/emulator:
xcrun simctl boot <UDID> # iOS- Build & deploy the app (keep this running):
dotnet build src/ShinyWonderland/ShinyWonderland.csproj -f net10.0-ios -t:Run -p:_DeviceName=:v2:udid=<UDID>- Wait for the agent to connect:
maui-devflow wait- Run the UI tests:
dotnet test tests/ShinyWonderland.UITests/The UI test suite (tests/ShinyWonderland.UITests/) covers:
- Startup - App loads and navigates from splash to main tab bar
- Navigation - All 6 tabs are reachable via Shell navigation
- Ride Times - Page elements load (timestamp, collection view, refresh, history button)
- Map Ride Times - Map control renders
- Settings - Sort radio buttons, notification switches, display filters, version label
- Parking - Map and toggle parking button
- Meal Times - Drink/food pass buttons and collection view
- Hours - Schedule collection view
- Ride History - Navigated via toolbar button, collection view loads
These tests were generated by having Claude Code:
- Analyze all XAML pages and ViewModels to understand every screen's UI elements
- Add
AutomationIdattributes to all interactive controls - Create a
MauiDevFlowDriverhelper that wrapsmaui-devflowCLI commands - Write xUnit tests that use the driver to navigate, tap, assert, and screenshot each screen
It isn't super pretty, but AI built it. This is about functionality and making shiny code!