diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..86f45b92 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,13 @@ +version: 2 +updates: + # The workflows pin every action to a commit SHA with its version in a comment; Dependabot bumps both. + # All action updates come in one PR, since each PR's Build run needs approval on the pr-build environment. + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + groups: + github-actions: + patterns: ['*'] + commit-message: + prefix: ci diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 410313aa..312895f2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,49 +1,122 @@ -name: Build Controls & Gallery - -# This workflow builds the iNKORE.UI.WPF.Modern.Controls and iNKORE.UI.WPF.Modern.Gallery projects and uploads the artifacts for use in other workflows or releases. +name: Build +# Builds the NuGet package and the Gallery and keeps them as run artifacts; nothing is published (see release.yml). +# Pull requests wait for a maintainer to approve the pr-build environment first; v* tags build right away. on: - push: - branches: [ ] pull_request: - branches: [ ] + push: + tags: ['v*'] workflow_dispatch: +permissions: + contents: read + +# A new push to a PR cancels the older run that is still waiting for approval. +concurrency: + group: build-${{ github.event.pull_request.number || github.run_id }} + cancel-in-progress: true + jobs: + approve: + if: github.event_name == 'pull_request' + runs-on: ubuntu-latest + environment: pr-build # the required reviewers on this environment are the approval gate + steps: + - run: echo "Approved" + build: + needs: approve + if: ${{ !cancelled() && (needs.approve.result == 'success' || needs.approve.result == 'skipped') }} + runs-on: windows-latest + outputs: + version: ${{ steps.version.outputs.version }} + package: ${{ steps.files.outputs.package }} + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - uses: microsoft/setup-msbuild@30375c66a4eea26614e0d39710365f22f8b0af57 # v3.0.0 + + - name: Choose version + id: version + shell: pwsh + run: | + if ($env:GITHUB_REF_TYPE -eq 'tag' -and $env:GITHUB_REF_NAME -like 'v*') { $arg = "-p:Version=$($env:GITHUB_REF_NAME.Substring(1))" } + else { $arg = "-p:VersionSuffix=ci.$env:GITHUB_RUN_NUMBER" } + "VERSION_ARG=$arg" >> $env:GITHUB_ENV + # The version the package should come out with; test-package checks it against this. + $version = msbuild source/iNKORE.UI.WPF.Modern.Controls/iNKORE.UI.WPF.Modern.Controls.csproj -getProperty:Version $arg + "version=$version" >> $env:GITHUB_OUTPUT + + - name: Build solution + shell: pwsh + run: >- + msbuild iNKORE.UI.WPF.Modern.sln -restore + -p:Configuration=Release "-p:Platform=Any CPU" -p:ContinuousIntegrationBuild=true $env:VERSION_ARG + + - name: Pack + shell: pwsh + run: >- + msbuild source/iNKORE.UI.WPF.Modern.Controls/iNKORE.UI.WPF.Modern.Controls.csproj -t:Pack -p:NoBuild=true + -p:Configuration=Release -p:ContinuousIntegrationBuild=true $env:VERSION_ARG + + # name@version keeps the boundary between name and version clear. The nupkg keeps NuGet's id.version.nupkg + # name on purpose: local folder feeds find packages by that file name, so renaming it breaks restore (NU1102). + - name: Zip Gallery + id: files + shell: pwsh + run: | + $package = Get-Item .nuget/iNKORE.UI.WPF.Modern.*.nupkg + $gallery = "iNKORE.UI.WPF.Modern.Gallery@$($package.BaseName.Substring('iNKORE.UI.WPF.Modern.'.Length)).zip" + New-Item -ItemType Directory -Force artifacts | Out-Null + Compress-Archive -Path source/iNKORE.UI.WPF.Modern.Gallery/bin/Release/net6.0-windows10.0.18362.0/* ` + -DestinationPath "artifacts/$gallery" + "package=$($package.Name)" >> $env:GITHUB_OUTPUT + "gallery=$gallery" >> $env:GITHUB_OUTPUT + + # archive: false uploads each file as is, so the artifact is the file itself, named after it, + # instead of a zip wrapped around it. Download them with download-artifact@v8 by that name. + - name: Upload package + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 + with: + path: .nuget/${{ steps.files.outputs.package }} + archive: false + include-hidden-files: true # .nuget/ is a dot folder, which upload-artifact skips by default + if-no-files-found: error + + - name: Upload Gallery + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 + with: + path: artifacts/${{ steps.files.outputs.gallery }} + archive: false + if-no-files-found: error + + # Checks the package's layout and versions, then builds small WPF apps against it and runs them (tests/Package). + # A failure here fails the run, and release.yml only releases a tag whose Build run succeeded. + test-package: + needs: build + # Without this the job is skipped on tag builds (approve is skipped there), and the run would still succeed. + if: ${{ !cancelled() && needs.build.result == 'success' }} runs-on: windows-latest - + env: + VERSION: ${{ needs.build.outputs.version }} steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - name: Setup MSBuild - uses: microsoft/setup-msbuild@v1.1 - - - name: Setup .NET - uses: actions/setup-dotnet@v3 - with: - dotnet-version: | - 6.0.x - 7.0.x - - - name: Restore NuGet packages - run: | - nuget restore iNKORE.UI.WPF.Modern.sln - - - name: Build solution - run: | - msbuild iNKORE.UI.WPF.Modern.sln /p:Configuration=Release /p:Platform="Any CPU" - - - name: Upload Controls artifact (.NET 6.0) - uses: actions/upload-artifact@v4 - with: - name: iNKORE.UI.WPF.Modern.Controls - path: source\iNKORE.UI.WPF.Modern.Controls\bin\Release\net6.0-windows10.0.18362.0 - - - name: Upload Gallery artifact - uses: actions/upload-artifact@v4 - with: - name: iNKORE.UI.WPF.Modern.Gallery - path: source\iNKORE.UI.WPF.Modern.Gallery\bin\Release\net6.0-windows10.0.18362.0 \ No newline at end of file + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - uses: microsoft/setup-msbuild@30375c66a4eea26614e0d39710365f22f8b0af57 # v3.0.0 + + - uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 + with: + dotnet-version: 8.0.x # the net8.0 consumer runs on it + + - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 + with: + name: ${{ needs.build.outputs.package }} + path: nupkg + + - name: Check package structure + shell: pwsh + run: tests/Package/Test-PackageStructure.ps1 -Package (Get-Item nupkg/*.nupkg).FullName -Version $env:VERSION + + - name: Build and run consumers + shell: pwsh + run: tests/Package/Test-Consumers.ps1 -Package (Get-Item nupkg/*.nupkg).FullName -Version $env:VERSION diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..aed7d725 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,82 @@ +name: Release + +# Publishing a GitHub release for a v* tag (written by hand on the Releases page) starts this. +# After approval on the nuget environment, the tag's Build outputs are pushed to NuGet.org and attached to the release. +# To retry, run it by hand on the tag (Use workflow from -> Tags); both steps are safe to repeat. +on: + release: + types: [published] + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: release-${{ github.ref_name }} + +jobs: + publish: + if: github.ref_type == 'tag' && startsWith(github.ref_name, 'v') + runs-on: ubuntu-latest + environment: nuget # the required reviewers on this environment approve every release + permissions: + actions: read # download the tag build's artifacts + contents: write # attach files to the release + id-token: write # NuGet trusted publishing + env: + TAG: ${{ github.ref_name }} + GH_TOKEN: ${{ github.token }} + GH_REPO: ${{ github.repository }} + steps: + # Build uploads the nupkg and the Gallery zip unwrapped (archive: false): each artifact is named after its file. + - name: Find the tag's build + id: build + run: | + run_id=$(gh run list --workflow build.yml --branch "$TAG" --event push --status success --limit 1 --json databaseId --jq '.[0].databaseId') + if [ -z "$run_id" ]; then + echo "::error::No successful Build run for $TAG yet. Wait for it to finish (or re-run it), then re-run this workflow." + exit 1 + fi + artifacts=$(gh api "repos/$GH_REPO/actions/runs/$run_id/artifacts" --jq '.artifacts[] | select(.expired | not) | .name') + package=$(grep -E '\.nupkg$' <<< "$artifacts" || true) + gallery=$(grep -E '^iNKORE\.UI\.WPF\.Modern\.Gallery@.*\.zip$' <<< "$artifacts" || true) + if [ -z "$package" ] || [ -z "$gallery" ]; then + echo "::error::Build run $run_id for $TAG has no package or Gallery artifact (expired?). Re-run that build, then this workflow." + exit 1 + fi + echo "run-id=$run_id" >> "$GITHUB_OUTPUT" + echo "package=$package" >> "$GITHUB_OUTPUT" + echo "gallery=$gallery" >> "$GITHUB_OUTPUT" + + - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 + with: + name: ${{ steps.build.outputs.package }} + run-id: ${{ steps.build.outputs.run-id }} + github-token: ${{ github.token }} + path: dist + + - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 + with: + name: ${{ steps.build.outputs.gallery }} + run-id: ${{ steps.build.outputs.run-id }} + github-token: ${{ github.token }} + path: dist + + # dotnet nuget push needs an SDK; install one rather than rely on what the runner image happens to ship. + - uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 + with: + dotnet-version: 10.0.x + + - name: NuGet login + uses: NuGet/login@8d196754b4036150537f80ac539e15c2f1028841 # v1.2.0 + id: login + with: + user: ${{ secrets.NUGET_USER }} + + - name: Push to NuGet.org + run: >- + dotnet nuget push "dist/*.nupkg" --api-key "${{ steps.login.outputs.NUGET_API_KEY }}" + --source https://api.nuget.org/v3/index.json --skip-duplicate + + - name: Attach files to the release + run: gh release upload "$TAG" dist/* --clobber diff --git a/.gitignore b/.gitignore index 1a57092e..47780c65 100644 --- a/.gitignore +++ b/.gitignore @@ -209,6 +209,7 @@ PublishScripts/ # Nuget personal access tokens and Credentials nuget.config +!tests/Package/Consumers/nuget.config # Microsoft Azure Build Output csx/ diff --git a/Directory.Build.props b/Directory.Build.props index cc0a2e7e..d921912d 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,6 +1,15 @@  - - iNKORE.UI.WPF.Modern - latest - - + + iNKORE.UI.WPF.Modern + latest + + + + + 0.10.2 + + + false + + \ No newline at end of file diff --git a/Directory.Build.targets b/Directory.Build.targets index 96aadd3d..37aba4ab 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -1,72 +1,102 @@  - - MIT - https://github.com/InkoreStudios/UI.WPF.Modern - WPF XAML UI Theme Controls Fluent Modern Metro WinUI - $(MSBuildThisFileDirectory)artifacts - + + $(MSBuildThisFileDirectory).nuget + - - True - + + + + 1.2.8 + + - - $(DefineConstants);NET461_OR_NEWER - - - $(DefineConstants);NET462_OR_NEWER - - - $(DefineConstants);NET47_OR_NEWER - - - $(DefineConstants);NET472_OR_NEWER - - - $(DefineConstants);NET48_OR_NEWER - - - $(DefineConstants);NET5_0_OR_NEWER - + + + + <_VersionAttributesFile>$(IntermediateOutputPath)$(AssemblyName).VersionInfo.g.cs + + + <_VersionAttributesLine Include="[assembly: System.Reflection.AssemblyVersion("$(AssemblyVersion)")]" /> + <_VersionAttributesLine Include="[assembly: System.Reflection.AssemblyFileVersion("$(AssemblyVersion)")]" /> + <_VersionAttributesLine Include="[assembly: System.Reflection.AssemblyInformationalVersion("$(Version)")]" /> + + + + + + + + - - 7.0 - - - - - - - - - + + True + + + + $(DefineConstants);NET461_OR_NEWER + + + $(DefineConstants);NET462_OR_NEWER + + + $(DefineConstants);NET47_OR_NEWER + + + $(DefineConstants);NET472_OR_NEWER + + + $(DefineConstants);NET48_OR_NEWER + + + $(DefineConstants);NET5_0_OR_NEWER + + + + 7.0 + + + + + + + + + + + + + + + $(MSBuildThisFileDirectory)libraries\Windows.WinMD + true + false + + + $(MSBuildThisFileDirectory)libraries\Windows.Foundation.FoundationContract.winmd + true + false + + + $(MSBuildThisFileDirectory)libraries\Windows.Foundation.UniversalApiContract.winmd + true + false + + + + - - - - - $(MSBuildThisFileDirectory)libraries\Windows.WinMD - true - false - - - $(MSBuildThisFileDirectory)libraries\Windows.Foundation.FoundationContract.winmd - true - false - - - $(MSBuildThisFileDirectory)libraries\Windows.Foundation.UniversalApiContract.winmd - true - false - - - - - - + diff --git a/assets/nuget/README.md b/assets/nuget/README.md new file mode 100644 index 00000000..596b9554 --- /dev/null +++ b/assets/nuget/README.md @@ -0,0 +1,28 @@ +Modern (Fluent 2) styles and controls for your WPF applications. + +- Repository: https://github.com/iNKORE-NET/UI.WPF.Modern/ + +- Documentation (Preview): https://docs.inkore.net/ui-wpf-modern/introduction/ + + +--- + +# ✨ Features + +- Modern styles and new features for the majority of the stock WPF controls. + +- Light and dark themes that can be easily customized. A high contrast theme is also included. + +- Mica and acrylic backdrops, snap layouts, and other modern features available. + +- Additional controls to help you build modern applications. With controls ported from the [Windows UI Library](https://github.com/microsoft/microsoft-ui-xaml), Community Toolkit, and also custom controls made by us. + +- Targets .NET Framework, .NET 6.0 or higher. Runs on Windows 7 or higher (Windows 10 or higher recommended). *(We will never leave Windows 7 users behind until the market **FULLY** says goodbye to it)* + + + +# 🤔 How to use + +- Check out the [Getting Started](https://docs.inkore.net/ui-wpf-modern/onboarding) guide on our documentation site. + +- We're currently working on a documentation site that simplifies your learning curve. However this can be a huge process. You can preview the documentation site at [docs.inkore.net/ui-wpf-modern](https://docs.inkore.net/ui-wpf-modern/introduction) (remember it's not finished yet). Feedback and contributions are welcome and strongly needed. \ No newline at end of file diff --git a/assets/nuget/icon.png b/assets/nuget/icon.png new file mode 100644 index 00000000..c7455137 Binary files /dev/null and b/assets/nuget/icon.png differ diff --git a/source/iNKORE.UI.WPF.Modern.Controls/Controls/Windows/InfoBar/Strings/Resources.ca-Es-VALENCIA.resx b/source/iNKORE.UI.WPF.Modern.Controls/Controls/Windows/InfoBar/Strings/Resources.ca-ES-valencia.resx similarity index 100% rename from source/iNKORE.UI.WPF.Modern.Controls/Controls/Windows/InfoBar/Strings/Resources.ca-Es-VALENCIA.resx rename to source/iNKORE.UI.WPF.Modern.Controls/Controls/Windows/InfoBar/Strings/Resources.ca-ES-valencia.resx diff --git a/source/iNKORE.UI.WPF.Modern.Controls/Controls/Windows/InfoBar/Strings/Resources.gd-gb.resx b/source/iNKORE.UI.WPF.Modern.Controls/Controls/Windows/InfoBar/Strings/Resources.gd-GB.resx similarity index 100% rename from source/iNKORE.UI.WPF.Modern.Controls/Controls/Windows/InfoBar/Strings/Resources.gd-gb.resx rename to source/iNKORE.UI.WPF.Modern.Controls/Controls/Windows/InfoBar/Strings/Resources.gd-GB.resx diff --git a/source/iNKORE.UI.WPF.Modern.Controls/Controls/Windows/PipsPager/Strings/Resources.ca-Es-VALENCIA.resx b/source/iNKORE.UI.WPF.Modern.Controls/Controls/Windows/PipsPager/Strings/Resources.ca-ES-valencia.resx similarity index 100% rename from source/iNKORE.UI.WPF.Modern.Controls/Controls/Windows/PipsPager/Strings/Resources.ca-Es-VALENCIA.resx rename to source/iNKORE.UI.WPF.Modern.Controls/Controls/Windows/PipsPager/Strings/Resources.ca-ES-valencia.resx diff --git a/source/iNKORE.UI.WPF.Modern.Controls/Controls/Windows/PipsPager/Strings/Resources.gd-gb.resx b/source/iNKORE.UI.WPF.Modern.Controls/Controls/Windows/PipsPager/Strings/Resources.gd-GB.resx similarity index 100% rename from source/iNKORE.UI.WPF.Modern.Controls/Controls/Windows/PipsPager/Strings/Resources.gd-gb.resx rename to source/iNKORE.UI.WPF.Modern.Controls/Controls/Windows/PipsPager/Strings/Resources.gd-GB.resx diff --git a/source/iNKORE.UI.WPF.Modern.Controls/Controls/Windows/TeachingTip/Strings/Resources.ca-Es-VALENCIA.resx b/source/iNKORE.UI.WPF.Modern.Controls/Controls/Windows/TeachingTip/Strings/Resources.ca-ES-valencia.resx similarity index 100% rename from source/iNKORE.UI.WPF.Modern.Controls/Controls/Windows/TeachingTip/Strings/Resources.ca-Es-VALENCIA.resx rename to source/iNKORE.UI.WPF.Modern.Controls/Controls/Windows/TeachingTip/Strings/Resources.ca-ES-valencia.resx diff --git a/source/iNKORE.UI.WPF.Modern.Controls/Controls/Windows/TeachingTip/Strings/Resources.gd-gb.resx b/source/iNKORE.UI.WPF.Modern.Controls/Controls/Windows/TeachingTip/Strings/Resources.gd-GB.resx similarity index 100% rename from source/iNKORE.UI.WPF.Modern.Controls/Controls/Windows/TeachingTip/Strings/Resources.gd-gb.resx rename to source/iNKORE.UI.WPF.Modern.Controls/Controls/Windows/TeachingTip/Strings/Resources.gd-GB.resx diff --git a/source/iNKORE.UI.WPF.Modern.Controls/iNKORE.UI.WPF.Modern.Controls.csproj b/source/iNKORE.UI.WPF.Modern.Controls/iNKORE.UI.WPF.Modern.Controls.csproj index ca16e6a1..8d2cd09a 100644 --- a/source/iNKORE.UI.WPF.Modern.Controls/iNKORE.UI.WPF.Modern.Controls.csproj +++ b/source/iNKORE.UI.WPF.Modern.Controls/iNKORE.UI.WPF.Modern.Controls.csproj @@ -1,88 +1,82 @@  - - net6.0-windows10.0.18362.0;net452 - true - en-US - $(TargetsForTfmSpecificBuildOutput);GetDocumentationFile - - - false - False - - ..\..\assets\icons\WpfLibrary.ico - True - ..\..\assets\others\iNKORE.Pulic.snk - iNKORE.UI.WPF.Modern + + net6.0-windows10.0.18362.0;net452 + true + en-US + true + $(MSBuildThisFileDirectory)..\iNKORE.UI.WPF.Modern.nuspec + $(MSBuildThisFileDirectory)..\ + false + true + False + + ..\..\assets\icons\WpfLibrary.ico + True + ..\..\assets\others\iNKORE.Pulic.snk + iNKORE.UI.WPF.Modern - $(NoWarn);CS1591;1701;1702;CA1416;CS1573 - + $(NoWarn);CS1591;1701;1702;CA1416;CS1573 + - + - - - + + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - PreserveNewest - - + + + PreserveNewest + + - - - + + + - - - + + + + $(NuspecProperties);version=$(PackageVersion) + $(NuspecProperties);configuration=$(Configuration) + $(NuspecProperties);uiwpfVersion=@(PackageReference->WithMetadataValue('Identity', 'iNKORE.UI.WPF')->'%(Version)') + + diff --git a/source/iNKORE.UI.WPF.Modern.Gallery/iNKORE.UI.WPF.Modern.Gallery.csproj b/source/iNKORE.UI.WPF.Modern.Gallery/iNKORE.UI.WPF.Modern.Gallery.csproj index 565a6fc5..f370bb2b 100644 --- a/source/iNKORE.UI.WPF.Modern.Gallery/iNKORE.UI.WPF.Modern.Gallery.csproj +++ b/source/iNKORE.UI.WPF.Modern.Gallery/iNKORE.UI.WPF.Modern.Gallery.csproj @@ -1,131 +1,132 @@ - - WinExe - net6.0-windows10.0.18362.0 - true - ..\..\assets\icons\WpfLibrary.ico - false - - - - - app.manifest - 7.0 - annotations - - - - 1701;1702;CA1416 - - - - 1701;1702;CA1416 - - - - - PublicResXFileCodeGenerator - Resources.Designer.cs - - - Code - - - True - True - Resources.resx - - - - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - True - True - Settings.settings - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - - - - - - - - MSBuild:Compile - Designer - True - - - - - - - - - - - - $(DefaultXamlRuntime) - Designer - - - - - - PreserveNewest - - + + WinExe + net6.0-windows10.0.18362.0 + true + ..\..\assets\icons\WpfLibrary.ico + false + true + + + + + app.manifest + 7.0 + annotations + + + + 1701;1702;CA1416 + + + + 1701;1702;CA1416 + + + + + PublicResXFileCodeGenerator + Resources.Designer.cs + + + Code + + + True + True + Resources.resx + + + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + True + Settings.settings + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + + + + + + + MSBuild:Compile + Designer + True + + + + + + + + + + + + $(DefaultXamlRuntime) + Designer + + + + + + PreserveNewest + + diff --git a/source/iNKORE.UI.WPF.Modern.nuspec b/source/iNKORE.UI.WPF.Modern.nuspec new file mode 100644 index 00000000..09043e0c --- /dev/null +++ b/source/iNKORE.UI.WPF.Modern.nuspec @@ -0,0 +1,61 @@ + + + + + iNKORE.UI.WPF.Modern + $version$ + iNKORE.UI.WPF.Modern + Yoojun Zhou + iNKORE Studios + false + https://github.com/iNKORE-NET/UI.WPF.Modern/blob/main/LICENSE.md + icon.png + README.md + https://docs.inkore.net/ui-wpf-modern + Modern (Fluent 2) styles and controls for your WPF applications. + Copyright © iNKORE! (iNKORE Studios) 2025. All rights reserved. + en-US + WPF;C#;Modern;Fluent;UI;iNKORE;XAML;Metro;CSharp;dotNET;Controls;Style;UI;WinUI + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/iNKORE.UI.WPF.Modern/Properties/AssemblyInfoCommon.cs b/source/iNKORE.UI.WPF.Modern/Properties/AssemblyInfoCommon.cs index 4247a3ed..bfb091a3 100644 --- a/source/iNKORE.UI.WPF.Modern/Properties/AssemblyInfoCommon.cs +++ b/source/iNKORE.UI.WPF.Modern/Properties/AssemblyInfoCommon.cs @@ -8,5 +8,4 @@ [assembly: AssemblyCopyright("Copyright © iNKORE Studios (iNKORE!) 2025")] [assembly: AssemblyTrademark("iNKORE!")] -[assembly: AssemblyVersion("0.10.2.0")] -[assembly: AssemblyFileVersion("0.10.2.0")] +// AssemblyVersion and AssemblyFileVersion are generated from $(Version) (see Directory.Build.props). diff --git a/source/iNKORE.UI.WPF.Modern/iNKORE.UI.WPF.Modern.csproj b/source/iNKORE.UI.WPF.Modern/iNKORE.UI.WPF.Modern.csproj index ae280737..2a574067 100644 --- a/source/iNKORE.UI.WPF.Modern/iNKORE.UI.WPF.Modern.csproj +++ b/source/iNKORE.UI.WPF.Modern/iNKORE.UI.WPF.Modern.csproj @@ -1,118 +1,121 @@  - - net6.0-windows10.0.18362.0;net452 - true - true - en-US - 1701;1702;1573;1591;CA1416 - false - ..\..\assets\icons\WpfLibrary.ico - True - ..\..\assets\others\iNKORE.Pulic.snk - True + + net6.0-windows10.0.18362.0;net452 + true + true + en-US + 1701;1702;1573;1591;CA1416 + false + true + ..\..\assets\icons\WpfLibrary.ico + True + ..\..\assets\others\iNKORE.Pulic.snk + True true - $(NoWarn);CS1591;1701;1702;CA1416;CS8632 - - - - true - 10.0.18362.0 - - Windows.Foundation; - Windows.UI.Color; - Windows.UI.IColors; - Windows.UI.ViewManagement.HandPreference; - Windows.UI.ViewManagement.IUISettings; - Windows.UI.ViewManagement.UIColorType; - Windows.UI.ViewManagement.UIElementType; - Windows.UI.ViewManagement.UISettings; - - - Windows.Foundation.Diagnostics; - Windows.Foundation.PropertyType; - - disable - - - - - - - - - - - - - - - - - - - - - - - - - - - - ..\..\libraries\Windows.WinMD - true - false - - - ..\..\libraries\Windows.Foundation.FoundationContract.winmd - true - false - - - ..\..\libraries\Windows.Foundation.UniversalApiContract.winmd - true - false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - True - True - Strings.resx - - - - - - ResXFileCodeGenerator - Strings.Designer.cs - iNKORE.UI.WPF.Modern - - + $(NoWarn);CS1591;1701;1702;CA1416;CS8632 + + + + true + 10.0.18362.0 + + Windows.Foundation; + Windows.UI.Color; + Windows.UI.IColors; + Windows.UI.ViewManagement.HandPreference; + Windows.UI.ViewManagement.IUISettings; + Windows.UI.ViewManagement.UIColorType; + Windows.UI.ViewManagement.UIElementType; + Windows.UI.ViewManagement.UISettings; + + + Windows.Foundation.Diagnostics; + Windows.Foundation.PropertyType; + + disable + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ..\..\libraries\Windows.WinMD + true + false + + + ..\..\libraries\Windows.Foundation.FoundationContract.winmd + true + false + + + ..\..\libraries\Windows.Foundation.UniversalApiContract.winmd + true + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + True + Strings.resx + + + + + + ResXFileCodeGenerator + Strings.Designer.cs + iNKORE.UI.WPF.Modern + + diff --git a/source/samples/SamplesCommon/SamplesCommon.csproj b/source/samples/SamplesCommon/SamplesCommon.csproj index c07f0db3..6b967679 100644 --- a/source/samples/SamplesCommon/SamplesCommon.csproj +++ b/source/samples/SamplesCommon/SamplesCommon.csproj @@ -1,29 +1,29 @@  - - net6.0-windows10.0.18362.0 - true - + + net6.0-windows10.0.18362.0 + true + - - - + + + - - - - - - - - True - Designer - MSBuild:Compile - - - - - - + + + + + + + + True + Designer + MSBuild:Compile + + + + + + diff --git a/tests/Package/Common.ps1 b/tests/Package/Common.ps1 new file mode 100644 index 00000000..4376cbb6 --- /dev/null +++ b/tests/Package/Common.ps1 @@ -0,0 +1,12 @@ +# Helpers shared by the package tests. + +# Visual Studio's MSBuild.exe, which runs on .NET Framework (dotnet build runs on .NET). +function Find-MSBuild { + $vswhere = Join-Path ${env:ProgramFiles(x86)} 'Microsoft Visual Studio\Installer\vswhere.exe' + if (Test-Path $vswhere) { + $path = & $vswhere -latest -prerelease -products * -requires Microsoft.Component.MSBuild -find 'MSBuild\**\Bin\MSBuild.exe' | + Select-Object -First 1 + if ($path) { return $path } + } + throw "Visual Studio's MSBuild.exe wasn't found; pass its path with -MSBuild." +} diff --git a/tests/Package/Consumers/Directory.Build.props b/tests/Package/Consumers/Directory.Build.props new file mode 100644 index 00000000..95d2efd7 --- /dev/null +++ b/tests/Package/Consumers/Directory.Build.props @@ -0,0 +1,3 @@ + + + diff --git a/tests/Package/Consumers/Directory.Build.targets b/tests/Package/Consumers/Directory.Build.targets new file mode 100644 index 00000000..95d2efd7 --- /dev/null +++ b/tests/Package/Consumers/Directory.Build.targets @@ -0,0 +1,3 @@ + + + diff --git a/tests/Package/Consumers/PackageConsumer/App.xaml b/tests/Package/Consumers/PackageConsumer/App.xaml new file mode 100644 index 00000000..4f8a6eb3 --- /dev/null +++ b/tests/Package/Consumers/PackageConsumer/App.xaml @@ -0,0 +1,14 @@ + + + + + + + + + + diff --git a/tests/Package/Consumers/PackageConsumer/App.xaml.cs b/tests/Package/Consumers/PackageConsumer/App.xaml.cs new file mode 100644 index 00000000..86183479 --- /dev/null +++ b/tests/Package/Consumers/PackageConsumer/App.xaml.cs @@ -0,0 +1,55 @@ +using System; +using System.Globalization; +using System.IO; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows; + +namespace PackageConsumer +{ + /// + /// A smoke test that checks itself; MainWindow runs the checks once it has rendered. Exits with 0 when they pass, + /// 1 when one fails or anything throws, and 2 when the window doesn't render in time. + /// + public partial class App : Application + { + static readonly TextWriter Output = TextWriter.Synchronized( + new StreamWriter(Console.OpenStandardOutput(), new UTF8Encoding(false)) { AutoFlush = true }); + static readonly Timer Watchdog; + + static App() + { + // Set before any UI exists, so the controls load their zh-TW strings. + var culture = new CultureInfo("zh-TW"); + CultureInfo.DefaultThreadCurrentCulture = CultureInfo.DefaultThreadCurrentUICulture = culture; + Thread.CurrentThread.CurrentCulture = Thread.CurrentThread.CurrentUICulture = culture; + + AppDomain.CurrentDomain.UnhandledException += (s, e) => Fail(e.ExceptionObject.ToString()); + TaskScheduler.UnobservedTaskException += (s, e) => Fail(e.Exception.ToString()); + Watchdog = new Timer(_ => Quit(2, "FAIL The window didn't render within 60 seconds."), null, 60000, Timeout.Infinite); + } + + public App() + { + DispatcherUnhandledException += (s, e) => Fail(e.Exception.ToString()); + } + + public static void Log(string line) => Output.WriteLine(line); + + public static void Pass() + { + Watchdog.Dispose(); + Log("PASS"); + Current.Shutdown(0); + } + + public static void Fail(string message) => Quit(1, "FAIL " + message); + + static void Quit(int code, string message) + { + Log(message); + Environment.Exit(code); + } + } +} diff --git a/tests/Package/Consumers/PackageConsumer/MainWindow.xaml b/tests/Package/Consumers/PackageConsumer/MainWindow.xaml new file mode 100644 index 00000000..03c462f1 --- /dev/null +++ b/tests/Package/Consumers/PackageConsumer/MainWindow.xaml @@ -0,0 +1,17 @@ + + + + + + + + +