Skip to content

Commit a659496

Browse files
authored
Add public IAlertManager and IAlertManagerSubscription interfaces (#34228)
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ## Description Fixes #34104 Custom platform backends (e.g., Linux/GTK) currently have no supported way to implement `DisplayAlert()`, `DisplayActionSheet()`, or `DisplayPromptAsync()`. The entire alert pipeline (`AlertManager`, `IAlertManagerSubscription`) is internal, forcing custom backends to use `DispatchProxy` + heavy reflection to intercept dialog requests. This PR introduces two public interfaces to enable custom platform backends to implement alert dialogs without reflection: ### New Public APIs **`IAlertManager`** — Public interface for the full alert management lifecycle. Custom backends can implement this to completely replace the default `AlertManager`: ```csharp public interface IAlertManager { void Subscribe(); void Unsubscribe(); void RequestAlert(Page page, AlertArguments arguments); void RequestActionSheet(Page page, ActionSheetArguments arguments); void RequestPrompt(Page page, PromptArguments arguments); } ``` **`IAlertManagerSubscription`** — Public interface for platform-specific dialog implementations. The default `AlertManager` already resolves this from DI, so custom backends can register their implementation directly: ```csharp public interface IAlertManagerSubscription { void OnAlertRequested(Page sender, AlertArguments arguments); void OnActionSheetRequested(Page sender, ActionSheetArguments arguments); void OnPromptRequested(Page sender, PromptArguments arguments); } ``` ### Usage Two levels of customization are now available: ```csharp // Simple: Just provide custom dialog implementations builder.Services.AddSingleton<IAlertManagerSubscription, GtkAlertSubscription>(); // Advanced: Replace the entire alert management system builder.Services.AddSingleton<IAlertManager, CustomAlertManager>(); ``` ### Changes - **New:** `IAlertManager` public interface in `Microsoft.Maui.Controls.Platform` - **New:** `IAlertManagerSubscription` public interface (moved from internal nested interface) - **Modified:** `AlertManager` now implements `IAlertManager` - **Modified:** `Window.AlertManager` property typed as `IAlertManager`, resolves custom implementation from DI - **Modified:** Tests updated + 2 new tests for DI resolution - **Updated:** All `PublicAPI.Unshipped.txt` files ### Related - Related PR: #33267 (draft, creates internal `IAlertManager` for #33266) - Real-world use case: [Maui.Gtk GtkAlertManager](https://github.com/redth/Maui.Gtk/blob/main/src/Platform.Maui.Linux.Gtk4/Platform/GtkAlertManager.cs) — 370 lines of reflection that this PR eliminates ---------
1 parent b7c6936 commit a659496

File tree

68 files changed

+10576
-800
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+10576
-800
lines changed

.github/copilot-instructions.md

Lines changed: 59 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,18 @@ Major test projects:
9090

9191
Find all tests: `find . -name "*.UnitTests.csproj"`
9292

93+
### CI Pipelines (Azure DevOps)
94+
95+
When referencing or triggering CI pipelines, use these current pipeline names:
96+
97+
| Pipeline | Name | Purpose |
98+
|----------|------|---------|
99+
| Overall CI | `maui-pr` | Full PR validation build |
100+
| Device Tests | `maui-pr-devicetests` | Helix-based device tests |
101+
| UI Tests | `maui-pr-uitests` | Appium-based UI tests |
102+
103+
**⚠️ Old pipeline names** (e.g., `MAUI-UITests-public`, `MAUI-public`) are **outdated** and should NOT be used. Always use the names above.
104+
93105
### Code Formatting
94106

95107
Always format code before committing:
@@ -126,26 +138,6 @@ When working with public API changes:
126138
- **Use `dotnet format analyzers`** if having trouble
127139
- **If files are incorrect**: Revert all changes, then add only the necessary new API entries
128140

129-
**🚨 CRITICAL: `#nullable enable` must be line 1**
130-
131-
Every `PublicAPI.Unshipped.txt` file starts with `#nullable enable` (often BOM-prefixed: `#nullable enable`) on the **first line**. If this line is moved or removed, the analyzer treats it as a declared API symbol and emits **RS0017** errors.
132-
133-
**Never sort these files with plain `sort`** — the BOM bytes (`0xEF 0xBB 0xBF`) sort after ASCII characters under `LC_ALL=C`, pushing `#nullable enable` to the bottom of the file.
134-
135-
When resolving merge conflicts or adding entries, use this safe pattern that preserves line 1:
136-
```bash
137-
for f in $(git diff --name-only --diff-filter=U | grep "PublicAPI.Unshipped.txt"); do
138-
# Extract and preserve the #nullable enable line (with or without BOM)
139-
HEADER=$(head -1 "$f" | grep -o '.*#nullable enable' || echo '#nullable enable')
140-
# Strip conflict markers, remove all #nullable lines, sort+dedup the API entries
141-
grep -v '^<<<<<<\|^======\|^>>>>>>\|#nullable enable' "$f" | LC_ALL=C sort -u | sed '/^$/d' > /tmp/api_fix.txt
142-
# Reassemble: header first, then sorted entries
143-
printf '%s\n' "$HEADER" > "$f"
144-
cat /tmp/api_fix.txt >> "$f"
145-
git add "$f"
146-
done
147-
```
148-
149141
### Branching
150142
- `main` - For bug fixes without API changes
151143
- `net10.0` - For new features and API changes
@@ -189,16 +181,23 @@ git commit -m "Fix: Description of the change"
189181
2. Exception: If the user's instructions explicitly include pushing, proceed without asking.
190182

191183
### Documentation
192-
193184
- Update XML documentation for public APIs
194185
- Follow existing code documentation patterns
195186
- Update relevant docs in `docs/` folder when needed
196187

197-
**Platform-Specific Documentation:**
198-
- `.github/instructions/safe-area-ios.instructions.md` - Safe area investigation (iOS/macCatalyst)
199-
- `.github/instructions/uitests.instructions.md` - UI test guidelines (includes safe area testing section)
200-
- `.github/instructions/android.instructions.md` - Android handler implementation
201-
- `.github/instructions/xaml-unittests.instructions.md` - XAML unit test guidelines
188+
### Opening PRs
189+
190+
All PRs are required to have this at the top of the description:
191+
192+
```
193+
<!-- Please let the below note in for people that find this PR -->
194+
> [!NOTE]
195+
> Are you waiting for the changes in this PR to be merged?
196+
> It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you!
197+
```
198+
199+
Always put that at the top, without the block quotes. Without it, users will NOT be able to try the PR and your work will have been in vain!
200+
202201

203202

204203
## Custom Agents and Skills
@@ -216,18 +215,24 @@ The repository includes specialized custom agents and reusable skills for specif
216215

217216
### Available Custom Agents
218217

219-
1. **write-tests-agent** - Agent for writing tests. Determines test type (UI vs XAML) and invokes the appropriate skill (`write-ui-tests`, `write-xaml-tests`)
218+
1. **pr** - Sequential 4-phase workflow for reviewing and working on PRs
219+
- **Use when**: A PR already exists and needs review or work, OR an issue needs a fix
220+
- **Capabilities**: PR review, test verification, fix exploration, alternative comparison
221+
- **Trigger phrases**: "review PR #XXXXX", "work on PR #XXXXX", "fix issue #XXXXX", "continue PR #XXXXX"
222+
- **Do NOT use for**: Just running tests manually → Use `sandbox-agent`
223+
224+
2. **write-tests-agent** - Agent for writing tests. Determines test type (UI vs XAML) and invokes the appropriate skill (`write-ui-tests`, `write-xaml-tests`)
220225
- **Use when**: Creating new tests for issues or PRs
221226
- **Capabilities**: Test type determination (UI and XAML), skill invocation, test verification
222227
- **Trigger phrases**: "write tests for #XXXXX", "create tests", "add test coverage"
223228

224-
2. **sandbox-agent** - Specialized agent for working with the Sandbox app for testing, validation, and experimentation
229+
3. **sandbox-agent** - Specialized agent for working with the Sandbox app for testing, validation, and experimentation
225230
- **Use when**: User wants to manually test PR functionality or reproduce issues
226231
- **Capabilities**: Sandbox app setup, Appium-based manual testing, PR functional validation
227232
- **Trigger phrases**: "test this PR", "validate PR #XXXXX in Sandbox", "reproduce issue #XXXXX", "try out in Sandbox"
228-
- **Do NOT use for**: Code review (use `pr-review` skill), writing automated tests (use write-tests-agent)
233+
- **Do NOT use for**: Code review (use pr agent), writing automated tests (use write-tests-agent)
229234

230-
3. **learn-from-pr** - Extracts lessons from PRs and applies improvements to the repository
235+
4. **learn-from-pr** - Extracts lessons from PRs and applies improvements to the repository
231236
- **Use when**: After complex PR, want to improve instruction files/skills based on lessons learned
232237
- **Capabilities**: Analyzes PR, identifies failure modes, applies improvements to instruction files, skills, code comments
233238
- **Trigger phrases**: "learn from PR #XXXXX and apply improvements", "improve repo based on what we learned", "update skills based on PR"
@@ -240,90 +245,79 @@ Skills are modular capabilities that can be invoked directly or used by agents.
240245

241246
#### User-Facing Skills
242247

243-
1. **pr-review** (`.github/skills/pr-review/SKILL.md`)
244-
- **Purpose**: End-to-end PR review orchestrator — follows phase instructions: pr-preflight, pr-gate, try-fix, pr-report
245-
- **Trigger phrases**: "review PR #XXXXX", "work on PR #XXXXX", "fix issue #XXXXX", "continue PR #XXXXX"
246-
- **Capabilities**: Multi-model fix exploration, test verification, alternative comparison, PR review recommendation
247-
- **Do NOT use for**: Just running tests manually → Use `sandbox-agent`
248-
- **Phase instructions** (in `.github/pr-review/`):
249-
- `pr-preflight.md` — Context gathering from issue/PR
250-
- `pr-gate.md` — Verify tests FAIL without fix, PASS with fix
251-
- `pr-report.md` — Final recommendation
252-
- **Phase skill**: `try-fix` — Multi-model fix exploration
253-
254-
3. **issue-triage** (`.github/skills/issue-triage/SKILL.md`)
248+
1. **issue-triage** (`.github/skills/issue-triage/SKILL.md`)
255249
- **Purpose**: Query and triage open issues that need milestones, labels, or investigation
256250
- **Trigger phrases**: "find issues to triage", "show me old Android issues", "what issues need attention"
257251
- **Scripts**: `init-triage-session.ps1`, `query-issues.ps1`, `record-triage.ps1`
258252

259-
4. **find-reviewable-pr** (`.github/skills/find-reviewable-pr/SKILL.md`)
253+
2. **find-reviewable-pr** (`.github/skills/find-reviewable-pr/SKILL.md`)
260254
- **Purpose**: Finds open PRs in dotnet/maui and dotnet/docs-maui that need review
261255
- **Trigger phrases**: "find PRs to review", "show milestoned PRs", "find partner PRs"
262256
- **Scripts**: `query-reviewable-prs.ps1`
263257
- **Categories**: P/0, milestoned, partner, community, recent, docs-maui
264258

265-
5. **pr-finalize** (`.github/skills/pr-finalize/SKILL.md`)
259+
3. **pr-finalize** (`.github/skills/pr-finalize/SKILL.md`)
266260
- **Purpose**: Verifies PR title and description match actual implementation, AND performs code review for best practices before merge.
267261
- **Trigger phrases**: "finalize PR #XXXXX", "check PR description for #XXXXX", "review commit message"
268262
- **Used by**: Before merging any PR, when description may be stale
269263
- **Note**: Does NOT require agent involvement or session markdown - works on any PR
270264
- **🚨 CRITICAL**: NEVER use `--approve` or `--request-changes` - only post comments. Approval is a human decision.
271265

272-
6. **learn-from-pr** (`.github/skills/learn-from-pr/SKILL.md`)
266+
4. **code-review** (`.github/skills/code-review/SKILL.md`)
267+
- **Purpose**: Reviews PR code changes for correctness, safety, and consistency with MAUI conventions. Walks through a MAUI-specific checklist covering handler lifecycle, platform code, safe area, threading, public API, and test patterns.
268+
- **Trigger phrases**: "review code for PR #XXXXX", "code review PR #XXXXX", "review this PR's code"
269+
- **Note**: Standalone skill — uses independence-first assessment (reads code before PR description to avoid anchoring bias). Can be used by any agent or invoked directly.
270+
- **🚨 CRITICAL**: NEVER use `--approve` or `--request-changes` — only post comments. Approval is a human decision.
271+
272+
5. **learn-from-pr** (`.github/skills/learn-from-pr/SKILL.md`)
273273
- **Purpose**: Analyzes completed PR to identify repository improvements (analysis only, no changes applied)
274274
- **Trigger phrases**: "what can we learn from PR #XXXXX?", "how can we improve agents based on PR #XXXXX?"
275275
- **Used by**: After complex PRs, when agent struggled to find solution
276276
- **Output**: Prioritized recommendations for instruction files, skills, code comments
277277
- **Note**: For applying changes automatically, use the learn-from-pr agent instead
278278

279-
7. **write-ui-tests** (`.github/skills/write-ui-tests/SKILL.md`)
279+
6. **write-ui-tests** (`.github/skills/write-ui-tests/SKILL.md`)
280280
- **Purpose**: Creates UI tests for GitHub issues and verifies they reproduce the bug
281281
- **Trigger phrases**: "write UI tests for #XXXXX", "create UI test for issue", "add UI test coverage"
282282
- **Output**: Test files that fail without fix, pass with fix
283283

284-
8. **write-xaml-tests** (`.github/skills/write-xaml-tests/SKILL.md`)
284+
7. **write-xaml-tests** (`.github/skills/write-xaml-tests/SKILL.md`)
285285
- **Purpose**: Creates XAML unit tests for XAML parsing, compilation, and source generation
286286
- **Trigger phrases**: "write XAML tests for #XXXXX", "test XamlC behavior", "reproduce XAML parsing bug"
287287
- **Output**: Test files for Controls.Xaml.UnitTests
288288

289-
9. **verify-tests-fail-without-fix** (`.github/skills/verify-tests-fail-without-fix/SKILL.md`)
289+
8. **verify-tests-fail-without-fix** (`.github/skills/verify-tests-fail-without-fix/SKILL.md`)
290290
- **Purpose**: Verifies UI tests catch the bug before fix and pass with fix
291291
- **Two modes**: Verify failure only (test creation) or full verification (test + fix)
292292
- **Used by**: After creating tests, before considering PR complete
293293

294-
10. **azdo-build-investigator** (`.github/skills/azdo-build-investigator/SKILL.md`)
295-
- **Purpose**: Investigates CI failures for PRs build errors, Helix test logs, and binlog analysis. Delegates to the `ci-analysis` skill from the dotnet/arcade-skills plugin.
296-
- **Trigger phrases**: "check build for PR #XXXXX", "why did PR build fail", "get build status", "what's failing on PR", "Helix failures"
294+
9. **pr-build-status** (`.github/skills/pr-build-status/SKILL.md`)
295+
- **Purpose**: Retrieves Azure DevOps build information for PRs (build IDs, stage status, failed jobs)
296+
- **Trigger phrases**: "check build for PR #XXXXX", "why did PR build fail", "get build status"
297297
- **Used by**: When investigating CI failures
298298

299-
11. **run-integration-tests** (`.github/skills/run-integration-tests/SKILL.md`)
299+
10. **run-integration-tests** (`.github/skills/run-integration-tests/SKILL.md`)
300300
- **Purpose**: Build, pack, and run .NET MAUI integration tests locally
301301
- **Trigger phrases**: "run integration tests", "test templates locally", "run macOSTemplates tests", "run RunOniOS tests"
302302
- **Categories**: Build, WindowsTemplates, macOSTemplates, Blazor, MultiProject, Samples, AOT, RunOnAndroid, RunOniOS
303303
- **Note**: **ALWAYS use this skill** instead of manual `dotnet test` commands for integration tests
304304

305-
12. **evaluate-pr-tests** (`.github/skills/evaluate-pr-tests/SKILL.md`)
306-
- **Purpose**: Evaluates tests added in a PR for coverage, quality, edge cases, and test type appropriateness
307-
- **Trigger phrases**: "evaluate tests in PR #XXXXX", "review test quality", "are these tests good enough", "check test coverage"
308-
- **Scripts**: `Gather-TestContext.ps1`
309-
- **Checks**: Fix coverage, edge case gaps, test type preference (unit > device > UI), conventions, flakiness risk, duplicate coverage, platform scope, assertion quality
310-
311-
#### Internal Skills (Used by Skills/Agents)
305+
#### Internal Skills (Used by Agents)
312306

313-
12. **try-fix** (`.github/skills/try-fix/SKILL.md`)
307+
11. **try-fix** (`.github/skills/try-fix/SKILL.md`)
314308
- **Purpose**: Proposes ONE independent fix approach, applies it, tests, records result with failure analysis, then reverts
315-
- **Used by**: `pr-review` skill Phase 3 (Try-Fix phase) - rarely invoked directly by users
309+
- **Used by**: pr agent Phase 3 (Fix phase) - rarely invoked directly by users
316310
- **Behavior**: Reads prior attempts to learn from failures. Max 5 attempts per session.
317311
- **Output**: Updates session markdown with attempt results and failure analysis
318312

319-
### Using Custom Agents and Skills
313+
### Using Custom Agents
320314

321-
**Delegation Policy**: When user request matches skill/agent trigger phrases, **ALWAYS invoke the appropriate skill or delegate to the agent immediately**. Do not ask for permission or explain alternatives unless the request is ambiguous.
315+
**Delegation Policy**: When user request matches agent trigger phrases, **ALWAYS delegate to the appropriate agent immediately**. Do not ask for permission or explain alternatives unless the request is ambiguous.
322316

323317
**Examples of correct delegation**:
324-
- User: "Review PR #12345" → Immediately invoke **pr-review** skill
318+
- User: "Review PR #12345" → Immediately invoke **pr** agent
325319
- User: "Test this PR" → Immediately invoke **sandbox-agent**
326-
- User: "Fix issue #67890" → Immediately invoke **pr-review** skill
320+
- User: "Fix issue #67890" (no PR exists) → Suggest using `/delegate` command
327321
- User: "Write tests for issue #12345" → Immediately invoke **write-tests-agent**
328322

329323
**When NOT to delegate**:

0 commit comments

Comments
 (0)