# IronServices.Maui MAUI controls and services for IronServices (IronLicensing, IronNotify, IronTelemetry). [![NuGet](https://img.shields.io/nuget/v/IronServices.Maui.svg)](https://www.nuget.org/packages/IronServices.Maui/) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) ## Installation ```xml ``` ## Quick Start ### 1. Register Services ```csharp // MauiProgram.cs builder.Services.AddIronServices(); // Or with custom URLs builder.Services.AddIronServices(options => { options.LicensingUrl = "https://ironlicensing.com"; options.NotifyUrl = "https://ironnotify.com"; options.TelemetryUrl = "https://irontelemetry.com"; }); ``` ### 2. Use Controls ```xaml ``` --- ## Controls | Control | Type | Description | |---------|------|-------------| | [`LoginView`](#loginview) | ContentView | Drop-in login form | | [`LicenseActivationView`](#licenseactivationview) | ContentView | License key entry and activation | | [`AppLogView`](#applogview) | ContentPage | Exception and telemetry log viewer | | [`UserJourneyView`](#userjourneyview) | ContentPage | User journey visualization with Timeline/Tree/Flow modes | --- ### LoginView A drop-in login form for IronServices authentication. **Type:** `ContentView` (embeddable) #### Properties | Property | Type | Default | Description | |----------|------|---------|-------------| | `Client` | `IronServicesClient` | `null` | **Required.** The client instance for authentication. | | `Title` | `string` | `"Sign In"` | Header text above the form. | | `Subtitle` | `string` | `"Enter your credentials..."` | Subheader text. | | `Logo` | `ImageSource` | `null` | Optional logo image. | | `ShowRegisterLink` | `bool` | `true` | Show "Sign Up" link. | | `ShowForgotPasswordLink` | `bool` | `true` | Show "Forgot Password?" link. | #### Events | Event | Args | Description | |-------|------|-------------| | `LoginSuccess` | `LoginSuccessEventArgs` | Fired on successful login. Contains `UserId`, `Email`, `DisplayName`. | | `LoginFailed` | `LoginFailedEventArgs` | Fired on failed login. Contains `Error` message. | | `RegisterRequested` | `EventArgs` | User tapped "Sign Up" link. | | `ForgotPasswordRequested` | `EventArgs` | User tapped "Forgot Password?" link. | #### Example ```csharp // XAML // Code-behind private async void OnLoginSuccess(object sender, LoginSuccessEventArgs e) { await DisplayAlert("Success", $"Welcome, {e.DisplayName}!", "OK"); await Shell.Current.GoToAsync("//main"); } private async void OnRegisterRequested(object sender, EventArgs e) { await Shell.Current.GoToAsync("//register"); } ``` --- ### LicenseActivationView A license key entry and activation form. **Type:** `ContentView` (embeddable) #### Properties | Property | Type | Default | Description | |----------|------|---------|-------------| | `LicenseManager` | `ILicenseManager` | `null` | **Required.** The license manager instance. | | `Title` | `string` | `"Activate License"` | Header text. | | `Subtitle` | `string` | `"Enter your license key..."` | Subheader text. | | `LicenseKey` | `string` | `null` | Pre-filled license key (two-way binding). | | `ShowHelpLink` | `bool` | `true` | Show help link below form. | | `HelpUrl` | `string` | `"https://..."` | URL opened when help tapped. | #### Events | Event | Args | Description | |-------|------|-------------| | `LicenseActivated` | `LicenseActivatedEventArgs` | Activation succeeded. Contains `License` info. | | `ActivationFailed` | `LicenseActivationFailedEventArgs` | Activation failed. Contains `Error` message. | | `HelpRequested` | `EventArgs` | User tapped help link. | #### Methods | Method | Returns | Description | |--------|---------|-------------| | `ValidateAsync()` | `Task` | Validate the entered license key without activating. | #### Example ```csharp // XAML // Code-behind private async void OnLicenseActivated(object sender, LicenseActivatedEventArgs e) { var license = e.License; await DisplayAlert("Activated", $"License: {license.Tier}\nExpires: {license.ExpiresAt:d}", "OK"); } ``` --- ### AppLogView A full-page log viewer for exceptions and telemetry events. Shows queued items from `TelemetryClient.OfflineQueue`. **Type:** `ContentPage` (standalone page, use with NavigationPage) #### Properties | Property | Type | Default | Description | |----------|------|---------|-------------| | `TelemetryClient` | `TelemetryClient` | `null` | Client to pull queued logs from. Auto-refreshes on set. | | `Title` | `string` | `"App Logs"` | Page title (shown in navigation bar). | | `ShowShareButton` | `bool` | `true` | Enable Share toolbar button. | | `ShowClearButton` | `bool` | `true` | Enable Clear toolbar button. | | `EnableLiveUpdates` | `bool` | `false` | Auto-refresh when new items are added (polls every 2s). | #### Events | Event | Args | Description | |-------|------|-------------| | `LogsCleared` | `EventArgs` | User cleared the log list. | | `LogsShared` | `EventArgs` | User shared the logs. | | `LogSelected` | `LogItem` | User selected a log entry. | | `LogsRefreshed` | `EventArgs` | Log list was refreshed. | #### Methods | Method | Returns | Description | |--------|---------|-------------| | `RefreshLogs()` | `void` | Reload logs from TelemetryClient queue. | | `AddLog(type, title, message, stackTrace?)` | `void` | Add a manual log entry. | | `AddException(Exception)` | `void` | Add an exception as a log entry. | | `ClearLogs()` | `void` | Clear displayed logs (not the queue). | | `ClearAllLogs()` | `void` | Clear displayed logs AND the offline queue. | | `ExportLogs()` | `string` | Export all logs as formatted text. | | `GetLogs()` | `IReadOnlyList` | Get current log items. | | `LogCount` | `int` | Number of log items. | #### LogItem Properties | Property | Type | Description | |----------|------|-------------| | `Timestamp` | `DateTime` | UTC timestamp. | | `Type` | `string` | `"exception"`, `"message"`, `"journey_start"`, `"step_start"`, etc. | | `Title` | `string` | Exception type name or message title. | | `Message` | `string` | Log message. | | `StackTrace` | `string?` | Stack trace for exceptions. | | `JourneyId` | `string?` | Associated user journey ID. | | `UserId` | `string?` | Associated user ID. | | `TypeDisplay` | `string` | Short type label: `"ERROR"`, `"MSG"`, `"START"`, etc. | | `TypeColor` | `Color` | Color for type badge. | | `TimestampDisplay` | `string` | Formatted local time (HH:mm:ss). | #### Example ```csharp // Navigate to log view await Navigation.PushAsync(new AppLogView { TelemetryClient = _telemetryClient, Title = "Error Logs", EnableLiveUpdates = true }); // With event handling var logView = new AppLogView { TelemetryClient = _telemetryClient }; logView.LogsCleared += (s, e) => Debug.WriteLine("Logs cleared"); logView.LogSelected += (s, item) => Debug.WriteLine($"Selected: {item.Title}"); await Navigation.PushAsync(logView); // Manual log entries (without TelemetryClient) var logView = new AppLogView(); logView.AddException(ex); logView.AddLog("warning", "Network Issue", "Connection timeout after 30s"); ``` #### Toolbar - **Refresh** (in header): Reloads from queue. - **Share** (Primary): Exports logs as text and opens system share sheet. - **Clear** (Secondary/overflow): Clears displayed logs. --- ### UserJourneyView A full-page user journey viewer with multiple visualization modes. Reconstructs journeys from `TelemetryClient` log items and displays steps, breadcrumbs, exceptions, and metadata. **Type:** `ContentPage` (standalone page, use with NavigationPage) #### View Modes | Mode | Description | |------|-------------| | `Timeline` | Vertical list with nested steps shown with indentation (default). | | `Tree` | Expandable tree hierarchy with collapsible journey/step nodes. | | `Flow` | Horizontal flowchart-style diagram showing step progression. | #### Properties | Property | Type | Default | Description | |----------|------|---------|-------------| | `TelemetryClient` | `TelemetryClient` | `null` | Client to pull journey data from. Auto-refreshes on set. | | `Title` | `string` | `"User Journeys"` | Page title. | | `ViewMode` | `JourneyViewMode` | `Timeline` | Current visualization mode. | | `EnableLiveUpdates` | `bool` | `false` | Auto-refresh when new items are added (polls every 2s). | | `ShowShareButton` | `bool` | `true` | Enable Share toolbar button. | | `ShowClearButton` | `bool` | `true` | Enable Clear toolbar button. | | `UserIdFilter` | `string?` | `null` | Filter to show only journeys for a specific user. | #### Events | Event | Args | Description | |-------|------|-------------| | `JourneySelected` | `JourneyItem` | User selected a journey from the list. | | `StepSelected` | `StepItem` | User selected a step in the detail panel. | | `JourneysRefreshed` | `EventArgs` | Journey list was refreshed. | | `JourneysCleared` | `EventArgs` | Journeys were cleared. | | `JourneysShared` | `EventArgs` | Journeys were exported/shared. | #### Methods | Method | Returns | Description | |--------|---------|-------------| | `RefreshJourneys()` | `void` | Reload journeys from TelemetryClient. | | `ClearJourneys()` | `void` | Clear displayed journeys. | | `ClearAllJourneys()` | `void` | Clear displayed journeys AND the TelemetryClient queue. | | `ExportJourneys()` | `string` | Export all journeys as formatted text. | | `GetJourneys()` | `IReadOnlyList` | Get current journey items. | | `JourneyCount` | `int` | Number of journeys. | #### JourneyItem Properties | Property | Type | Description | |----------|------|-------------| | `JourneyId` | `string` | Unique journey identifier. | | `Name` | `string` | Journey name (e.g., "Checkout Flow"). | | `UserId` | `string?` | Associated user ID. | | `UserEmail` | `string?` | Associated user email. | | `Status` | `JourneyDisplayStatus` | `InProgress`, `Completed`, `Failed`, `Abandoned`. | | `StartTime` | `DateTime` | When the journey started. | | `EndTime` | `DateTime?` | When the journey ended (null if in progress). | | `DurationMs` | `double?` | Duration in milliseconds. | | `DurationDisplay` | `string` | Formatted duration: `"125ms"`, `"2.3s"`, `"1.5m"`. | | `TimeAgo` | `string` | Relative time: `"just now"`, `"5m ago"`, `"2h ago"`. | | `StatusDisplay` | `string` | Human-readable status text. | | `StatusColor` | `Color` | Color for status badge (Blue/Green/Red/Gray). | | `StatusIcon` | `string` | Icon text: `"..."`, `"OK"`, `"X"`, `"-"`. | | `Steps` | `ObservableCollection` | Top-level steps in this journey. | | `Breadcrumbs` | `List` | Breadcrumbs captured during journey. | | `Exceptions` | `List` | Exceptions captured during journey. | | `Metadata` | `Dictionary` | Custom metadata. | | `StepCount` | `int` | Total steps (including nested). | | `FailedStepCount` | `int` | Number of failed steps. | | `HasFailedSteps` | `bool` | Whether any steps failed. | | `HasExceptions` | `bool` | Whether any exceptions occurred. | | `HasUser` | `bool` | Whether a user is associated. | #### StepItem Properties | Property | Type | Description | |----------|------|-------------| | `StepId` | `string` | Unique step identifier. | | `ParentStepId` | `string?` | Parent step ID for nested steps. | | `Name` | `string` | Step name (e.g., "Process Payment"). | | `Category` | `string?` | Category: `"business"`, `"technical"`, `"navigation"`. | | `Status` | `StepDisplayStatus` | `InProgress`, `Completed`, `Failed`, `Skipped`. | | `FailureReason` | `string?` | Reason for failure. | | `StartTime` | `DateTime` | When the step started. | | `EndTime` | `DateTime?` | When the step ended. | | `DurationMs` | `double?` | Duration in milliseconds. | | `DurationDisplay` | `string` | Formatted duration. | | `StatusColor` | `Color` | Color for status indicator. | | `StatusIcon` | `string` | Icon text. | | `ChildSteps` | `ObservableCollection` | Nested child steps. | | `NestingLevel` | `int` | Depth level for indentation. | | `IndentMargin` | `Thickness` | Calculated margin for indentation. | #### BreadcrumbItem Properties | Property | Type | Description | |----------|------|-------------| | `Timestamp` | `DateTime` | When captured. | | `Category` | `string` | Breadcrumb category. | | `Message` | `string` | Breadcrumb message. | | `Level` | `string` | Log level: `"info"`, `"warning"`, `"error"`, `"debug"`. | | `LevelColor` | `Color` | Color based on level. | | `Data` | `Dictionary?` | Additional data. | #### ExceptionItem Properties | Property | Type | Description | |----------|------|-------------| | `Timestamp` | `DateTime` | When captured. | | `ExceptionType` | `string` | Exception type name. | | `Message` | `string` | Exception message. | | `StackTrace` | `string?` | Stack trace. | | `StepId` | `string?` | Step ID where exception occurred. | | `HasStackTrace` | `bool` | Whether stack trace is available. | #### Example ```csharp // Basic usage await Navigation.PushAsync(new UserJourneyView { TelemetryClient = _telemetryClient, EnableLiveUpdates = true }); // With view mode and filtering var journeyView = new UserJourneyView { TelemetryClient = _telemetryClient, ViewMode = JourneyViewMode.Tree, UserIdFilter = currentUser.Id }; await Navigation.PushAsync(journeyView); // Event handling var journeyView = new UserJourneyView { TelemetryClient = _telemetryClient }; journeyView.JourneySelected += (s, journey) => { Debug.WriteLine($"Selected: {journey.Name} ({journey.StepCount} steps)"); }; journeyView.StepSelected += (s, step) => { Debug.WriteLine($"Step: {step.Name} - {step.StatusDisplay}"); }; await Navigation.PushAsync(journeyView); ``` #### Detail Panel When a journey is selected, a detail panel shows: - **Status, Duration, User** - Summary info - **Steps** - List of steps with status indicators and timing - **Breadcrumbs** - Timestamped breadcrumb trail - **Exceptions** - Exception details (tap to copy) - **Metadata** - Key-value pairs - **Copy to Clipboard** - Export journey details #### Toolbar - **Timeline/Tree/Flow** buttons - Switch view modes - **Share** (Primary) - Export journeys as text - **Clear** (Secondary) - Clear displayed journeys - **Refresh** - Reload from TelemetryClient --- ## Services ### MauiSecureTokenStorage Secure token storage using MAUI `SecureStorage`. Automatically registered when using `AddIronServices()`. ```csharp // Automatically used by IronServicesClient builder.Services.AddIronServices(); // Or manually services.AddSingleton(); ``` ### ServiceCollectionExtensions ```csharp // Default URLs services.AddIronServices(); // Custom URLs services.AddIronServices(options => { options.LicensingUrl = "https://licensing.myapp.com"; options.NotifyUrl = "https://notify.myapp.com"; options.TelemetryUrl = "https://telemetry.myapp.com"; }); ``` Registers: - `MauiSecureTokenStorage` as `ITokenStorage` - `IronServicesClient` as singleton --- ## Complete Example ```csharp // MauiProgram.cs public static MauiApp CreateMauiApp() { var builder = MauiApp.CreateBuilder(); builder.UseMauiApp(); // Register IronServices builder.Services.AddIronServices(); // Register TelemetryClient for logging builder.Services.AddSingleton(sp => new TelemetryClient(new TelemetryOptions { Dsn = "your-dsn-here", EnableOfflineQueue = true })); return builder.Build(); } // LoginPage.xaml // LoginPage.xaml.cs public partial class LoginPage : ContentPage { public LoginPage(IronServicesClient client) { InitializeComponent(); LoginControl.Client = client; } private async void OnLoginSuccess(object sender, LoginSuccessEventArgs e) { await Shell.Current.GoToAsync("//main"); } } // SettingsPage.xaml.cs - Navigate to logs private async void OnViewLogsClicked(object sender, EventArgs e) { var telemetry = Handler.MauiContext.Services.GetService(); await Navigation.PushAsync(new AppLogView { TelemetryClient = telemetry, EnableLiveUpdates = true }); } // SettingsPage.xaml.cs - Navigate to journeys private async void OnViewJourneysClicked(object sender, EventArgs e) { var telemetry = Handler.MauiContext.Services.GetService(); await Navigation.PushAsync(new UserJourneyView { TelemetryClient = telemetry, EnableLiveUpdates = true, ViewMode = JourneyViewMode.Timeline }); } ``` --- ## Styling All controls use MAUI resource dictionaries. Override these colors in your `App.xaml`: ```xaml #512BD4 #DFD8F7 #E1E1E1 #C8C8C8 #919191 #6E6E6E #404040 #374151 #1F2937 #212121 #FFFFFF ``` Controls support light/dark themes via `AppThemeBinding`. --- ## Platform Support | Platform | Minimum Version | |----------|-----------------| | Android | API 21 (5.0) | | iOS | 15.0 | | macOS | 15.0 | | Windows | 10.0.17763.0 | --- ## Dependencies - `IronServices.Client` - Core API client - `IronLicensing.Client` - License validation - `IronTelemetry.Client` - Telemetry, journeys, and logging - `Microsoft.Maui.Controls` - MAUI framework --- ## License MIT License - see [LICENSE](LICENSE) file.