diff --git a/CHANGELOG.md b/CHANGELOG.md index 3de7f013..61c03413 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,23 @@ All notable changes to the MMCA.Common packages are documented here. The format [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions follow [Semantic Versioning](https://semver.org/) and are derived from git tags by MinVer (see [the published versioning policy](https://ivanball.github.io/docs/guides/common-VERSIONING.html)). +## [1.227.0] - 2026-10-04 + +### Added + +- `RegistrationSettings` (`MMCA.Common.UI`, configuration section `Registration`, bound by `AddUIShared` like `LegalSettings`): `CollectAddress` (default `true`) shows the optional address block on the Register page; a host that stores no address sets it to `false`, which hides the block and skips its validation, so nothing is collected and then dropped. +- `NotificationScopeKey.MetadataKey` (`"scopeKey"`) and `NotificationHubService.NotificationFilter`: a scoped push carries its scope key in the live SignalR metadata, and `NotificationListener` uses the filter with `INotificationScopeProvider` so a notification for another scope (another event, another tenant) neither toasts nor bumps the badge. Unscoped sends and unscoped hosts behave as before. +- Login reads the `error` query parameter (`Login.Error`) that the OAuth completion redirect sets and shows a localized message in the page's alert (`Auth.Login.ExternalError.*`, English and Spanish), where a refused external sign-in used to land on a bare form. + +### Fixed + +- External sign-in with GitHub creates the account. `OAuthControllerBase` reads the display name from `urn:github:name` before `ClaimTypes.Name`, which GitHub maps to the login handle (never a space, so the split produced an empty last name and every first GitHub sign-up was refused with `User.LastName.Empty`). A missing or single-token name now falls back to the non-empty placeholder "User" for whichever part is absent. +- `TermsAcceptanceGate` keeps its consent dialog open across navigation (`CloseOnNavigation = false`). A list page rewrites its own URL right after it loads, and the dialog provider closed every open dialog on that `LocationChanged`, so consent was skipped for the rest of the session. +- The skip link in `MainLayout` stays on the current page: its href resolves against the current path rather than the base href (which navigated to the home page), the interactive click focuses the main region, and `#main-content` is focusable (`tabindex="-1"`). Nav links show a visible `:focus-visible` outline. +- `BiometricGate` signs out through `IAuthUIService.LogoutAsync`, so the auth state is notified and the read and local caches are cleared; it only cleared the tokens, leaving the UI signed in with the previous session's cached data. +- MAUI capability services keep their null/false contracts on any platform failure: `MauiSpeechToTextService`, `MauiShareService`, `MauiScreenshotService` and `MauiMediaPickerService` catch every non-cancellation exception (they caught a few named types, so anything else surfaced as an unhandled error). Speech recognition starts and stops on the main thread, which Android's recognizer requires. +- `QrCodeImage` shrinks to its container (`max-width: 100%; height: auto`), so a large QR code is no longer clipped on a phone. + ## [1.226.0] - 2026-10-04 ### Added diff --git a/Source/Core/MMCA.Common.Shared/PublicAPI.Shipped.txt b/Source/Core/MMCA.Common.Shared/PublicAPI.Shipped.txt index 1d5d120e..e9312d87 100644 --- a/Source/Core/MMCA.Common.Shared/PublicAPI.Shipped.txt +++ b/Source/Core/MMCA.Common.Shared/PublicAPI.Shipped.txt @@ -1077,3 +1077,4 @@ virtual MMCA.Common.Shared.ValueObjects.ValueObject.PrintMembers(System.Text.Str ~override MMCA.Common.Shared.Concurrency.KeyedSemaphoreStripe.Releaser.ToString() -> string ~override MMCA.Common.Shared.Legal.AcceptLegalTermsRequest.Equals(object obj) -> bool ~override MMCA.Common.Shared.Legal.AcceptLegalTermsRequest.ToString() -> string +const MMCA.Common.Shared.Notifications.NotificationScopeKey.MetadataKey = "scopeKey" -> string! diff --git a/Source/Core/MMCA.Common.Shared/PublicAPI.Unshipped.txt b/Source/Core/MMCA.Common.Shared/PublicAPI.Unshipped.txt index 1b635e16..ab058de6 100644 --- a/Source/Core/MMCA.Common.Shared/PublicAPI.Unshipped.txt +++ b/Source/Core/MMCA.Common.Shared/PublicAPI.Unshipped.txt @@ -1,2 +1 @@ #nullable enable -const MMCA.Common.Shared.Notifications.NotificationScopeKey.MetadataKey = "scopeKey" -> string! diff --git a/Source/Presentation/MMCA.Common.UI/PublicAPI.Shipped.txt b/Source/Presentation/MMCA.Common.UI/PublicAPI.Shipped.txt index d36abbe0..3da6b9f0 100644 --- a/Source/Presentation/MMCA.Common.UI/PublicAPI.Shipped.txt +++ b/Source/Presentation/MMCA.Common.UI/PublicAPI.Shipped.txt @@ -1518,3 +1518,12 @@ virtual MMCA.Common.UI.Services.Api.EntityServiceBase void ~override MMCA.Common.UI.Theme.MmcaThemeProviders.BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder) -> void ~override MMCA.Common.UI.Theme.ThemeToggle.BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder) -> void +MMCA.Common.UI.Common.Settings.RegistrationSettings +MMCA.Common.UI.Common.Settings.RegistrationSettings.CollectAddress.get -> bool +MMCA.Common.UI.Common.Settings.RegistrationSettings.CollectAddress.set -> void +MMCA.Common.UI.Common.Settings.RegistrationSettings.RegistrationSettings() -> void +static readonly MMCA.Common.UI.Common.Settings.RegistrationSettings.SectionName -> string! +MMCA.Common.UI.Pages.Auth.Login.Error.get -> string? +MMCA.Common.UI.Pages.Auth.Login.Error.set -> void +MMCA.Common.UI.Services.Notifications.NotificationHubService.NotificationFilter.get -> System.Func?, System.Threading.Tasks.Task!>? +MMCA.Common.UI.Services.Notifications.NotificationHubService.NotificationFilter.set -> void diff --git a/Source/Presentation/MMCA.Common.UI/PublicAPI.Unshipped.txt b/Source/Presentation/MMCA.Common.UI/PublicAPI.Unshipped.txt index 9f645aca..ab058de6 100644 --- a/Source/Presentation/MMCA.Common.UI/PublicAPI.Unshipped.txt +++ b/Source/Presentation/MMCA.Common.UI/PublicAPI.Unshipped.txt @@ -1,10 +1 @@ #nullable enable -MMCA.Common.UI.Common.Settings.RegistrationSettings -MMCA.Common.UI.Common.Settings.RegistrationSettings.CollectAddress.get -> bool -MMCA.Common.UI.Common.Settings.RegistrationSettings.CollectAddress.set -> void -MMCA.Common.UI.Common.Settings.RegistrationSettings.RegistrationSettings() -> void -static readonly MMCA.Common.UI.Common.Settings.RegistrationSettings.SectionName -> string! -MMCA.Common.UI.Pages.Auth.Login.Error.get -> string? -MMCA.Common.UI.Pages.Auth.Login.Error.set -> void -MMCA.Common.UI.Services.Notifications.NotificationHubService.NotificationFilter.get -> System.Func?, System.Threading.Tasks.Task!>? -MMCA.Common.UI.Services.Notifications.NotificationHubService.NotificationFilter.set -> void