diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 80543cae..0c5f8290 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -112,6 +112,12 @@ jobs: with: global-json-file: tooling/global.json + # Run from ./tooling so global.json scopes the install to the pinned SDK feature + # band; otherwise the workloads land on the runner's newer preinstalled SDK. + - name: Install .NET workloads + working-directory: tooling + run: dotnet workload install wasm-tools + - name: .NET Info (if diagnostics) if: ${{ env.ENABLE_DIAGNOSTICS == 'true' }} run: dotnet --info @@ -151,6 +157,14 @@ jobs: # WinUI 3 not supported on uwp - winui: 3 multitarget: uwp + include: + # The Uno.Sdk head replaces the classic Wasm head on WinUI 3, so it rides on the + # existing wasm/winui3 job as a flag rather than a fake entry in the multitarget axis. + # GenerateSingleSampleHeads.ps1 derives the same thing itself (wasm + WinUI 3); this flag + # only drives which CI steps run below (workloads, build command), not the script's own behavior. + - winui: 3 + multitarget: wasm + unoSdkHead: true env: HEADS_DIRECTORY: tooling/ProjectHeads @@ -180,6 +194,13 @@ jobs: with: global-json-file: tooling/global.json + # Run from ./tooling so global.json scopes the install to the pinned SDK feature + # band; otherwise the workloads land on the runner's newer preinstalled SDK. + - name: Install .NET workloads + if: ${{ matrix.multitarget == 'wasm' }} + working-directory: tooling + run: dotnet workload install wasm-tools ${{ matrix.unoSdkHead && 'android ios maui' || '' }} + - name: .NET Info (if diagnostics) if: ${{ env.ENABLE_DIAGNOSTICS == 'true' }} run: dotnet --info @@ -217,8 +238,17 @@ jobs: - name: Add project heads to ${{ env.TEST_PROJECT_NAME }} working-directory: ./${{ env.TEST_PROJECT_DIRECTORY }} - run: ${{ github.workspace }}/${{ env.HEADS_DIRECTORY }}/GenerateSingleSampleHeads.ps1 -MultiTargets ${{ matrix.multitarget }} -winui ${{ matrix.winui }} -componentPath "${{ github.workspace }}/${{ env.TEST_PROJECT_DIRECTORY }}"${{ env.ENABLE_DIAGNOSTICS == 'true' && ' -UseDiagnostics' || '' }} - + run: >- + ${{ github.workspace }}/${{ env.HEADS_DIRECTORY }}/GenerateSingleSampleHeads.ps1 + -MultiTargets ${{ matrix.multitarget }} + -winui ${{ matrix.winui }} + -componentPath "${{ github.workspace }}/${{ env.TEST_PROJECT_DIRECTORY }}" + ${{ env.ENABLE_DIAGNOSTICS == 'true' && ' -UseDiagnostics' || '' }} + + # The generated solution already contains only the head(s) for the requested MultiTarget(s) + # (GenerateSingleSolution.ps1 swaps in the Uno.Sdk head instead of the classic Wasm one for + # WinUI 3 + wasm), so one MSBuild invocation covers the Uno.Sdk head too - msbuild.exe builds + # it fine, verified locally against dotnet build with identical results. - name: MSBuild working-directory: ./${{ env.TEST_PROJECT_DIRECTORY }} run: msbuild.exe ${{ env.TEST_PROJECT_NAME }}.sln /restore /nowarn:MSB4011 -p:Configuration=Release /m ${{ env.ENABLE_DIAGNOSTICS == 'true' && '/bl' || '' }} /v:${{ env.MSBUILD_VERBOSITY }} @@ -249,10 +279,11 @@ jobs: name: new-experiment-logs-${{ matrix.multitarget }}-winui${{ matrix.winui }} path: ./**/*.*log - wasm-linux: + uno-linux: runs-on: ubuntu-latest env: HEADS_DIRECTORY: tooling/ProjectHeads + PROJECT_DIRECTORY: tooling/ProjectTemplate TEST_PROJECT_NAME: CiTestExp steps: @@ -267,6 +298,18 @@ jobs: with: global-json-file: tooling/global.json + # iOS/maccatalyst workloads aren't installable on Linux (Uno.Sdk + # auto-filters those TFMs there). android + wasm-tools are both + # required: even a `-f net10.0-browserwasm` build restores all of the + # head's TargetFrameworks, so the net10.0-android TFM's workload is + # validated during restore. + # Run from ./tooling so global.json scopes the install to the pinned + # SDK feature band; otherwise the workloads land on the runner's newer + # preinstalled SDK and the 9.0.x build can't see them (NETSDK1147). + - name: Install .NET workloads + working-directory: tooling + run: dotnet workload install android wasm-tools + - name: .NET Info (if diagnostics) if: ${{ env.ENABLE_DIAGNOSTICS == 'true' }} run: dotnet --info @@ -295,21 +338,18 @@ jobs: working-directory: ./components run: dotnet new ctk-component -n ${{ env.TEST_PROJECT_NAME }} - - name: Generate solution - shell: pwsh - working-directory: ./ - run: ./tooling/GenerateAllSolution.ps1${{ env.ENABLE_DIAGNOSTICS == 'true' && ' -UseDiagnostics' || '' }} -MultiTargets wasm - - - name: dotnet build + # Build-Toolkit-Gallery.ps1 sets up TFMs/WinUI/project references and builds the Uno head + # directly (components are pulled in transitively as ProjectReferences), so this replaces + # the previous solution-gen + component prebuild + two head builds with one step - the old + # sequence built every component up to 3x over. + - name: Build Uno head (gallery) shell: pwsh working-directory: ./ - run: ./tooling/Build-Toolkit-Components.ps1 -Release -MultiTargets wasm ${{ env.ENABLE_DIAGNOSTICS == 'true' && ' -BinlogOutput ./ -EnableBinLogs' || '' }} - - # TODO: Do we want to run tests here? Can we do that on linux easily? + run: ./tooling/Build-Toolkit-Gallery.ps1 -Heads Uno -Release -MultiTargets wasm,linux ${{ env.ENABLE_DIAGNOSTICS == 'true' && ' -BinlogOutput ./ -EnableBinLogs' || '' }} - name: Artifact - Diagnostic Logs uses: actions/upload-artifact@v4 if: ${{ (env.ENABLE_DIAGNOSTICS == 'true' || env.COREHOST_TRACE != '') && always() }} with: - name: linux-logs + name: uno-linux-logs path: ./**/*.*log diff --git a/Build-Toolkit-Components.ps1 b/Build-Toolkit-Components.ps1 index 6cbc0ec5..4fac8c41 100644 --- a/Build-Toolkit-Components.ps1 +++ b/Build-Toolkit-Components.ps1 @@ -57,11 +57,11 @@ Date: 2/19/2024 #> Param ( - [ValidateSet('all', 'wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android', 'netstandard')] + [ValidateSet('all', 'wasm', 'uwp', 'wasdk', 'wpf', 'win32', 'linux', 'macos', 'ios', 'android', 'netstandard')] [Alias("mt")] [string[]]$MultiTargets = @('uwp', 'wasm', 'wasdk'), # default settings - - [ValidateSet('wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android', 'netstandard')] + + [ValidateSet('wasm', 'uwp', 'wasdk', 'wpf', 'win32', 'linux', 'macos', 'ios', 'android', 'netstandard')] [string[]]$ExcludeMultiTargets = @(), # default settings [Alias("c")] @@ -97,7 +97,7 @@ Param ( if ($MultiTargets -eq 'all') { - $MultiTargets = @('wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android', 'netstandard') + $MultiTargets = @('wasm', 'uwp', 'wasdk', 'wpf', 'win32', 'linux', 'macos', 'ios', 'android', 'netstandard') } if ($null -eq $ExcludeMultiTargets) diff --git a/Build-Toolkit-Gallery.ps1 b/Build-Toolkit-Gallery.ps1 index 7d92154e..81a706c3 100644 --- a/Build-Toolkit-Gallery.ps1 +++ b/Build-Toolkit-Gallery.ps1 @@ -9,7 +9,7 @@ Specifies the MultiTarget TFM(s) to include for building the components. The default value is 'all'. .PARAMETER ExcludeMultiTargets - Specifies the MultiTarget TFM(s) to exclude for building the components. The default value excludes targets that require additional tooling or workloads to build: 'wpf', 'linuxgtk', 'macos', 'ios', and 'android'. Run uno-check to install the required workloads. + Specifies the MultiTarget TFM(s) to exclude for building the components. The default value excludes targets that require additional tooling or workloads to build: 'wpf', 'linux', 'macos', 'ios', and 'android'. Run uno-check to install the required workloads. .PARAMETER Heads The heads to include in the build. Default is 'Uwp', 'Wasdk', 'Wasm'. @@ -46,17 +46,17 @@ Date: 2/19/2024 #> Param ( - [ValidateSet('all', 'wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android', 'netstandard')] + [ValidateSet('all', 'wasm', 'uwp', 'wasdk', 'wpf', 'win32', 'linux', 'macos', 'ios', 'android', 'netstandard')] [Alias("mt")] [string[]]$MultiTargets = @('uwp', 'wasdk', 'wasm'), # default settings - - [ValidateSet('wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android', 'netstandard')] + + [ValidateSet('wasm', 'uwp', 'wasdk', 'wpf', 'win32', 'linux', 'macos', 'ios', 'android', 'netstandard')] [string[]]$ExcludeMultiTargets = @(), # default settings - [ValidateSet('all', 'Uwp', 'Wasdk', 'Wasm', 'Tests.Uwp', 'Tests.Wasdk')] + [ValidateSet('all', 'Uwp', 'Wasdk', 'Wasm', 'Uno', 'Tests.Uwp', 'Tests.Wasdk')] [string[]]$Heads = @('Uwp', 'Wasdk', 'Wasm'), - [ValidateSet('Uwp', 'Wasdk', 'Wasm', 'Tests.Uwp', 'Tests.Wasdk')] + [ValidateSet('Uwp', 'Wasdk', 'Wasm', 'Uno', 'Tests.Uwp', 'Tests.Wasdk')] [string[]]$ExcludeHeads, [Alias("bl")] @@ -102,7 +102,7 @@ if ($MultiTargets.Contains('uwp') -and $MultiTargets.Contains('wasdk')) } if ($MultiTargets -eq 'all') { - $MultiTargets = @('wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android', 'netstandard') + $MultiTargets = @('wasm', 'uwp', 'wasdk', 'wpf', 'win32', 'linux', 'macos', 'ios', 'android', 'netstandard') } if ($ExcludeMultiTargets) { @@ -131,17 +131,31 @@ if ($Components -notcontains 'Converters') { & $PSScriptRoot\MultiTarget\GenerateAllProjectReferences.ps1 -MultiTarget $MultiTargets -Components $Components if ($Heads -eq 'all') { - $Heads = @('Uwp', 'Wasdk', 'Wasm', 'Tests.Uwp', 'Tests.Wasdk') + $Heads = @('Uwp', 'Wasdk', 'Wasm', 'Uno', 'Tests.Uwp', 'Tests.Wasdk') } function Invoke-MSBuildWithBinlog { param ( - [string]$TargetHeadPath + [string]$TargetHeadPath, + [string]$TargetFramework ) # Reset build args to default $msbuildArgs = @("-r", "-m", "-t:Clean,Build") + if ($TargetFramework) { + # dotnet build's "-f" does a scoped inner-build restore for just that TFM; plain + # "/p:TargetFramework=" on a multi-targeted project restores the outer project's full TFM + # closure first, which fails for components that don't support every TFM the head declares. + # msbuild.exe has no "-f" equivalent, so this only reliably supports one TFM at a time there. + if ($($PSVersionTable.Platform) -eq "Unix") { + $msbuildArgs += "-f:$TargetFramework" + } + else { + $msbuildArgs += "/p:TargetFramework=$TargetFramework" + } + } + # Add additional properties to the msbuild arguments if ($AdditionalProperties) { foreach ($property in $AdditionalProperties.GetEnumerator()) { @@ -153,12 +167,13 @@ function Invoke-MSBuildWithBinlog { if ($EnableBinLogs) { # Get binlog filename and output path $csprojFileName = [System.IO.Path]::GetFileNameWithoutExtension($TargetHeadPath) - $defaultBinlogFilename = "$csprojFileName.msbuild.binlog" + $binlogSuffix = $TargetFramework ? ".$TargetFramework" : "" + $defaultBinlogFilename = "$csprojFileName$binlogSuffix.msbuild.binlog" $finalBinlogPath = $defaultBinlogFilename; # Set default binlog output location if not provided if ($BinlogOutput) { - $finalBinlogPath = "$BinlogOutput/$defaultBinlogFilename" + $finalBinlogPath = "$BinlogOutput/$defaultBinlogFilename" } $msbuildArgs += "/bl:$finalBinlogPath" @@ -172,7 +187,40 @@ function Invoke-MSBuildWithBinlog { $msbuildArgs += "/verbosity:detailed" } - msbuild $msbuildArgs $TargetHeadPath + # On Linux there's no msbuild.exe on PATH; dotnet build is the only option there anyway. + if ($($PSVersionTable.Platform) -eq "Unix") { + dotnet build $msbuildArgs $TargetHeadPath + } + else { + msbuild $msbuildArgs $TargetHeadPath + } +} + +# The Uno.Sdk head covers several MultiTargets from one multi-TFM csproj (see +# ProjectHeads/AllComponents/Uno/CommunityToolkit.App.Uno.csproj). Building all of its enabled TFMs +# in one invocation isn't reliable across every combination, so - matching what CI already does - +# build it one TFM at a time via `-f`, only for the TFMs the requested $MultiTargets actually enable. +function Get-UnoSdkHeadTargetFrameworks { + param ( + [string[]]$MultiTargets + ) + + $targetFrameworks = [System.Collections.ArrayList]::new() + + if (($MultiTargets | Where-Object { @('win32', 'linux', 'macos') -contains $_ }).Count -gt 0) { + [void]$targetFrameworks.Add('net10.0-desktop') + } + if ($MultiTargets -contains 'wasm') { + [void]$targetFrameworks.Add('net10.0-browserwasm') + } + if ($MultiTargets -contains 'android') { + [void]$targetFrameworks.Add('net10.0-android') + } + if ($MultiTargets -contains 'ios') { + [void]$targetFrameworks.Add('net10.0-ios') + } + + return $targetFrameworks } foreach ($head in $Heads) { @@ -182,5 +230,19 @@ foreach ($head in $Heads) { $targetHeadPath = Get-ChildItem "$PSScriptRoot/ProjectHeads/AllComponents/$head/*.csproj" - Invoke-MSBuildWithBinlog $targetHeadPath $EnableBinLogs $BinlogOutput + if ($head -eq 'Uno') { + $unoTargetFrameworks = Get-UnoSdkHeadTargetFrameworks -MultiTargets $MultiTargets + + if ($unoTargetFrameworks.Count -eq 0) { + Write-Warning "None of the requested MultiTargets ($MultiTargets) are served by the Uno.Sdk head. Skipping." + continue + } + + foreach ($targetFramework in $unoTargetFrameworks) { + Invoke-MSBuildWithBinlog $targetHeadPath $targetFramework + } + } + else { + Invoke-MSBuildWithBinlog $targetHeadPath + } } diff --git a/CommunityToolkit.App.Shared/CommunityToolkit.App.Shared.projitems b/CommunityToolkit.App.Shared/CommunityToolkit.App.Shared.projitems index 732e956e..39caa849 100644 --- a/CommunityToolkit.App.Shared/CommunityToolkit.App.Shared.projitems +++ b/CommunityToolkit.App.Shared/CommunityToolkit.App.Shared.projitems @@ -35,6 +35,7 @@ GettingStartedPage.xaml + GeneratedSampleOptionsRenderer.xaml diff --git a/CommunityToolkit.App.Shared/Polyfills/ColorCode/RichTextBlockFormatter.cs b/CommunityToolkit.App.Shared/Polyfills/ColorCode/RichTextBlockFormatter.cs new file mode 100644 index 00000000..7325b122 --- /dev/null +++ b/CommunityToolkit.App.Shared/Polyfills/ColorCode/RichTextBlockFormatter.cs @@ -0,0 +1,130 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#if HAS_UNO && WINUI3 +#nullable enable +using ColorCode.Common; +using ColorCode.Parsing; +using ColorCode.Styling; +using Microsoft.UI.Text; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Documents; +using Microsoft.UI.Xaml.Media; +using Windows.UI.Text; + +namespace ColorCode; + +/// +/// Port of ColorCode.WinUI's RichTextBlockFormatter, which only ships for Windows. +/// See https://github.com/CommunityToolkit/ColorCode-Universal/blob/main/ColorCode.UWP/RichTextBlockFormatter.cs +/// +public class RichTextBlockFormatter : CodeColorizerBase +{ + private InlineCollection? _inlines; + + public RichTextBlockFormatter(ElementTheme theme) + : base(theme == ElementTheme.Dark ? StyleDictionary.DefaultDark : StyleDictionary.DefaultLight, null) + { + } + + public void FormatRichTextBlock(string sourceCode, ILanguage language, RichTextBlock richText) + { + var paragraph = new Paragraph(); + richText.Blocks.Add(paragraph); + + _inlines = paragraph.Inlines; + languageParser.Parse(sourceCode, language, Write); + } + + protected override void Write(string parsedSourceCode, IList scopes) + { + List styleInsertions = new(); + + foreach (var scope in scopes) + { + GetStyleInsertionsForCapturedStyle(scope, styleInsertions); + } + + styleInsertions.SortStable((x, y) => x.Index.CompareTo(y.Index)); + + int offset = 0; + Scope? previousScope = null; + + foreach (var insertion in styleInsertions) + { + AddRun(parsedSourceCode.Substring(offset, insertion.Index - offset), previousScope); + offset = insertion.Index; + previousScope = insertion.Scope; + } + + var remaining = parsedSourceCode.Substring(offset); + + // Ensures that those loose carriages don't run away! + if (remaining != "\r") + { + AddRun(remaining, null); + } + } + + private void AddRun(string text, Scope? scope) + { + Run run = new() { Text = text }; + + if (scope is not null && Styles.Contains(scope.Name)) + { + var style = Styles[scope.Name]; + + if (!string.IsNullOrWhiteSpace(style.Foreground)) + { + run.Foreground = new SolidColorBrush(ParseColor(style.Foreground)); + } + + if (style.Italic) + { + run.FontStyle = FontStyle.Italic; + } + + if (style.Bold) + { + run.FontWeight = FontWeights.Bold; + } + } + + _inlines!.Add(run); + } + + private static Windows.UI.Color ParseColor(string hex) + { + hex = hex.Replace("#", string.Empty); + + byte a = 255; + int index = 0; + + if (hex.Length == 8) + { + a = Convert.ToByte(hex.Substring(index, 2), 16); + index += 2; + } + + byte r = Convert.ToByte(hex.Substring(index, 2), 16); + byte g = Convert.ToByte(hex.Substring(index + 2, 2), 16); + byte b = Convert.ToByte(hex.Substring(index + 4, 2), 16); + + return Windows.UI.Color.FromArgb(a, r, g, b); + } + + private static void GetStyleInsertionsForCapturedStyle(Scope scope, ICollection styleInsertions) + { + styleInsertions.Add(new TextInsertion { Index = scope.Index, Scope = scope }); + + foreach (var childScope in scope.Children) + { + GetStyleInsertionsForCapturedStyle(childScope, styleInsertions); + } + + styleInsertions.Add(new TextInsertion { Index = scope.Index + scope.Length }); + } +} +#endif diff --git a/CommunityToolkit.App.Shared/Renderers/Markdown/MarkdownTextBlock.cs b/CommunityToolkit.App.Shared/Renderers/Markdown/MarkdownTextBlock.cs index 2b0d3293..bb2e1cd7 100644 --- a/CommunityToolkit.App.Shared/Renderers/Markdown/MarkdownTextBlock.cs +++ b/CommunityToolkit.App.Shared/Renderers/Markdown/MarkdownTextBlock.cs @@ -2,7 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#if HAS_UNO +#if HAS_LABS_MARKDOWNTEXTBLOCK + using CommunityToolkit.WinUI.Controls; + using Microsoft.UI.Text; + using ToolkitMTB = CommunityToolkit.WinUI.Controls.MarkdownTextBlock; +#elif HAS_UNO #if WINAPPSDK using ToolkitMTB = Microsoft.UI.Xaml.Controls.TextBlock; #else @@ -16,7 +20,7 @@ #endif #endif -#if HAS_UNO_WASM +#if HAS_UNO_WASM && !WINUI3 using Markdig; using Uno.Foundation.Interop; using Uno.UI.Runtime.WebAssembly; @@ -27,7 +31,46 @@ namespace CommunityToolkit.App.Shared.Renderers; /// /// Provide an abstraction around the Toolkit MarkdownTextBlock for both UWP and WinUI 3 in the same namespace (until 8.0) as well as a polyfill for WebAssembly/WASM. /// -#if HAS_UNO_WASM +#if HAS_LABS_MARKDOWNTEXTBLOCK +public partial class MarkdownTextBlock : ToolkitMTB +{ + public MarkdownTextBlock() + { + IsTextSelectionEnabled = true; + + // Matches the Windows typography from ToolkitDocumentationRenderer.xaml + Config = new MarkdownConfig + { + Themes = new MarkdownThemes + { + H1FontSize = 28, + H1Margin = new Thickness(0, 20, 0, 4), + H2FontSize = 18, + H2Margin = new Thickness(0, 20, 0, 0), + H3FontSize = 16, + H4FontSize = 14, + H5FontSize = 14, + H5FontWeight = FontWeights.Normal, + H6FontSize = 14, + ParagraphMargin = new Thickness(0, 0, 0, 12), + ParagraphLineHeight = 20, + InlineCodeFontSize = 12, + }, + }; + + OnLinkClicked += (_, e) => + { + LinkClicked?.Invoke(this, new LinkClickedEventArgs(e.Uri.ToString())); + e.Handled = true; + }; + } + + // RichTextBlock always wraps, kept so the shared XAML can set it + public TextWrapping TextWrapping { get; set; } + + public event EventHandler? LinkClicked; +} +#elif HAS_UNO_WASM && !WINUI3 [HtmlElement("div")] public partial class MarkdownTextBlock : TextBlock { @@ -108,6 +151,10 @@ public MarkdownTextBlock() #endif #if HAS_UNO -//// Polyfill dummy for event callback -public class LinkClickedEventArgs : EventArgs { } +public class LinkClickedEventArgs : EventArgs +{ + public LinkClickedEventArgs(string link) => Link = link; + + public string Link { get; } +} #endif diff --git a/CommunityToolkit.App.Shared/Renderers/ToolkitDocumentationRenderer.xaml b/CommunityToolkit.App.Shared/Renderers/ToolkitDocumentationRenderer.xaml index 0ebf3f79..138e2f84 100644 --- a/CommunityToolkit.App.Shared/Renderers/ToolkitDocumentationRenderer.xaml +++ b/CommunityToolkit.App.Shared/Renderers/ToolkitDocumentationRenderer.xaml @@ -103,7 +103,7 @@ diff --git a/CommunityToolkit.App.Shared/Renderers/ToolkitDocumentationRenderer.xaml.cs b/CommunityToolkit.App.Shared/Renderers/ToolkitDocumentationRenderer.xaml.cs index ddbcd721..3c30e82c 100644 --- a/CommunityToolkit.App.Shared/Renderers/ToolkitDocumentationRenderer.xaml.cs +++ b/CommunityToolkit.App.Shared/Renderers/ToolkitDocumentationRenderer.xaml.cs @@ -188,13 +188,13 @@ private static async Task GetDocumentationFileContents(ToolkitFrontMatte } } -#if HAS_UNO +#if HAS_UNO && !HAS_LABS_MARKDOWNTEXTBLOCK private void MarkdownTextBlock_LinkClicked(object sender, LinkClickedEventArgs e) { // No-op - WASM handles via browser 'a' tag, Windows has handler below. // TODO: For other platforms } -#elif !HAS_UNO +#else private async void MarkdownTextBlock_LinkClicked(object sender, LinkClickedEventArgs e) { if (!Uri.IsWellFormedUriString(e.Link, UriKind.Absolute)) diff --git a/CommunityToolkit.App.Shared/Renderers/ToolkitSampleRenderer.xaml b/CommunityToolkit.App.Shared/Renderers/ToolkitSampleRenderer.xaml index 0235141a..ff784aec 100644 --- a/CommunityToolkit.App.Shared/Renderers/ToolkitSampleRenderer.xaml +++ b/CommunityToolkit.App.Shared/Renderers/ToolkitSampleRenderer.xaml @@ -225,12 +225,7 @@ - + - + diff --git a/CommunityToolkit.App.Shared/Renderers/ToolkitSampleRenderer.xaml.cs b/CommunityToolkit.App.Shared/Renderers/ToolkitSampleRenderer.xaml.cs index 6af5bc68..f6ad6a46 100644 --- a/CommunityToolkit.App.Shared/Renderers/ToolkitSampleRenderer.xaml.cs +++ b/CommunityToolkit.App.Shared/Renderers/ToolkitSampleRenderer.xaml.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#if !HAS_UNO +#if !HAS_UNO || WINUI3 using ColorCode; #endif using CommunityToolkit.Tooling.SampleGen.Metadata; @@ -39,8 +39,40 @@ public sealed partial class ToolkitSampleRenderer : Page public ToolkitSampleRenderer() { this.InitializeComponent(); + +#if HAS_UNO + XAMLCodeHost.Content = XAMLCodeRenderer; + CSharpCodeHost.Content = CSharpCodeRenderer; +#endif } +#if HAS_UNO + // XAML can't tell Uno's WinUI flavors apart, and only WinUI 3 (Uno 7+) supports RichTextBlock. +#if WINUI3 + private readonly RichTextBlock XAMLCodeRenderer = CreateCodeRenderer(); + private readonly RichTextBlock CSharpCodeRenderer = CreateCodeRenderer(); + + private static RichTextBlock CreateCodeRenderer() => new() + { + FontFamily = new FontFamily("Consolas"), + FontSize = 12, + IsTextSelectionEnabled = true, + }; +#else + private readonly TextBlock XAMLCodeRenderer = CreateCodeRenderer(); + private readonly TextBlock CSharpCodeRenderer = CreateCodeRenderer(); + + private static TextBlock CreateCodeRenderer() => new() + { + Margin = new Thickness(0, 12, 0, 12), + FontFamily = new FontFamily("Consolas"), + FontSize = 12, + IsTextSelectionEnabled = true, + TextWrapping = TextWrapping.WrapWholeWords, + }; +#endif +#endif + /// /// The backing for the property. /// @@ -337,13 +369,12 @@ private void CodeBtn_OnClick(object sender, RoutedEventArgs e) private void RenderCode() { - // Uno doesn't support RichTextBlock, so we are using a normal TextBlock instead on WASM -#if !HAS_UNO +#if !HAS_UNO || WINUI3 RichTextBlockFormatter codeFormatter = new RichTextBlockFormatter(ActualTheme); #endif if (XamlCode is not null) { -#if HAS_UNO +#if HAS_UNO && !WINUI3 XAMLCodeRenderer.Text = XamlCode; #else XAMLCodeRenderer.Blocks?.Clear(); @@ -353,7 +384,7 @@ private void RenderCode() if (CSharpCode is not null) { -#if HAS_UNO +#if HAS_UNO && !WINUI3 CSharpCodeRenderer.Text = CSharpCode; #else CSharpCodeRenderer.Blocks?.Clear(); diff --git a/GenerateAllSolution.ps1 b/GenerateAllSolution.ps1 index 72eb9bac..f2ea256f 100644 --- a/GenerateAllSolution.ps1 +++ b/GenerateAllSolution.ps1 @@ -38,11 +38,11 @@ Date: April 27, 2022 #> Param ( - [ValidateSet('all', 'wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android', 'netstandard')] + [ValidateSet('all', 'wasm', 'uwp', 'wasdk', 'wpf', 'win32', 'linux', 'macos', 'ios', 'android', 'netstandard')] [Alias("mt")] - [string[]]$MultiTargets = @('uwp', 'wasm', 'wasdk'), + [string[]]$MultiTargets = @('uwp', 'wasm', 'wasdk', 'win32'), - [ValidateSet('wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android', 'netstandard')] + [ValidateSet('wasm', 'uwp', 'wasdk', 'wpf', 'win32', 'linux', 'macos', 'ios', 'android', 'netstandard')] [string[]]$ExcludeMultiTargets = @(), # default settings [Alias("c")] @@ -54,12 +54,12 @@ Param ( [string[]]$ExcludeComponents, [switch]$UseDiagnostics = $false, - + [bool]$Launch = $true ) if ($MultiTargets.Contains('all')) { - $MultiTargets = @('wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android', 'netstandard') + $MultiTargets = @('wasm', 'uwp', 'wasdk', 'wpf', 'win32', 'linux', 'macos', 'ios', 'android', 'netstandard') } if ($null -eq $ExcludeMultiTargets) @@ -150,11 +150,25 @@ foreach ($componentName in $Components) { # Deployable sample gallery heads # Only include heads for requested MultiTargets if components were included that use them. -# === -# TODO: this handles separate project heads, but won't directly handle the unified Skia head from Uno. -# Once we have that, just do a transform on the csproj filename inside this loop to decide the same csproj for those separate MultiTargets. -# === +# These have no head project of their own - they're served by the unified Uno.Sdk head added below. +$unoSdkHeadMultiTargets = @('win32', 'linux', 'macos', 'ios', 'android') + +# The Uno.Sdk head is implied by the requested MultiTargets, not a separate switch: it's the only +# head that can serve win32/linux/macos/ios/android, and for wasm it replaces the classic Wasm head +# once WinUI 3 is requested (WinUI 2 + wasm keeps using the classic head). +$includeUnoSdkHead = (($allUsedMultiTargetPrefs | Where-Object { $unoSdkHeadMultiTargets -contains $_ }).Count -gt 0) -or ` + ($allUsedMultiTargetPrefs.Contains('wasm') -and $WinUIMajorVersion -eq 3) + foreach ($multitarget in $allUsedMultiTargetPrefs) { + if ($unoSdkHeadMultiTargets -contains $multitarget) { + continue + } + + # When using the Uno.Sdk head, skip the traditional Wasm head (Uno.Sdk covers wasm for WinUI 3) + if ($multitarget -eq 'wasm' -and $includeUnoSdkHead) { + continue + } + # capitalize first letter, avoid case sensitivity issues on linux $csprojFileNamePartForMultiTarget = $multitarget.substring(0,1).ToUpper() + $multitarget.Substring(1).ToLower() @@ -168,6 +182,15 @@ foreach ($multitarget in $allUsedMultiTargetPrefs) { } } +if ($includeUnoSdkHead) { + $unoHeadPath = "./tooling/ProjectHeads/AllComponents/Uno/CommunityToolkit.App.Uno.csproj" + if (Test-Path $unoHeadPath) { + [void]$projects.Add($unoHeadPath) + } else { + Write-Warning "Uno.Sdk head project not found at $unoHeadPath." + } +} + if ($UseDiagnostics.IsPresent) { $sdkoptions = "-d" diff --git a/GenerateSingleSolution.ps1 b/GenerateSingleSolution.ps1 index e0e73d7d..a3294ad4 100644 --- a/GenerateSingleSolution.ps1 +++ b/GenerateSingleSolution.ps1 @@ -33,7 +33,7 @@ Date: Feb 9, 2023 #> Param ( - [ValidateSet('all', 'wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android')] + [ValidateSet('all', 'wasm', 'uwp', 'wasdk', 'wpf', 'win32', 'linux', 'macos', 'ios', 'android')] [Alias("mt")] [string[]]$MultiTargets = @('uwp', 'wasm', 'wasdk'), @@ -98,7 +98,7 @@ if (-not (Test-Path "$componentPath/src" -PathType Container)) # ----------------- if ($MultiTargets.Contains('all')) { - $MultiTargets = @('wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android') + $MultiTargets = @('wasm', 'uwp', 'wasdk', 'wpf', 'win32', 'linux', 'macos', 'ios', 'android') } if ($null -eq $ExcludeMultiTargets) @@ -188,9 +188,25 @@ Write-Output "Generating solution for $componentName in $generatedSolutionFilePa # All heads are included by default since they reside in the same folder as the component. # Remove any heads that are not required for the solution. -# TODO: this handles separate project heads, but won't directly handle the unified Skia head from Uno. -# Once we have that, just do a transform on the csproj filename inside this loop to decide the same csproj for those separate MultiTargets. +# These have no head project of their own - they're served by the unified Uno.Sdk head added below. +$unoSdkHeadMultiTargets = @('win32', 'linux', 'macos', 'ios', 'android') + +# The Uno.Sdk head is implied by the requested MultiTargets, not a separate switch: it's the only +# head that can serve win32/linux/macos/ios/android, and for wasm it replaces the classic Wasm head +# once WinUI 3 is requested (WinUI 2 + wasm keeps using the classic head). +$includeUnoSdkHead = (($MultiTargets | Where-Object { $unoSdkHeadMultiTargets -contains $_ }).Count -gt 0) -or ` + ($MultiTargets.Contains('wasm') -and $WinUIMajorVersion -eq 3) + foreach ($multitarget in $MultiTargets) { + if ($unoSdkHeadMultiTargets -contains $multitarget) { + continue + } + + # When using the Uno.Sdk head, skip the traditional Wasm head (Uno.Sdk covers wasm for WinUI 3) + if ($multitarget -eq 'wasm' -and $includeUnoSdkHead) { + continue + } + # capitalize first letter, avoid case sensitivity issues on linux $csprojFileNamePartForMultiTarget = $multitarget.substring(0,1).ToUpper() + $multitarget.Substring(1).ToLower() @@ -208,6 +224,17 @@ foreach ($multitarget in $MultiTargets) { } } +if ($includeUnoSdkHead) { + $unoHeadPath = "$outputHeadsDir\Uno\*Uno.csproj" + if (Test-Path $unoHeadPath) { + foreach ($foundItem in Get-ChildItem $unoHeadPath) { + $projects = $projects + $foundItem.FullName + } + } else { + Write-Warning "Uno.Sdk head project not found at $unoHeadPath." + } +} + # Include common dependencies required for solution to build $projects = $projects + "$PSScriptRoot\CommunityToolkit.App.Shared\**\*.*proj" $projects = $projects + "$PSScriptRoot\CommunityToolkit.Tests.Shared\**\*.*proj" diff --git a/GenerateVSCodeLaunchConfig.ps1 b/GenerateVSCodeLaunchConfig.ps1 index 58ced9ed..f8809ea2 100644 --- a/GenerateVSCodeLaunchConfig.ps1 +++ b/GenerateVSCodeLaunchConfig.ps1 @@ -9,7 +9,7 @@ function CreateVsCodeLaunchConfigJson { ) return "{ - `"name`": `"$projectName`", + `"name`": `"$projectName (Wasm)`", `"type`": `"coreclr`", `"request`": `"launch`", `"program`": `"dotnet`", @@ -29,6 +29,32 @@ function CreateVsCodeLaunchConfigJson { }"; } +function CreateUnoVsCodeLaunchConfigJson { + param ( + [string]$projectName + ) + + return "{ + `"name`": `"$projectName (Uno)`", + `"type`": `"coreclr`", + `"request`": `"launch`", + `"program`": `"dotnet`", + `"args`": [ + `"run`", + `"build`", + `"/r`", + `"/p:UnoSourceGeneratorUseGenerationHost=true`", + `"/p:UnoSourceGeneratorUseGenerationController=false`", + `"/p:UnoRemoteControlPort=443`", + `"--project=`$`{workspaceFolder`}/components/$projectName/heads/Uno/$projectName.Uno.csproj`" + ], + `"presentation`": { + `"group`": `"2`" + }, + `"cwd`": `"`$`{workspaceFolder`}/components/$projectName/heads/Uno`" + }"; +} + $launchConfigJson = Get-Content -Path "$PSScriptRoot/../.vscode/launch.json" -ErrorAction Stop; $launchConfig = $launchConfigJson | ConvertFrom-Json; @@ -46,8 +72,11 @@ foreach ($projectPath in Get-ChildItem -Directory -Depth 0 -Path "$PSScriptRoot/ $configJson = CreateVsCodeLaunchConfigJson $projectName; $config = $configJson | ConvertFrom-Json; - $launchConfig.configurations += $config; + + $unoConfigJson = CreateUnoVsCodeLaunchConfigJson $projectName; + $unoConfig = $unoConfigJson | ConvertFrom-Json; + $launchConfig.configurations += $unoConfig; } if ($allowGitChanges.IsPresent) { diff --git a/MultiTarget/AvailableTargetFrameworks.props b/MultiTarget/AvailableTargetFrameworks.props index 1c02bc51..47ddf644 100644 --- a/MultiTarget/AvailableTargetFrameworks.props +++ b/MultiTarget/AvailableTargetFrameworks.props @@ -12,21 +12,26 @@ uap10.0.17763;net8.0-windows10.0.26100.0;net9.0-windows10.0.26100.0; net9.0-windows10.0.26100.0;net8.0-windows10.0.26100.0; - net9.0; - net9.0; - net9.0; - - net9.0-android; - net9.0-maccatalyst; - net9.0-ios; + + net10.0 + net9.0 + + $(UnoDotNetTargetFramework); + $(UnoDotNetTargetFramework); + $(UnoDotNetTargetFramework); + + $(UnoDotNetTargetFramework)-android; + $(UnoDotNetTargetFramework)-maccatalyst; + $(UnoDotNetTargetFramework)-ios; - net9.0; - net9.0; - net9.0; + $(UnoDotNetTargetFramework); + $(UnoDotNetTargetFramework); + $(UnoDotNetTargetFramework); + $(UnoDotNetTargetFramework); netstandard2.0; - net9.0; + $(UnoDotNetTargetFramework); \ No newline at end of file diff --git a/MultiTarget/Defaults.props b/MultiTarget/Defaults.props index 86e5e82f..fbf71733 100644 --- a/MultiTarget/Defaults.props +++ b/MultiTarget/Defaults.props @@ -1,5 +1,5 @@ - uwp;wasdk;wpf;wasm;linuxgtk;macos;ios;android; + uwp;wasdk;wpf;win32;wasm;linux;macos;ios;android; \ No newline at end of file diff --git a/MultiTarget/DefinedConstants.props b/MultiTarget/DefinedConstants.props index b5c8c2c9..d890e153 100644 --- a/MultiTarget/DefinedConstants.props +++ b/MultiTarget/DefinedConstants.props @@ -13,8 +13,12 @@ $(DefineConstants);__IOS__; $(DefineConstants);__MACOS__; $(DefineConstants);HAS_UNO_SKIA;__SKIA__;WINDOWS_WPF; - $(DefineConstants);HAS_UNO_SKIA;__SKIA__;__GTK__; + $(DefineConstants);HAS_UNO_SKIA;__SKIA__;__GTK__; + $(DefineConstants);HAS_UNO_SKIA;__SKIA__; + + $(DefineConstants);HAS_UNO_SKIA;__SKIA__; + $(DefineConstants);NET10_0_OR_GREATER $(DefineConstants);NET9_0_OR_GREATER $(DefineConstants);NET8_0_OR_GREATER $(DefineConstants);NET7_0_OR_GREATER diff --git a/MultiTarget/EnabledTargetFrameworks.props b/MultiTarget/EnabledTargetFrameworks.props index 6f1c0ab9..ce94724e 100644 --- a/MultiTarget/EnabledTargetFrameworks.props +++ b/MultiTarget/EnabledTargetFrameworks.props @@ -10,14 +10,20 @@ $(TargetFrameworks);$(WinAppSdkTargetFrameworks) - true - true + true + true $(TargetFrameworks);$(DotnetCommonTargetFramework) - $(TargetFrameworks);$(MacOSLibTargetFrameworks) + + $(TargetFrameworks);$(MacOSLibTargetFrameworks) $(TargetFrameworks);$(iOSLibTargetFrameworks) $(TargetFrameworks);$(AndroidLibTargetFrameworks) diff --git a/MultiTarget/Filter-Supported-Components.ps1 b/MultiTarget/Filter-Supported-Components.ps1 index bc187e85..2ba1a0bb 100644 --- a/MultiTarget/Filter-Supported-Components.ps1 +++ b/MultiTarget/Filter-Supported-Components.ps1 @@ -17,7 +17,7 @@ Date: 6/6/2025 #> Param ( - [ValidateSet('all', 'wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android', 'netstandard')] + [ValidateSet('all', 'wasm', 'uwp', 'wasdk', 'wpf', 'win32', 'linux', 'macos', 'ios', 'android', 'netstandard')] [Alias("mt")] [Parameter(Mandatory=$true)] [string[]]$MultiTargets, @@ -32,7 +32,7 @@ Param ( ) if ($MultiTargets -eq 'all') { - $MultiTargets = @('wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android', 'netstandard') + $MultiTargets = @('wasm', 'uwp', 'wasdk', 'wpf', 'win32', 'linux', 'macos', 'ios', 'android', 'netstandard') } $supportedComponents = @(); diff --git a/MultiTarget/GenerateAllProjectReferences.ps1 b/MultiTarget/GenerateAllProjectReferences.ps1 index 62ca3b02..ab495bf4 100644 --- a/MultiTarget/GenerateAllProjectReferences.ps1 +++ b/MultiTarget/GenerateAllProjectReferences.ps1 @@ -4,8 +4,8 @@ Param ( [Parameter(HelpMessage = "Only projects that support these targets will have references generated for use by deployable heads.")] [Alias("mt")] - [ValidateSet('wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android', 'netstandard')] - [string[]]$MultiTargets = @("uwp", "wasdk", "wpf", "wasm", "linuxgtk", "macos", "ios", "android", "netstandard"), + [ValidateSet('wasm', 'uwp', 'wasdk', 'wpf', 'win32', 'linux', 'macos', 'ios', 'android', 'netstandard')] + [string[]]$MultiTargets = @("uwp", "wasdk", "wpf", "win32", "wasm", "linux", "macos", "ios", "android", "netstandard"), [Parameter(HelpMessage = "The names of the components to generate references for. Defaults to all components.")] [string[]]$Components = @("all"), diff --git a/MultiTarget/GenerateMultiTargetAwareProjectReferenceProps.ps1 b/MultiTarget/GenerateMultiTargetAwareProjectReferenceProps.ps1 index dbbd6728..461ca388 100644 --- a/MultiTarget/GenerateMultiTargetAwareProjectReferenceProps.ps1 +++ b/MultiTarget/GenerateMultiTargetAwareProjectReferenceProps.ps1 @@ -15,9 +15,9 @@ Param ( [string]$projectRootPlaceholder = "[ProjectRoot]", [Parameter(HelpMessage = "Only projects that support these targets will have references generated for use by deployable heads.")] - [ValidateSet("uwp", "wasdk", "wpf", "wasm", "linuxgtk", "macos", "ios", "android", "netstandard")] + [ValidateSet("uwp", "wasdk", "wpf", "win32", "wasm", "linux", "macos", "ios", "android", "netstandard")] [Alias("mt")] - [string[]] $MultiTargets = @("uwp", "wasdk", "wpf", "wasm", "linuxgtk", "macos", "ios", "android", "netstandard") + [string[]] $MultiTargets = @("uwp", "wasdk", "wpf", "win32", "wasm", "linux", "macos", "ios", "android", "netstandard") ) if ($projectPath.EndsWith(".projitems")) { @@ -74,7 +74,7 @@ function ShouldMultiTargetMsBuildValue([string] $target) { return $(ShouldMultiTarget $target).ToString().ToLower() } -$targeted = @("uwp", "wasdk", "wpf", "wasm", "linuxgtk", "macos", "ios", "android", "netstandard").Where({ ShouldMultiTarget $_ }) +$targeted = @("uwp", "wasdk", "wpf", "win32", "wasm", "linux", "macos", "ios", "android", "netstandard").Where({ ShouldMultiTarget $_ }) if ($targeted.Count -gt 0) { Write-Host "Generating project references for $([System.IO.Path]::GetFileNameWithoutExtension($projectFileName)): $($targeted -Join ', ')" @@ -84,7 +84,8 @@ $templateContents = $templateContents -replace [regex]::escape("[CanTargetWasm]" $templateContents = $templateContents -replace [regex]::escape("[CanTargetUwp]"), "'$(ShouldMultiTargetMsBuildValue "uwp")'"; $templateContents = $templateContents -replace [regex]::escape("[CanTargetWasdk]"), "'$(ShouldMultiTargetMsBuildValue "wasdk")'"; $templateContents = $templateContents -replace [regex]::escape("[CanTargetWpf]"), "'$(ShouldMultiTargetMsBuildValue "wpf")'"; -$templateContents = $templateContents -replace [regex]::escape("[CanTargetLinuxGtk]"), "'$(ShouldMultiTargetMsBuildValue "linuxgtk")'"; +$templateContents = $templateContents -replace [regex]::escape("[CanTargetWin32]"), "'$(ShouldMultiTargetMsBuildValue "win32")'"; +$templateContents = $templateContents -replace [regex]::escape("[CanTargetLinux]"), "'$(ShouldMultiTargetMsBuildValue "linux")'"; $templateContents = $templateContents -replace [regex]::escape("[CanTargetMacOS]"), "'$(ShouldMultiTargetMsBuildValue "macos")'"; $templateContents = $templateContents -replace [regex]::escape("[CanTargetiOS]"), "'$(ShouldMultiTargetMsBuildValue "ios")'"; $templateContents = $templateContents -replace [regex]::escape("[CanTargetDroid]"), "'$(ShouldMultiTargetMsBuildValue "android")'"; diff --git a/MultiTarget/Library.props b/MultiTarget/Library.props index 61ab36c8..60904221 100644 --- a/MultiTarget/Library.props +++ b/MultiTarget/Library.props @@ -7,12 +7,19 @@ + + + - + + + .NETCoreApp + diff --git a/MultiTarget/MultiTargetAwareProjectReference.props.template b/MultiTarget/MultiTargetAwareProjectReference.props.template index 86b3c4d8..9ab42496 100644 --- a/MultiTarget/MultiTargetAwareProjectReference.props.template +++ b/MultiTarget/MultiTargetAwareProjectReference.props.template @@ -11,7 +11,8 @@ ($(IsUwp) == 'true' AND [CanTargetUwp] == 'true') OR ($(IsWinAppSdk) == 'true' AND [CanTargetWasdk] == 'true') OR ($(IsWpf) == 'true' AND [CanTargetWpf] == 'true') OR - ($(IsGtk) == 'true' AND [CanTargetLinuxGtk] == 'true') OR + ($(IsWin32) == 'true' AND [CanTargetWin32] == 'true') OR + ($(IsLinux) == 'true' AND [CanTargetLinux] == 'true') OR ($(IsMacOS) == 'true' AND [CanTargetMacOS] == 'true') OR ($(IsiOS) == 'true' AND [CanTargetiOS] == 'true') OR ($(IsDroid) == 'true' AND [CanTargetDroid] == 'true') OR diff --git a/MultiTarget/MultiTargetAwareSharedProjectImport.props.template b/MultiTarget/MultiTargetAwareSharedProjectImport.props.template index 06c9c8e0..0108d531 100644 --- a/MultiTarget/MultiTargetAwareSharedProjectImport.props.template +++ b/MultiTarget/MultiTargetAwareSharedProjectImport.props.template @@ -7,7 +7,7 @@ ($(IsUwp) == 'true' AND 'false' == 'true') OR ($(IsWinAppSdk) == 'true' AND 'true' == 'true') OR ($(IsWpf) == 'true' AND 'false' == 'true') OR - ($(IsGtk) == 'true' AND 'false' == 'true') OR + ($(IsLinux) == 'true' AND 'false' == 'true') OR ($(IsMacOS) == 'true' AND 'false' == 'true') OR ($(IsiOS) == 'true' AND 'false' == 'true') OR ($(IsDroid) == 'true' AND 'false' == 'true') OR diff --git a/MultiTarget/MultiTargetIdentifiers.props b/MultiTarget/MultiTargetIdentifiers.props index 47c8eb48..60f16dfa 100644 --- a/MultiTarget/MultiTargetIdentifiers.props +++ b/MultiTarget/MultiTargetIdentifiers.props @@ -17,7 +17,8 @@ true true - true + true + true true true true @@ -33,9 +34,14 @@ true true - true - true - true + + true + true + + true + true + true true true @@ -47,7 +53,7 @@ true true - true + true + 5.5.87 + + 7.0.0-dev.1656 + + $(UnoUIPackageVersion) + $(UnoWinUIPackageVersion) - - - + + - + + + + + + + + + + true - - + + + + + + + + - - + + + - - + + @@ -45,7 +70,12 @@ $(NoWarn);CS1570; - + + + + + + diff --git a/MultiTarget/ReadMe.md b/MultiTarget/ReadMe.md index fd8d7f19..7c304f33 100644 --- a/MultiTarget/ReadMe.md +++ b/MultiTarget/ReadMe.md @@ -17,7 +17,7 @@ By default, all available targets are enabled: ```xml - uwp;wasdk;wpf;wasm;linuxgtk;macos;ios;android; + uwp;wasdk;wpf;win32;wasm;linux;macos;ios;android; ``` @@ -32,6 +32,33 @@ For example, to only target UWP, WASM and Android: ``` +### Available targets + +A MultiTarget names a *platform your component runs on*, not a TFM. The TFMs and the deployable +head it maps to depend on which WinUI version is selected, since Uno 5.x (WinUI 2, `Uno.UI`) and +Uno 7.x (WinUI 3, `Uno.WinUI`) ship different heads and .NET versions: `net{x}` is `net9.0` on WinUI 2 and +`net10.0` on WinUI 3, since Uno 7 requires .NET 10. + +| MultiTarget | Platform | WinUI 2 (Uno 5.x) | WinUI 3 (Uno 7.x) | +| --- | --- | --- | --- | +| `uwp` | Windows, UWP XAML | `uap10.0.17763`, `net{x}-windows10.0.26100` | n/a | +| `wasdk` | Windows, Windows App SDK | n/a | `net{x}-windows10.0.19041` | +| `wasm` | WebAssembly | `net{x}`, Wasm head | `net{x}`, `net{x}-browserwasm` head | +| `wpf` | Windows desktop, Skia WPF | `net{x}`, Skia WPF head | n/a — use `win32` | +| `win32` | Windows desktop, Skia Win32 | n/a — use `wpf` | `net{x}`, `net{x}-desktop` head | +| `linux` | Linux desktop | `net{x}`, Skia GTK head | `net{x}`, `net{x}-desktop` head | +| `macos` | macOS | `net{x}-maccatalyst` | `net{x}`, `net{x}-desktop` head | +| `ios` | iOS | `net{x}-ios` | `net{x}-ios` | +| `android` | Android | `net{x}-android` | `net{x}-android` | +| `netstandard` | .NET Standard, no WinUI | `netstandard2.0` | `netstandard2.0` | + +`win32`, `linux` and `macos` all deploy from the same build output on WinUI 3: Uno 6+ replaced the +per-OS Skia heads with a single cross-platform `net{x}-desktop` head that picks its backend at +runtime. They stay separate MultiTargets so a component can declare — and solution generation and +CI can request — only the desktop platforms that are actually supported. + +Mac Catalyst is WinUI 2 only. Uno 7 removes support for it, and on WinUI 3 macOS is reached through +the Skia desktop head instead, so `net{x}-maccatalyst` is not part of the WinUI 3 package surface. ## ProjectReference Generation diff --git a/MultiTarget/Test-Component-Support.ps1 b/MultiTarget/Test-Component-Support.ps1 index 3844dedd..a78c756f 100644 --- a/MultiTarget/Test-Component-Support.ps1 +++ b/MultiTarget/Test-Component-Support.ps1 @@ -32,11 +32,11 @@ Date: 6/6/2025 #> Param ( - [ValidateSet('wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android', 'netstandard')] + [ValidateSet('wasm', 'uwp', 'wasdk', 'wpf', 'win32', 'linux', 'macos', 'ios', 'android', 'netstandard')] [Alias("smt")] [string[]]$SupportedMultiTargets, - [ValidateSet('all', 'wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android', 'netstandard')] + [ValidateSet('all', 'wasm', 'uwp', 'wasdk', 'wpf', 'win32', 'linux', 'macos', 'ios', 'android', 'netstandard')] [Alias("rmt")] [Parameter(Mandatory=$true)] [string[]]$RequestedMultiTargets, @@ -51,17 +51,20 @@ Param ( ) if ($RequestedMultiTargets -eq 'all') { - $RequestedMultiTargets = @('wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android', 'netstandard') + $RequestedMultiTargets = @('wasm', 'uwp', 'wasdk', 'wpf', 'win32', 'linux', 'macos', 'ios', 'android', 'netstandard') } # List of WinUI-0 (non-WinUI) compatible multitargets $WinUI0MultiTargets = @('netstandard') -# List of WinUI-2 compatible multitargets -$WinUI2MultiTargets = @('uwp', 'wasm', 'wpf', 'linuxgtk', 'macos', 'ios', 'android') +# List of WinUI-2 (Uno 5.x / Uno.UI) compatible multitargets. +# 'linux' is the Skia GTK head there; 'wpf' is the Skia WPF head. +$WinUI2MultiTargets = @('uwp', 'wasm', 'wpf', 'linux', 'macos', 'ios', 'android') -# List of WinUI-3 compatible multitargets -$WinUI3MultiTargets = @('wasdk', 'wasm', 'wpf', 'linuxgtk', 'macos', 'ios', 'android') +# List of WinUI-3 (Uno 7.x / Uno.WinUI) compatible multitargets. +# win32, linux and macos are the desktop surface, all served by the single net10.0-desktop head that +# replaced Uno 5's per-OS Skia heads. 'wpf' stays WinUI 2 only, since Uno 6 dropped Uno.UI.Skia.Wpf. +$WinUI3MultiTargets = @('wasdk', 'wasm', 'win32', 'linux', 'macos', 'ios', 'android') # If WinUI 0 is requested, the component must not support WinUI 2 or WinUI 3 to be built. # If WinUI 2 or 3 is requested, the component must have a target that supports WinUI 2 or 3 to be built. diff --git a/MultiTarget/UseTargetFrameworks.ps1 b/MultiTarget/UseTargetFrameworks.ps1 index 1fa00ae4..927df5dc 100644 --- a/MultiTarget/UseTargetFrameworks.ps1 +++ b/MultiTarget/UseTargetFrameworks.ps1 @@ -22,19 +22,19 @@ #> Param ( [Parameter(HelpMessage = "The target frameworks to enable.")] - [ValidateSet('all', 'wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android', 'netstandard')] + [ValidateSet('all', 'wasm', 'uwp', 'wasdk', 'wpf', 'win32', 'linux', 'macos', 'ios', 'android', 'netstandard')] [Alias("mt")] [string[]]$MultiTargets = @('uwp', 'wasdk', 'wasm'), # default settings [Parameter(HelpMessage = "The target frameworks to disable.")] - [ValidateSet('wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android', 'netstandard')] + [ValidateSet('wasm', 'uwp', 'wasdk', 'wpf', 'win32', 'linux', 'macos', 'ios', 'android', 'netstandard')] [string[]]$ExcludeMultiTargets = @() # default settings ) $fileContents = Get-Content -Path $PSScriptRoot/EnabledMultiTargets.props $newFileContents = $fileContents; -$AllMultiTargets = @('wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android', 'netstandard') +$AllMultiTargets = @('wasm', 'uwp', 'wasdk', 'wpf', 'win32', 'linux', 'macos', 'ios', 'android', 'netstandard') # Exclude as needed foreach ($excluded in $ExcludeMultiTargets) { diff --git a/MultiTarget/UseUnoWinUI.ps1 b/MultiTarget/UseUnoWinUI.ps1 index 7b419a43..e260c3dd 100644 --- a/MultiTarget/UseUnoWinUI.ps1 +++ b/MultiTarget/UseUnoWinUI.ps1 @@ -11,14 +11,12 @@ function ApplyWinUISwap([string] $filePath) { $fileContents = $fileContents -replace '2', '3'; $fileContents = $fileContents -replace 'Uwp', 'WinUI'; $fileContents = $fileContents -replace 'Uwp', 'WinUI'; - $fileContents = $fileContents -replace 'Uno.UI', 'Uno.WinUI'; } if ($winUIMajorVersion -eq "2") { $fileContents = $fileContents -replace '3', '2'; $fileContents = $fileContents -replace 'WinUI', 'Uwp'; $fileContents = $fileContents -replace 'WinUI', 'Uwp'; - $fileContents = $fileContents -replace 'Uno.WinUI', 'Uno.UI'; } Set-Content -Force -Path $filePath -Value $fileContents; @@ -27,7 +25,6 @@ function ApplyWinUISwap([string] $filePath) { Write-Output "Switching Uno to WinUI $winUIMajorVersion"; -ApplyWinUISwap $PSScriptRoot/../ProjectHeads/App.Head.Uno.props ApplyWinUISwap $PSScriptRoot/PackageReferences/Uno.props ApplyWinUISwap $PSScriptRoot/WinUI.TargetVersion.props diff --git a/ProjectHeads/AllComponents/Uno/Assets/Icons/icon.svg b/ProjectHeads/AllComponents/Uno/Assets/Icons/icon.svg new file mode 100644 index 00000000..a15af53a --- /dev/null +++ b/ProjectHeads/AllComponents/Uno/Assets/Icons/icon.svg @@ -0,0 +1,42 @@ + + + + + + diff --git a/ProjectHeads/AllComponents/Uno/Assets/Icons/icon_foreground.svg b/ProjectHeads/AllComponents/Uno/Assets/Icons/icon_foreground.svg new file mode 100644 index 00000000..8ffc41ae --- /dev/null +++ b/ProjectHeads/AllComponents/Uno/Assets/Icons/icon_foreground.svg @@ -0,0 +1,137 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ProjectHeads/AllComponents/Uno/Assets/SharedAssets.md b/ProjectHeads/AllComponents/Uno/Assets/SharedAssets.md new file mode 100644 index 00000000..b1cc4e76 --- /dev/null +++ b/ProjectHeads/AllComponents/Uno/Assets/SharedAssets.md @@ -0,0 +1,32 @@ +# Shared Assets + +See documentation about assets here: https://github.com/unoplatform/uno/blob/master/doc/articles/features/working-with-assets.md + +## Here is a cheat sheet + +1. Add the image file to the `Assets` directory of a shared project. +2. Set the build action to `Content`. +3. (Recommended) Provide an asset for various scales/dpi + +### Examples + +```text +\Assets\Images\logo.scale-100.png +\Assets\Images\logo.scale-200.png +\Assets\Images\logo.scale-400.png + +\Assets\Images\scale-100\logo.png +\Assets\Images\scale-200\logo.png +\Assets\Images\scale-400\logo.png +``` + +### Table of scales + +| Scale | WinUI | iOS | Android | +|-------|:-----------:|:---------------:|:-------:| +| `100` | scale-100 | @1x | mdpi | +| `125` | scale-125 | N/A | N/A | +| `150` | scale-150 | N/A | hdpi | +| `200` | scale-200 | @2x | xhdpi | +| `300` | scale-300 | @3x | xxhdpi | +| `400` | scale-400 | N/A | xxxhdpi | diff --git a/ProjectHeads/AllComponents/Uno/Assets/Splash/splash_screen.svg b/ProjectHeads/AllComponents/Uno/Assets/Splash/splash_screen.svg new file mode 100644 index 00000000..8ffc41ae --- /dev/null +++ b/ProjectHeads/AllComponents/Uno/Assets/Splash/splash_screen.svg @@ -0,0 +1,137 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ProjectHeads/AllComponents/Uno/CommunityToolkit.App.Uno.csproj b/ProjectHeads/AllComponents/Uno/CommunityToolkit.App.Uno.csproj new file mode 100644 index 00000000..27259efc --- /dev/null +++ b/ProjectHeads/AllComponents/Uno/CommunityToolkit.App.Uno.csproj @@ -0,0 +1,131 @@ + + + + + + + + true + + + $(TargetFrameworks)net10.0-desktop; + $(TargetFrameworks)net10.0-browserwasm; + $(TargetFrameworks)net10.0-android; + $(TargetFrameworks)net10.0-ios; + + + + Exe + + + SkiaRenderer; + + + false + true + + + true + true + CommunityToolkit.App.Uno + + + true + true + true + true + true + true + true + true + true + true + 3 + true + WinUI + + $(DefineConstants);WINUI3 + + + + + + + + + + + + net10.0 + net10.0-android + net10.0-ios + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SourceAssets/%(RecursiveDir)%(FileName)%(Extension) + + + SourceAssets/%(RecursiveDir)%(FileName)%(Extension) + + + SourceAssets/%(RecursiveDir)%(FileName)%(Extension).dat + + + + + + $(NoWarn);IL2026;Uno0006 + + + + diff --git a/ProjectHeads/AllComponents/Uno/Platforms/Android/AndroidManifest.xml b/ProjectHeads/AllComponents/Uno/Platforms/Android/AndroidManifest.xml new file mode 100644 index 00000000..24ee4aea --- /dev/null +++ b/ProjectHeads/AllComponents/Uno/Platforms/Android/AndroidManifest.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/ProjectHeads/AllComponents/Uno/Platforms/Android/Assets/AboutAssets.txt b/ProjectHeads/AllComponents/Uno/Platforms/Android/Assets/AboutAssets.txt new file mode 100644 index 00000000..6b8fc66e --- /dev/null +++ b/ProjectHeads/AllComponents/Uno/Platforms/Android/Assets/AboutAssets.txt @@ -0,0 +1,5 @@ +Any raw assets you want to be deployed with your application can be placed in this +directory (and child directories). Deployment of the asset to your application is done +using the IDE or by using the following MSBuild property in your .csproj: + + diff --git a/ProjectHeads/AllComponents/Uno/Platforms/Android/Main.Android.cs b/ProjectHeads/AllComponents/Uno/Platforms/Android/Main.Android.cs new file mode 100644 index 00000000..31d89a6f --- /dev/null +++ b/ProjectHeads/AllComponents/Uno/Platforms/Android/Main.Android.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Android.App; +using Android.Runtime; + +namespace CommunityToolkit.App.Uno; + +[global::Android.App.ApplicationAttribute( + Label = "@string/ApplicationName", + Icon = "@mipmap/icon", + LargeHeap = true, + HardwareAccelerated = true, + Theme = "@style/AppTheme" +)] +public class Application : Microsoft.UI.Xaml.NativeApplication +{ + public Application(IntPtr javaReference, JniHandleOwnership transfer) + : base(() => new CommunityToolkit.App.Shared.App(), javaReference, transfer) + { + } +} \ No newline at end of file diff --git a/ProjectHeads/AllComponents/Uno/Platforms/Android/MainActivity.Android.cs b/ProjectHeads/AllComponents/Uno/Platforms/Android/MainActivity.Android.cs new file mode 100644 index 00000000..ad38d011 --- /dev/null +++ b/ProjectHeads/AllComponents/Uno/Platforms/Android/MainActivity.Android.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Android.App; +using Android.Content.PM; +using Android.OS; +using Android.Views; +using Android.Widget; + +namespace CommunityToolkit.App.Uno; + +[Activity( + MainLauncher = true, + ConfigurationChanges = global::Uno.UI.ActivityHelper.AllConfigChanges, + WindowSoftInputMode = SoftInput.AdjustNothing | SoftInput.StateHidden +)] +public class MainActivity : Microsoft.UI.Xaml.ApplicationActivity +{ +} \ No newline at end of file diff --git a/ProjectHeads/AllComponents/Uno/Platforms/Android/Resources/values/Strings.xml b/ProjectHeads/AllComponents/Uno/Platforms/Android/Resources/values/Strings.xml new file mode 100644 index 00000000..ee06a129 --- /dev/null +++ b/ProjectHeads/AllComponents/Uno/Platforms/Android/Resources/values/Strings.xml @@ -0,0 +1,4 @@ + + + CommunityToolkit + diff --git a/ProjectHeads/AllComponents/Uno/Platforms/Android/Resources/values/Styles.xml b/ProjectHeads/AllComponents/Uno/Platforms/Android/Resources/values/Styles.xml new file mode 100644 index 00000000..2c3bf24a --- /dev/null +++ b/ProjectHeads/AllComponents/Uno/Platforms/Android/Resources/values/Styles.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/ProjectHeads/AllComponents/Uno/Platforms/Android/environment.conf b/ProjectHeads/AllComponents/Uno/Platforms/Android/environment.conf new file mode 100644 index 00000000..9d9709a9 --- /dev/null +++ b/ProjectHeads/AllComponents/Uno/Platforms/Android/environment.conf @@ -0,0 +1,2 @@ +## Mono GC tuning params +MONO_GC_PARAMS=soft-heap-limit=512m,nursery-size=64m,evacuation-threshold=66,major=marksweep,concurrent-sweep diff --git a/ProjectHeads/AllComponents/Uno/Platforms/Desktop/Program.cs b/ProjectHeads/AllComponents/Uno/Platforms/Desktop/Program.cs new file mode 100644 index 00000000..2f5400b3 --- /dev/null +++ b/ProjectHeads/AllComponents/Uno/Platforms/Desktop/Program.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Uno.UI.Hosting; +using CommunityToolkit.App.Shared; + +internal class Program +{ + [STAThread] + public static void Main(string[] args) + { + var host = UnoPlatformHostBuilder.Create() + .App(() => new CommunityToolkit.App.Shared.App()) + .UseX11() + .UseLinuxFrameBuffer() + .UseMacOS() + .UseWin32() + .Build(); + + host.Run(); + } +} \ No newline at end of file diff --git a/ProjectHeads/AllComponents/Uno/Platforms/WebAssembly/LinkerConfig.xml b/ProjectHeads/AllComponents/Uno/Platforms/WebAssembly/LinkerConfig.xml new file mode 100644 index 00000000..cc3e5cdd --- /dev/null +++ b/ProjectHeads/AllComponents/Uno/Platforms/WebAssembly/LinkerConfig.xml @@ -0,0 +1,3 @@ + + + diff --git a/ProjectHeads/AllComponents/Uno/Platforms/WebAssembly/Program.cs b/ProjectHeads/AllComponents/Uno/Platforms/WebAssembly/Program.cs new file mode 100644 index 00000000..f07914ec --- /dev/null +++ b/ProjectHeads/AllComponents/Uno/Platforms/WebAssembly/Program.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Uno.UI.Hosting; +using CommunityToolkit.App.Shared; + +public class Program +{ + public static async Task Main(string[] args) + { + var host = UnoPlatformHostBuilder.Create() + .App(() => new CommunityToolkit.App.Shared.App()) + .UseWebAssembly() + .Build(); + + await host.RunAsync(); + } +} \ No newline at end of file diff --git a/ProjectHeads/AllComponents/Uno/Platforms/WebAssembly/WasmScripts/AppManifest.js b/ProjectHeads/AllComponents/Uno/Platforms/WebAssembly/WasmScripts/AppManifest.js new file mode 100644 index 00000000..8018667f --- /dev/null +++ b/ProjectHeads/AllComponents/Uno/Platforms/WebAssembly/WasmScripts/AppManifest.js @@ -0,0 +1,3 @@ +var UnoAppManifest = { + displayName: "CommunityToolkit" +} diff --git a/ProjectHeads/AllComponents/Uno/Platforms/WebAssembly/manifest.webmanifest b/ProjectHeads/AllComponents/Uno/Platforms/WebAssembly/manifest.webmanifest new file mode 100644 index 00000000..8d6e55be --- /dev/null +++ b/ProjectHeads/AllComponents/Uno/Platforms/WebAssembly/manifest.webmanifest @@ -0,0 +1,10 @@ +{ + "name": "CommunityToolkit", + "description": "CommunityToolkit", + "short_name": "CommunityToolkit", + "start_url": "/index.html", + "display": "standalone", + "background_color": "#FFFFFF", + "theme_color": "#FFFFFF", + "scope": "/" +} diff --git a/ProjectHeads/AllComponents/Uno/Platforms/iOS/Entitlements.plist b/ProjectHeads/AllComponents/Uno/Platforms/iOS/Entitlements.plist new file mode 100644 index 00000000..6631ffa6 --- /dev/null +++ b/ProjectHeads/AllComponents/Uno/Platforms/iOS/Entitlements.plist @@ -0,0 +1,6 @@ + + + + + + diff --git a/ProjectHeads/AllComponents/Uno/Platforms/iOS/Info.plist b/ProjectHeads/AllComponents/Uno/Platforms/iOS/Info.plist new file mode 100644 index 00000000..8f81dd88 --- /dev/null +++ b/ProjectHeads/AllComponents/Uno/Platforms/iOS/Info.plist @@ -0,0 +1,43 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + + CFBundleIdentifier + com.companyname.CommunityToolkit + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + CommunityToolkit + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + MinimumOSVersion + 16.0 + UIDeviceFamily + + 1 + 2 + + UILaunchStoryboardName + LaunchScreen + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/ProjectHeads/AllComponents/Uno/Platforms/iOS/Main.iOS.cs b/ProjectHeads/AllComponents/Uno/Platforms/iOS/Main.iOS.cs new file mode 100644 index 00000000..b163d7dd --- /dev/null +++ b/ProjectHeads/AllComponents/Uno/Platforms/iOS/Main.iOS.cs @@ -0,0 +1,21 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Uno.UI.Hosting; +using CommunityToolkit.App.Shared; + +namespace CommunityToolkit.App.Uno; + +public class EntryPoint +{ + public static void Main(string[] args) + { + var host = UnoPlatformHostBuilder.Create() + .App(() => new CommunityToolkit.App.Shared.App()) + .UseAppleUIKit() + .Build(); + + host.Run(); + } +} \ No newline at end of file diff --git a/ProjectHeads/AllComponents/Uno/Platforms/iOS/Media.xcassets/LaunchImages.launchimage/Contents.json b/ProjectHeads/AllComponents/Uno/Platforms/iOS/Media.xcassets/LaunchImages.launchimage/Contents.json new file mode 100644 index 00000000..4103a707 --- /dev/null +++ b/ProjectHeads/AllComponents/Uno/Platforms/iOS/Media.xcassets/LaunchImages.launchimage/Contents.json @@ -0,0 +1,20 @@ +{ + "images": [ + { + "idiom": "universal", + "scale": "1x" + }, + { + "idiom": "universal", + "scale": "2x" + }, + { + "idiom": "universal", + "scale": "3x" + } + ], + "info": { + "version": 1, + "author": "xcode" + } +} diff --git a/ProjectHeads/AllComponents/Uno/Platforms/iOS/PrivacyInfo.xcprivacy b/ProjectHeads/AllComponents/Uno/Platforms/iOS/PrivacyInfo.xcprivacy new file mode 100644 index 00000000..1d00d2f5 --- /dev/null +++ b/ProjectHeads/AllComponents/Uno/Platforms/iOS/PrivacyInfo.xcprivacy @@ -0,0 +1,31 @@ + + + + + NSPrivacyTracking + + NSPrivacyTrackingDomains + + NSPrivacyCollectedDataTypes + + NSPrivacyAccessedAPITypes + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategorySystemBootTime + NSPrivacyAccessedAPITypeReasons + + 35F9.1 + + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryFileTimestamp + NSPrivacyAccessedAPITypeReasons + + C617.1 + + + + + diff --git a/ProjectHeads/AllComponents/Wasm/CommunityToolkit.App.Wasm.csproj b/ProjectHeads/AllComponents/Wasm/CommunityToolkit.App.Wasm.csproj index ad0e0d70..3510eeed 100644 --- a/ProjectHeads/AllComponents/Wasm/CommunityToolkit.App.Wasm.csproj +++ b/ProjectHeads/AllComponents/Wasm/CommunityToolkit.App.Wasm.csproj @@ -11,11 +11,12 @@ wasm + + - diff --git a/ProjectHeads/AllComponents/Wasm/Program.cs b/ProjectHeads/AllComponents/Wasm/Program.cs index 43e990c1..a7aae2ee 100644 --- a/ProjectHeads/AllComponents/Wasm/Program.cs +++ b/ProjectHeads/AllComponents/Wasm/Program.cs @@ -5,7 +5,7 @@ using CommunityToolkit.App.Shared; #if WINAPPSDK -using Microsoft.UI.Xaml; +using Uno.UI.Hosting; #else using Windows.UI.Xaml; #endif @@ -14,6 +14,17 @@ namespace CommunityToolkit.App.Wasm; public class Program { +#if WINAPPSDK + static async Task Main(string[] args) + { + var host = UnoPlatformHostBuilder.Create() + .App(() => new CommunityToolkit.App.Shared.App()) + .UseWebAssembly() + .Build(); + + await host.RunAsync(); + } +#else private static CommunityToolkit.App.Shared.App? _app; static int Main(string[] args) @@ -22,4 +33,5 @@ static int Main(string[] args) return 0; } +#endif } diff --git a/ProjectHeads/App.Head.Android.props b/ProjectHeads/App.Head.Android.props new file mode 100644 index 00000000..2a864dec --- /dev/null +++ b/ProjectHeads/App.Head.Android.props @@ -0,0 +1,7 @@ + + + + + false + + diff --git a/ProjectHeads/App.Head.Uno.UI.Dependencies.props b/ProjectHeads/App.Head.Uno.UI.Dependencies.props index 361463b9..49fe326c 100644 --- a/ProjectHeads/App.Head.Uno.UI.Dependencies.props +++ b/ProjectHeads/App.Head.Uno.UI.Dependencies.props @@ -6,5 +6,3 @@ - - diff --git a/ProjectHeads/App.Head.Uno.WinUI.Dependencies.props b/ProjectHeads/App.Head.Uno.WinUI.Dependencies.props index d18fbfb5..172299f4 100644 --- a/ProjectHeads/App.Head.Uno.WinUI.Dependencies.props +++ b/ProjectHeads/App.Head.Uno.WinUI.Dependencies.props @@ -4,6 +4,16 @@ - + + + + + + + + $(DefineConstants);HAS_LABS_MARKDOWNTEXTBLOCK + + + diff --git a/ProjectHeads/App.Head.Uno.props b/ProjectHeads/App.Head.Uno.props index 865ea717..6f5cafab 100644 --- a/ProjectHeads/App.Head.Uno.props +++ b/ProjectHeads/App.Head.Uno.props @@ -1,6 +1,7 @@ - WinUI + WinUI + Uwp @@ -25,8 +26,9 @@ - + + diff --git a/ProjectHeads/App.Head.Wasm.props b/ProjectHeads/App.Head.Wasm.props index ed7c9705..32487037 100644 --- a/ProjectHeads/App.Head.Wasm.props +++ b/ProjectHeads/App.Head.Wasm.props @@ -2,6 +2,7 @@ Exe $(WasmHeadTargetFramework.Split(';')[0]) + false + + + + + true + + + $(TargetFrameworks)net10.0-desktop; + $(TargetFrameworks)net10.0-browserwasm; + $(TargetFrameworks)net10.0-android; + $(TargetFrameworks)net10.0-ios; + + + + Exe + ProjectTemplate.Samples + ProjectTemplate.Samples.Uno + + + SkiaRenderer; + + + false + true + + + true + true + + + true + true + true + true + true + true + true + true + true + true + 3 + true + WinUI + + $(DefineConstants);WINUI3 + + + + + + + + net10.0 + net10.0-android + net10.0-ios + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SourceAssets/%(RecursiveDir)%(FileName)%(Extension).dat + + + + + + + $(NoWarn);IL2026;Uno0006 + + + + diff --git a/ProjectHeads/SingleComponent/Wasm/Program.cs b/ProjectHeads/SingleComponent/Wasm/Program.cs index 9522ede6..91bd1b52 100644 --- a/ProjectHeads/SingleComponent/Wasm/Program.cs +++ b/ProjectHeads/SingleComponent/Wasm/Program.cs @@ -4,10 +4,25 @@ using CommunityToolkit.App.Shared; +#if WINAPPSDK +using Uno.UI.Hosting; +#endif + namespace ProjectTemplateExperiment.Samples.Wasm; public class Program { +#if WINAPPSDK + static async Task Main(string[] args) + { + var host = UnoPlatformHostBuilder.Create() + .App(() => new App()) + .UseWebAssembly() + .Build(); + + await host.RunAsync(); + } +#else private static App? _app; static int Main(string[] args) @@ -16,4 +31,5 @@ static int Main(string[] args) return 0; } +#endif } diff --git a/ProjectHeads/Targets/AddMultiTargetCompatibleSampleDocs.targets b/ProjectHeads/Targets/AddMultiTargetCompatibleSampleDocs.targets index 02d0ea88..6f16a26e 100644 --- a/ProjectHeads/Targets/AddMultiTargetCompatibleSampleDocs.targets +++ b/ProjectHeads/Targets/AddMultiTargetCompatibleSampleDocs.targets @@ -8,10 +8,22 @@ uwp wasm wasdk + wpf + win32 + linux macos ios android netstandard + + + + $(MultiTargetIdentifier)win32; + $(MultiTargetIdentifier)linux; + $(MultiTargetIdentifier)macos; diff --git a/ProjectHeads/Tasks/CheckMultiTarget.props b/ProjectHeads/Tasks/CheckMultiTarget.props index 812b68fe..2b9c581b 100644 --- a/ProjectHeads/Tasks/CheckMultiTarget.props +++ b/ProjectHeads/Tasks/CheckMultiTarget.props @@ -120,7 +120,22 @@ multiTargetIdentifier = ExtractMultiTargetIdentifier(multiTargetPropsContent); } - IsSupported = multiTargetIdentifier.Split(';').Contains(MultiTargetIdentifier); + // MultiTargetIdentifier may be a ';' separated list: the unified Uno desktop head covers + // several MultiTargets with a single build, so a doc matching any one of them is supported. + string[] componentMultiTargets = multiTargetIdentifier.Split(';'); + IsSupported = false; + + foreach (string headMultiTarget in MultiTargetIdentifier.Split(';')) + { + string trimmedHeadMultiTarget = headMultiTarget.Trim(); + + if (trimmedHeadMultiTarget.Length > 0 && componentMultiTargets.Contains(trimmedHeadMultiTarget)) + { + IsSupported = true; + break; + } + } + FilePath.SetMetadata("IsSupported", IsSupported.ToString()); ]]> diff --git a/ProjectTemplate/src/MultiTarget.props b/ProjectTemplate/src/MultiTarget.props index b11c1942..7d1e11c3 100644 --- a/ProjectTemplate/src/MultiTarget.props +++ b/ProjectTemplate/src/MultiTarget.props @@ -4,6 +4,6 @@ MultiTarget is a custom property that indicates which target a project is designed to be built for / run on. Used to create project references, generate solution files, enable/disable TargetFrameworks, and build nuget packages. --> - uwp;wasdk;wpf;wasm;linuxgtk;macos;ios;android; + uwp;wasdk;wpf;win32;wasm;linux;macos;ios;android; \ No newline at end of file diff --git a/global.json b/global.json index 5d4b9f49..7f21440e 100644 --- a/global.json +++ b/global.json @@ -3,8 +3,9 @@ "version": "10.0.401", "rollForward": "latestFeature" }, - "msbuild-sdks": + "msbuild-sdks": { - "MSBuild.Sdk.Extras":"3.0.44" + "MSBuild.Sdk.Extras":"3.0.44", + "Uno.Sdk": "7.0.0-dev.51" } }