Niddy.Core
1.0.2
See the version list below for details.
dotnet add package Niddy.Core --version 1.0.2
NuGet\Install-Package Niddy.Core -Version 1.0.2
<PackageReference Include="Niddy.Core" Version="1.0.2" />
<PackageVersion Include="Niddy.Core" Version="1.0.2" />
<PackageReference Include="Niddy.Core" />
paket add Niddy.Core --version 1.0.2
#r "nuget: Niddy.Core, 1.0.2"
#:package Niddy.Core@1.0.2
#addin nuget:?package=Niddy.Core&version=1.0.2
#tool nuget:?package=Niddy.Core&version=1.0.2
<p align="center"> <img src="https://raw.githubusercontent.com/vonderborch/Niddy/main/assets/branding/niddy-package-icon.png" alt="Niddy logo" width="160" height="160" /> </p>
Niddy
This is my personal utility library. It's public in case it's useful to someone, but it's built for my own projects first: APIs may change between versions, and issues or PRs may not get a response. Use it, fork it, or borrow from it freely (MIT).
A collection of general-purpose .NET utilities and Avalonia UI helpers, split into focused NuGet packages so you only pull in what you need.
Packages
dotnet add package Niddy.Core
dotnet add package Niddy.Avalonia
dotnet add package Niddy.Avalonia.Generators # optional: automatic page registration
Alternatively, clone this repo and reference the relevant project(s) directly.
Features
Niddy.Core
- Helpers (
Niddy.Helpers): byte manipulation, disposing utilities, IO/path/stream/URL helpers, JSON helpers, list extensions, string extensions, and retry-with-exponential-backoff (sync and async) - Threading (
Niddy.Threading): lock-freeGuard(atomic boolean flag) andAtomicOperations, plusDebouncerandThrottlerfor bursty events (sync or async actions,TimeProvider-driven, posting back to the captured synchronization context) - Results (
Niddy.Results):Result,Result<T>andOption<T>value types withMatch/Map/Bind,Result.Try/TryAsyncand anErrorrecord - Humanize (
Niddy.Helpers): file sizes (1.5 MB), counts (12.3K), durations (5 min 3 s), relative times (3 minutes ago), plurals and ordinals - Files (
Niddy.IO):AtomicFilewrites (temp file + replace, so a crash never leaves half a file),DebouncedFileWatcher(one batchedChangedevent per burst), andAppPathsfor per-platform data, config, cache and log folders - Logging (
Niddy.Logging): a rolling file logger forMicrosoft.Extensions.Logging(AddFile,NiddyLogging.CreateFactory) - Settings (
Niddy.Settings):SettingsStore<T>, a typed JSON settings file with atomic saves,Update/Reset, and optional reload on external changes - Secure storage (
Niddy.Security): platform-native secure storage viaISecureStorage— macOS Keychain, Windows Credential Manager, Linux Secret Service, with an encrypted-file fallback;SecureStorageFactoryauto-selects the right implementation
Niddy.Avalonia
- App setup (
Niddy.Avalonia.Hosting): derive yourAppfromNiddyAppand configure pages, dialogs, toasts, theme and the main window in oneConfiguremethod. It decides between desktop and mobile mode itself (or you setMode) and builds the right shell, so you only write pages, never windows - Dialog system (
Niddy.Avalonia.Dialogs):Dialogstatic facade for Notification, Confirmation, Warning, Input, MultiInput, Progress, Selection, Exception, Color, Markdown, Table and Web dialogs. Each dialog is one control, shown either as an overlay card or in a modal window (DialogDisplayMode.Autopicks); derive fromDialogBase<TResult>and callDialog.Showfor your own dialogs. Every dialog inherits the same title, description and button-row layout fromDialogLayout. Window dialogs take an optional fixedwindowWidthandwindowHeight. Escape, the window close button, and the platform back request act as the cancel button - Page system (
Niddy.Avalonia.PageSystem): derive pages fromPageorPage<TAppDataContext, TPageDataContext>, register them explicitly or automatically with the generator (including pages in referenced projects and plugin assemblies loaded at runtime), and show them in aPageViewwith a back stack, parameters, lifecycle hooks, navigation guards, kept-alive pages, nested child views and page transitions. Pages can declare keyboard shortcuts (Shortcut = "Primary+1") - Data contexts (
Niddy.Avalonia.DataContexts):DataContextBase, a ReactiveUI base class for a view's data context withIsBusy/ErrorMessageand aRunAsynchelper - Toasts:
Toast.Showover aToastHost, shown at any of eight screen positions (ScreenPlacement), with a separate placement for mobile and narrow windows. Toasts can carry an action button (Undo, Retry…), repeated toasts merge into one with a count, andToast.ShowProgressshows a progress toast you update and complete - File pickers:
FilePickerreturnsIStorageFile/IStorageFolderhandles, with desktop-only*Pathvariants - Window and layout memory (
Niddy.Avalonia.State): windows reopen at their last size, position and state (kept on screen if a monitor went away), andGrid/ProportionalStackPanelsplitters keep their sizes, viaWindowMemory.Key/LayoutMemory.Keyattached properties - Global exception handler (
Niddy.Avalonia.Hosting): logs UI-thread, unobserved-task and background-thread exceptions and showsDialog.Exceptioninstead of crashing - Converters and markup (
Niddy.Avalonia.Converters): enum-to-bool (radio buttons), bool-to-value, humanize and collection-emptiness converters,{niddy:EnumValues}, and oneniddyXAML namespace for everything - Responsive layout (
Niddy.Avalonia.Layout):Responsive.NarrowBelow/WideAboveaddnarrow/medium/wideclasses by width for styles to target
Desktop, mobile, and browser
Everything works on desktop. For mobile and browser apps (a single view, no windows):
- With
NiddyAppthis is already set up. Otherwise, wrap your main view's content in aDialogOverlayHost(and aToastHostfor toasts). Dialogs then open as overlays, includingDialog.Exception; without a host, dialogs throw a clearInvalidOperationExceptionbecause there's no window to open. - Use the
FilePickermethods that return storage handles; the*Pathvariants return null there. - The platform back request (Android back button, browser back) dismisses an open overlay dialog first, then goes back a page in the most recently attached
PageView. SetHandleBackRequests="False"on aPageViewto opt out. - Overlay dialogs and toasts stay clear of safe-area insets (notch, status and navigation bars) and the on-screen keyboard.
Documentation
Full docs live in docs/: a page per class, with examples, organized by package and folder.
- Docs index: every class in Niddy.Core, Niddy.Avalonia and the generator.
- Walkthroughs that span several classes:
- AI-GUIDE.md: one file that explains how to use the whole library, written for AI coding assistants (and handy for people too). Point your assistant at it.
Quick start
An Avalonia app is an App class deriving from NiddyApp, plus pages:
using Niddy.Avalonia.Hosting;
using Niddy.Avalonia.PageSystem;
public class App : NiddyApp
{
protected override void Configure(NiddyAppOptions options)
{
options.Title = "My App";
options.StartingPage = HomePage.PageId;
options.AppDataContext = new MainDataContext();
options.Layout = pages => new PageMenu { Content = pages }; // optional navigation menu
}
}
// Registered at compile time by Niddy.Avalonia.Generators
[PageRegistration(DisplayName = "Home", Shortcut = "Primary+1")]
public partial class HomePage : Page<MainDataContext, HomePageDataContext>
{
public HomePage() => InitializeComponent();
}
// Program.cs (desktop)
AppBuilder.Configure<App>().UsePlatformDetect().StartWithClassicDesktopLifetime(args);
Then, from any page:
using Niddy.Avalonia.Dialogs;
using Niddy.Avalonia.Toast;
if (await Dialog.Warning.Open(this, "Delete project?", "This can't be undone.", yesButtonText: "Delete"))
{
DeleteProject();
Toast.Show(this, "Project deleted", actionText: "Undo", action: RestoreProject);
}
NavigateTo<SettingsPage>();
And Niddy.Core, in any app:
using Niddy.IO;
using Niddy.Logging;
using Niddy.Security;
var paths = AppPaths.For("MyApp").EnsureCreated(); // per-platform data, config, cache, log folders
using var loggerFactory = NiddyLogging.CreateFactory(paths); // rolling log files in paths.Logs
ISecureStorage secrets = SecureStorageFactory.Create(paths.Data, "MyApp"); // keychain / credential manager
secrets.SetToken("api-key", key);
See the docs for everything else.
Development
Requires the .NET 10 SDK (pinned in global.json).
The packages live under src/, and each has a test project under tests/ (xUnit v3; the Avalonia tests run headless, and the generator tests run the generator on in-memory compilations). tests/Fixtures/ holds small page libraries the tests reference or load at runtime. Run them all with dotnet test.
- Clone or fork the repo
- Create a new branch
- Code!
- Push your changes and open a PR
- Once approved, they'll be merged in
- Profit!
Releasing
All packages share one SemVer 2 version, taken from the GitHub release tag.
- Create a GitHub release with a tag like
v1.2.0(orv1.3.0-beta.1for a pre-release; the leadingvis optional) - Publishing the release runs the publish workflow, which runs the tests, then packs every project at that version and pushes it to NuGet
Publishing uses nuget.org trusted publishing, so no API key is stored in the repo. It needs, once:
- a trusted publishing policy on nuget.org (your username → Trusted Publishing) for owner
vonderborch, repositoryNiddyand workflow filenuget-publish.yml - a
NUGET_USERrepository secret holding the nuget.org profile name that owns the packages
Local builds are versioned 0.0.0-dev.
Future Plans
See list of issues under the Milestones: https://github.com/vonderborch/Niddy/milestones
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- CommunityToolkit.HighPerformance (>= 8.4.2)
- Microsoft.Extensions.Logging (>= 10.0.12)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Niddy.Core:
| Package | Downloads |
|---|---|
|
Niddy.Avalonia
Niddy: my personal .NET utilities. Avalonia UI helpers: app hosting, dialogs (window and overlay, including color, markdown, table and web), a page system with menus and keyboard shortcuts, toasts with actions and progress, window and layout memory, a global exception handler, converters, responsive layout, theming and file pickers. |
GitHub repositories
This package is not used by any popular GitHub repositories.