diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7bbec7b..89e3ff3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,7 +1,6 @@ -# This is a basic workflow to help you get started with Actions name: CI -# Controls when the workflow will run + on: # Triggers the workflow on push or pull request events but only for the master branch push: @@ -10,63 +9,220 @@ on: # Allows you to run this workflow manually from the Actions tab workflow_dispatch: -# A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: # This workflow contains a single job called "build" build: # The type of runner that the job will run on - runs-on: windows-2019 + runs-on: windows-2022 # Steps represent a sequence of tasks that will be executed as part of the job steps: - - name: Check Commit and Install 7Zip PowerShell Module + # Step to check if the commit message contains #GITBUILD + - name: Check Commit Message shell: powershell - run: | - # cancel early, if not build commit - $strVal ='${{ github.event.commits[0].message }}' + # Get the commit message + $strVal = '${{ github.event.commits[0].message }}' # Convert commit message to a single line if multiline $singleLineStrVal = $strVal -replace "`r`n", " " -replace "`n", " " - if($singleLineStrVal -match '#GITBUILD') - { - Write-Host 'True' + if ($singleLineStrVal -match '#GITBUILD') { + Write-Host 'Build commit detected. Proceeding with build...' + echo "build_trigger=true" >> $env:GITHUB_ENV } else { - Write-Host 'False' - exit(1) + Write-Host 'No build commit. Skipping build steps...' + echo "build_trigger=false" >> $env:GITHUB_ENV } - Install-Module 7Zip4PowerShell -Force -Verbose + + # Step to ensure the repository is checked out - uses: actions/checkout@v2 - + + # Inform if build steps are skipped + - name: Inform Skipped Build Steps + if: env.build_trigger != 'true' + shell: powershell + run: | + Write-Host "Skipping build steps because the commit message does not contain #GITBUILD." + + # Install 7Zip PowerShell module + - name: Install 7Zip PowerShell Module + if: env.build_trigger == 'true' + shell: powershell + run: Install-Module 7Zip4PowerShell -Force -Verbose + + # Restore NuGet packages - name: Restore NuGet packages + if: env.build_trigger == 'true' run: nuget restore UnityLauncherPro.sln - + + # Build the binary - name: Build Binary + if: env.build_trigger == 'true' shell: cmd run: call .\Build.cmd - + + # Build the artifact - name: Build Artifact + if: env.build_trigger == 'true' shell: cmd run: call .\ArtifactBuild.cmd + # Check that output exists + - name: Validate UnityLauncherPro.exe exists + if: env.build_trigger == 'true' + shell: cmd + run: | + if not exist "UnityLauncherPro\bin\Release\UnityLauncherPro.exe" ( + echo ERROR: UnityLauncherPro.exe not found. + exit /b 1 + ) + echo Found UnityLauncherPro.exe + + # 1) Compute a wrapped major.minor.build from the run number + - name: Compute installer version + if: env.build_trigger == 'true' + shell: bash + run: | + TOTAL=${{ github.run_number }} + BUILD=$(( TOTAL % 65536 )) + MINOR_TOTAL=$(( TOTAL / 65536 )) + MINOR=$(( MINOR_TOTAL % 256 )) + MAJOR=$(( MINOR_TOTAL / 256 )) + echo "INSTALLER_MAJOR=$MAJOR" >> $GITHUB_ENV + echo "INSTALLER_MINOR=$MINOR" >> $GITHUB_ENV + echo "INSTALLER_BUILD=$BUILD" >> $GITHUB_ENV + echo "INSTALLER_VER=$MAJOR.$MINOR.$BUILD" >> $GITHUB_ENV + echo "Computed installer version → $MAJOR.$MINOR.$BUILD (run #${{ github.run_number }})" + + # 2) Patch your .vdproj in place (inject ProductVersion and a new GUID) + - name: Patch .vdproj ProductVersion & ProductCode + if: env.build_trigger == 'true' + shell: pwsh + run: | + $proj = 'UnityLauncherProInstaller\UnityLauncherProInstaller.vdproj' + $ver = "${{ env.INSTALLER_VER }}" # e.g. 0.0.118 + $guid = [Guid]::NewGuid().ToString("B").ToUpper() # e.g. {E821A3F5-1F84-4A4B-BE9D-115D93E9E6F0} + + # Read & rewrite line-by-line + $fixed = Get-Content $proj | ForEach-Object { + if ($_ -match '^(\s*)"ProductVersion"') { + # preserve indentation, then inject exactly one pair of braces + "$($Matches[1])""ProductVersion"" = ""8:$ver""" + } + elseif ($_ -match '^(\s*)"ProductCode"') { + "$($Matches[1])""ProductCode"" = ""8:$guid""" + } + else { + $_ + } + } + + # Overwrite the project + Set-Content -Path $proj -Value $fixed + + Write-Host "→ ProductVersion patched to 8:$ver" + Write-Host "→ ProductCode patched to 8:$guid" + + + # 3) **DEBUG**: print out the patched .vdproj so you can inspect it + - name: Show patched .vdproj + if: env.build_trigger == 'true' + shell: pwsh + run: | + $proj = 'UnityLauncherProInstaller\UnityLauncherProInstaller.vdproj' + Write-Host "=== BEGIN .vdproj CONTENT ===" + Get-Content $proj + Write-Host "=== END .vdproj CONTENT ===" + + # locate VS 2022 + - name: Locate Visual Studio 2022 + id: vswhere + shell: pwsh + run: | + $installPath = vswhere -latest -products * -requires Microsoft.Component.MSBuild ` + -property installationPath + if (-not $installPath) { throw 'VS 2022 not found' } + Write-Host "##[set-output name=installPath]$installPath" + + # download vs installer builder (v2.0.1) + - name: Download Installer-Projects VSIX + shell: pwsh + run: | + $vsixUrl = "https://marketplace.visualstudio.com/_apis/public/gallery/publishers/VisualStudioClient/vsextensions/MicrosoftVisualStudio2022InstallerProjects/2.0.1/vspackage" + Invoke-WebRequest $vsixUrl -OutFile installerprojects.vsix + + # install vs installer builder + - name: Install Installer-Projects extension + shell: pwsh + run: | + $vsixInstaller = Join-Path "${{ steps.vswhere.outputs.installPath }}" 'Common7\IDE\VSIXInstaller.exe' + Write-Host "Running: $vsixInstaller installerprojects.vsix /quiet" + & $vsixInstaller installerprojects.vsix /quiet + + # Build MSI installer project using Visual Studio 2022 workaround + - name: Build Installer MSI + if: env.build_trigger == 'true' + shell: cmd + run: | + echo === Running BuildInstaller.bat === + call .\BuildInstaller.bat || echo WARNING: BuildInstaller.bat exited with %ERRORLEVEL%, continuing... + echo === Verifying MSI === + if exist "UnityLauncherProInstaller\Release\UnityLauncherPro-Installer.msi" ( + echo Success: MSI found at UnityLauncherProInstaller\Release\UnityLauncherPro-Installer.msi + exit /b 0 + ) else ( + echo ERROR: MSI not found in UnityLauncherProInstaller\Release + exit /b 1 + ) + + # Get the current date and time - name: Get current date and time id: datetime - run: echo "::set-output name=current_datetime::$(date +'%d/%m/%Y %H:%M')" - + if: env.build_trigger == 'true' # Only run if build was triggered + run: | + # Save the current date and time to an environment variable + echo "current_datetime=$(date +'%d/%m/%Y %H:%M')" >> $GITHUB_ENV + + # Step to get previous tag and commits + - name: Get commits since last release + id: get_commits + if: env.build_trigger == 'true' # Only run if build was triggered + shell: bash + run: | + # Get the most recent tag + PREV_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "none") + if [ "$PREV_TAG" = "none" ]; then + echo "No previous tag found, listing all commits" + COMMITS=$(git log --pretty=format:"* %s" --no-merges) + else + echo "Previous tag: $PREV_TAG" + # List commits since last tag + COMMITS=$(git log $PREV_TAG..HEAD --pretty=format:"* %s" --no-merges) + fi + # Save commits to the environment + echo "commits=$COMMITS" >> $GITHUB_ENV + + # Create a release - name: Create Release id: create_release + if: env.build_trigger == 'true' # Execute only if build was triggered uses: actions/create-release@latest env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: tag_name: ${{github.run_number}} - release_name: ${{ steps.datetime.outputs.current_datetime }} (${{ github.run_number }}) + release_name: ${{ env.current_datetime }} (${{ github.run_number }}) body: | Automated Release by GitHub Action CI + + ### Commits in this release: + ${{ env.commits }} draft: false - prerelease: false - + prerelease: false + + # Upload the release asset - name: Upload Release Asset id: upload-release-asset + if: env.build_trigger == 'true' # Execute only if build was triggered uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -76,3 +232,14 @@ jobs: asset_name: UnityLauncherPro.zip asset_content_type: application/zip + # Upload MSI installer to release + - name: Upload MSI Installer + if: env.build_trigger == 'true' + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ./UnityLauncherProInstaller/Release/UnityLauncherPro-Installer.msi + asset_name: UnityLauncherPro-Installer.msi + asset_content_type: application/x-msi diff --git a/Build.cmd b/Build.cmd index 96f1597..80288d1 100644 --- a/Build.cmd +++ b/Build.cmd @@ -1,10 +1,10 @@ @echo off REM Default VS paths to check if no Paths.cmd file exists -set VISUAL_STUDIO_PATH_0="%programfiles(x86)%\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\msbuild.exe" -set VISUAL_STUDIO_PATH_1="%programfiles(x86)%\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\msbuild.exe" -set VISUAL_STUDIO_PATH_2="%programfiles(x86)%\Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin\msbuild.exe" -set VISUAL_STUDIO_PATH_3="%programfiles(x86)%\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\msbuild.exe" +set VISUAL_STUDIO_PATH_0="%programfiles%\Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin\msbuild.exe" +set VISUAL_STUDIO_PATH_1="%programfiles%\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\msbuild.exe" +set VISUAL_STUDIO_PATH_2="%programfiles(x86)%\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\msbuild.exe" +set VISUAL_STUDIO_PATH_3="%programfiles(x86)%\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\msbuild.exe" pushd "%~dp0" if exist Debug rd /s /q Debug diff --git a/BuildInstaller.bat b/BuildInstaller.bat new file mode 100644 index 0000000..97b0d01 --- /dev/null +++ b/BuildInstaller.bat @@ -0,0 +1,75 @@ +@ECHO OFF +SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION + +ECHO: +ECHO === Starting Installer Build Workaround === + +REM Store current directory +SET "current_path=%CD%" + +REM Try all known editions of Visual Studio 2022 +SET "vs_base_path=%ProgramFiles%\Microsoft Visual Studio\2022" +FOR %%E IN (Community Professional Enterprise) DO ( + IF EXIST "%vs_base_path%\%%E\Common7\IDE\CommonExtensions\Microsoft\VSI\DisableOutOfProcBuild\DisableOutOfProcBuild.exe" ( + SET "buildfix_path=%vs_base_path%\%%E\Common7\IDE\CommonExtensions\Microsoft\VSI\DisableOutOfProcBuild" + SET "devenv_path=%vs_base_path%\%%E\Common7\IDE\devenv.exe" + SET "vs_edition=%%E" + GOTO :FoundEdition + ) +) + +ECHO [ERROR] Could not find DisableOutOfProcBuild.exe in any known VS2022 edition. +EXIT /B 1 + +:FoundEdition +ECHO Found Visual Studio 2022 Edition: %vs_edition% +CD /D "%buildfix_path%" +CALL DisableOutOfProcBuild.exe + +REM Restore previous directory +CD /D "%current_path%" + +REM === Validate required files === +ECHO: +ECHO === Checking required files === + +SET "error=0" + +IF NOT EXIST "UnityLauncherPro\bin\Release\UnityLauncherPro.exe" ( + ECHO [ERROR] Missing file: UnityLauncherPro\bin\Release\UnityLauncherPro.exe + SET "error=1" +) +IF NOT EXIST "UnityLauncherPro\Images\icon.ico" ( + ECHO [ERROR] Missing file: UnityLauncherPro\Images\icon.ico + SET "error=1" +) + +IF %error% NEQ 0 ( + ECHO [ERROR] Required files are missing. Aborting installer build. + EXIT /B 1 +) + + +ECHO: +ECHO === Building Installer === +"%devenv_path%" UnityLauncherPro.sln /Rebuild Release /Project UnityLauncherProInstaller > build_output.log 2>&1 +SET "exitCode=%ERRORLEVEL%" + +TYPE build_output.log +ECHO: +ECHO === devenv.exe exit code: %exitCode% === + +IF NOT "%exitCode%"=="0" ( + ECHO [ERROR] Installer build failed. Check build_output.log for details. + EXIT /B %exitCode% +) + + +ECHO: +ECHO === Build Complete === + +REM Optional cleanup: disable workaround +REG DELETE "HKCU\Software\Microsoft\VisualStudio\Setup" /v VSDisableOutOfProcBuild /f >NUL 2>&1 + +ENDLOCAL +EXIT /B %exitCode% diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..6b201eb --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,41 @@ +# Contributing to UnityLauncherPro + +Thanks for your interest in contributing! +Here’s how you can help: + +## How to Contribute + +0. **Open Issue** Describe your idea first (if its useful, it might get accepted) OR check existing issues and comment there +1. **Fork** the repository +2. **Clone** your fork: `git clone https://github.com/YOURUSERNAME/UnityLauncherPro.git` +3. Optional: **Create a new branch**: `git checkout -b feature-name` +4. **Make your changes** +5. **Commit**: `git commit -m "Add feature XYZ"` +6. **Push**: `git push origin feature-name` +7. **Open a Pull Request** from your fork + +## Reporting Bugs + +- Use the **Issues** tab +- Include **steps to reproduce**, screenshots, and error messages + +## Suggesting Features + +- Open an issue with `[Feature]` in the title +- Describe the problem your feature solves +- Note: Not all features get merged! *i'd like to keep workflows and UI something close to my own preferences (Sorry!), but you can of course make your own forks with additional features! + +## Code Style & External Libraries + +- Style is not enforced +- Simple code is good and functions can be as long as they need, to do the task (but can extract commonly used parts/methods into Tools or other helper libraries) +- Avoid using external packages/nugets/dependencies (to keep this as a small single exe build) +- Try to keep main features fast (or even improve existing features to make this more lightweight and faster to start etc.) + +## Need Help? + +Feel free to open an issue or post in discussion. + +--- + +Thanks for contributing! diff --git a/README.md b/README.md index 3ff010a..c81ac2a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,5 @@ # UnityLauncherPro -[![Build Status](https://ci.appveyor.com/api/projects/status/hajcaavcsg7904rx?svg=true)](https://github.com/unitycoder/UnityLauncherPro/releases/latest/download/UnityLauncherPro.zip) [![Downloads](https://img.shields.io/github/downloads/unitycoder/unitylauncherpro/total)](https://github.com/unitycoder/UnityLauncherPro/releases/latest/download/UnityLauncherPro.zip) [![GitHub license](https://img.shields.io/github/license/unitycoder/UnityLauncherPro)](https://github.com/unitycoder/UnityLauncherPro/blob/master/LICENSE) [](https://discord.gg/cXT97hU) [![VirusTotal scan now](https://img.shields.io/static/v1?label=VirusTotal&message=Scan)](https://www.virustotal.com/gui/url/e123b616cf4cbe3d3f7ba13b0d88cf5fff4638f72d5b9461088d0b11e9a41de3?nocache=1) [![CodeQL](https://github.com/unitycoder/UnityLauncherPro/actions/workflows/codeql.yml/badge.svg)](https://github.com/unitycoder/UnityLauncherPro/actions/workflows/codeql.yml) - +[![Build Status](https://github.com/unitycoder/UnityLauncherPro/actions/workflows/main.yml/badge.svg)](https://github.com/unitycoder/UnityLauncherPro/releases/latest/download/UnityLauncherPro.zip) [![Downloads](https://img.shields.io/github/downloads/unitycoder/unitylauncherpro/total)](https://github.com/unitycoder/UnityLauncherPro/releases/latest/download/UnityLauncherPro.zip) [![GitHub license](https://img.shields.io/github/license/unitycoder/UnityLauncherPro)](https://github.com/unitycoder/UnityLauncherPro/blob/master/LICENSE) [](https://discord.gg/cXT97hU) [![VirusTotal scan now](https://img.shields.io/static/v1?label=VirusTotal&message=Scan)](https://www.virustotal.com/gui/url/e123b616cf4cbe3d3f7ba13b0d88cf5fff4638f72d5b9461088d0b11e9a41de3?nocache=1) [![CodeQL](https://github.com/unitycoder/UnityLauncherPro/actions/workflows/codeql.yml/badge.svg)](https://github.com/unitycoder/UnityLauncherPro/actions/workflows/codeql.yml) Handle all your Unity versions and Projects easily! @@ -27,6 +26,9 @@ Handle all your Unity versions and Projects easily! - Select template for new project (template based on selected unity version) - And more: https://github.com/unitycoder/UnityLauncherPro/wiki/Launcher-Comparison +### Powered by +[![JetBrains logo.](https://resources.jetbrains.com/storage/products/company/brand/logos/jetbrains.svg)](https://jb.gg/OpenSourceSupport) + ### Forum Thread https://forum.unity.com/threads/unity-launcher-launch-correct-unity-versions-for-each-project-automatically.488718/ @@ -37,9 +39,12 @@ https://github.com/unitycoder/UnityLauncherPro/wiki See DEV branch for latest commits https://github.com/unitycoder/UnityLauncherPro/tree/dev
Pre-releases are sometimes available from dev branch: https://github.com/unitycoder/UnityLauncherPro/releases +### Contributing +See https://github.com/unitycoder/UnityLauncherPro/blob/master/CONTRIBUTING.md + ### Screenshots -![image](https://user-images.githubusercontent.com/5438317/71485879-184b3a00-281c-11ea-97db-73c5dfa9bb4e.png) +![Image](https://github.com/user-attachments/assets/80bd8ff4-7e90-4c1a-9501-74cf3ea538f6) ![image](https://github.com/unitycoder/UnityLauncherPro/assets/5438317/21eb1fcd-3cb1-4dea-8133-9ce440de77d8) @@ -47,7 +52,7 @@ Pre-releases are sometimes available from dev branch: https://github.com/unityco ![image](https://github.com/unitycoder/UnityLauncherPro/assets/5438317/6f8dce07-c640-42db-a1ef-d8bcc7a80cc2) -![image](https://user-images.githubusercontent.com/5438317/206923022-4b4bb8ed-0351-408f-b1d3-82bd6eefbc45.png) +![Image](https://github.com/user-attachments/assets/fa4e004a-f3c6-47d5-996f-9b603048ad18) ### Perform tasks on selected project ![image](https://github.com/unitycoder/UnityLauncherPro/assets/5438317/a0b468ba-e3a6-420b-8155-78bc32814752) @@ -70,3 +75,4 @@ Pre-releases are sometimes available from dev branch: https://github.com/unityco
Old (winforms) version is here: https://github.com/unitycoder/UnityLauncher + diff --git a/UnityLauncherPro.sln b/UnityLauncherPro.sln index 63fd938..2314601 100644 --- a/UnityLauncherPro.sln +++ b/UnityLauncherPro.sln @@ -1,14 +1,13 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.28307.539 +# Visual Studio Version 17 +VisualStudioVersion = 17.13.35931.197 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnityLauncherPro", "UnityLauncherPro\UnityLauncherPro.csproj", "{EC78D91A-3E63-4CAA-8BC3-9673A30FDA45}" EndProject +Project("{54435603-DBB4-11D2-8724-00A0C9A8B90C}") = "UnityLauncherProInstaller", "UnityLauncherProInstaller\UnityLauncherProInstaller.vdproj", "{249180EF-BFC1-9DD7-48CC-E2B9253A64E0}" +EndProject Global - GlobalSection(Performance) = preSolution - HasPerformanceSessions = true - EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU @@ -18,6 +17,9 @@ Global {EC78D91A-3E63-4CAA-8BC3-9673A30FDA45}.Debug|Any CPU.Build.0 = Debug|Any CPU {EC78D91A-3E63-4CAA-8BC3-9673A30FDA45}.Release|Any CPU.ActiveCfg = Release|Any CPU {EC78D91A-3E63-4CAA-8BC3-9673A30FDA45}.Release|Any CPU.Build.0 = Release|Any CPU + {249180EF-BFC1-9DD7-48CC-E2B9253A64E0}.Debug|Any CPU.ActiveCfg = Debug + {249180EF-BFC1-9DD7-48CC-E2B9253A64E0}.Release|Any CPU.ActiveCfg = Release + {249180EF-BFC1-9DD7-48CC-E2B9253A64E0}.Release|Any CPU.Build.0 = Release EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -28,4 +30,7 @@ Global GlobalSection(Performance) = preSolution HasPerformanceSessions = true EndGlobalSection + GlobalSection(Performance) = preSolution + HasPerformanceSessions = true + EndGlobalSection EndGlobal diff --git a/UnityLauncherPro/App.config b/UnityLauncherPro/App.config index 9c04471..7df03f7 100644 --- a/UnityLauncherPro/App.config +++ b/UnityLauncherPro/App.config @@ -1,15 +1,15 @@ - + - + -
+
- + @@ -44,10 +44,10 @@ False - + - + True @@ -62,7 +62,7 @@ False - + False @@ -95,10 +95,10 @@ 0 - + - + False @@ -107,7 +107,7 @@ False - + @@ -127,7 +127,7 @@ - + diff --git a/UnityLauncherPro/App.xaml.cs b/UnityLauncherPro/App.xaml.cs index 180b5f2..d14e416 100644 --- a/UnityLauncherPro/App.xaml.cs +++ b/UnityLauncherPro/App.xaml.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Configuration; -using System.Data; -using System.Linq; -using System.Threading.Tasks; -using System.Windows; +using System.Windows; namespace UnityLauncherPro { diff --git a/UnityLauncherPro/Converters/LastModifiedConverter.cs b/UnityLauncherPro/Converters/LastModifiedConverter.cs index 710dd14..a0f2b45 100644 --- a/UnityLauncherPro/Converters/LastModifiedConverter.cs +++ b/UnityLauncherPro/Converters/LastModifiedConverter.cs @@ -23,5 +23,23 @@ public object ConvertBack(object value, Type targetType, object parameter, Cultu return DateTime.ParseExact((string)value, MainWindow.currentDateFormat, culture); } + } + + // just for tooltip + [ValueConversion(typeof(DateTime), typeof(String))] + public class LastModifiedConverterTooltip : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value == null) return null; + DateTime date = (DateTime)value; + return date.ToString(MainWindow.currentDateFormat); + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + return DateTime.ParseExact((string)value, MainWindow.currentDateFormat, culture); + } + } } diff --git a/UnityLauncherPro/Converters/ReleaseDateConverter.cs b/UnityLauncherPro/Converters/ReleaseDateConverter.cs index e6a5be4..e1ed7e5 100644 --- a/UnityLauncherPro/Converters/ReleaseDateConverter.cs +++ b/UnityLauncherPro/Converters/ReleaseDateConverter.cs @@ -1,29 +1,49 @@ using System; using System.Globalization; +using System.Windows; using System.Windows.Data; namespace UnityLauncherPro.Converters { - [ValueConversion(typeof(DateTime), typeof(String))] + [ValueConversion(typeof(DateTime), typeof(string))] public class ReleaseDateConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - if (value == null) return null; - DateTime date = (DateTime)value; + if (value == null || !(value is DateTime date)) + { + return DependencyProperty.UnsetValue; + } - // get first part of string until space character (updates only contain mm/dd/yyyy) - string dateStrTrimmed = MainWindow.currentDateFormat; - if (dateStrTrimmed.IndexOf(' ') > -1) dateStrTrimmed = dateStrTrimmed.Split(' ')[0]; + // Use a default date format if currentDateFormat is null or empty + string dateStrTrimmed = MainWindow.currentDateFormat ?? "MM/dd/yyyy"; - return MainWindow.useHumanFriendlyDateFormat ? Tools.GetElapsedTime(date) : date.ToString(dateStrTrimmed); + // If the format includes time, use only the date portion + if (dateStrTrimmed.Contains(" ")) + { + dateStrTrimmed = dateStrTrimmed.Split(' ')[0]; + } + + // Return a human-friendly format if enabled; otherwise, format based on dateStrTrimmed + return MainWindow.useHumanFriendlyDateFormat + ? Tools.GetElapsedTime(date) + : date.ToString(dateStrTrimmed, culture); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { - // not used ? - return DateTime.ParseExact((string)value, MainWindow.currentDateFormat, culture); - } + if (value == null || string.IsNullOrWhiteSpace(value.ToString())) + { + return DependencyProperty.UnsetValue; + } + // Attempt to parse back to DateTime using the specified format + if (DateTime.TryParseExact((string)value, MainWindow.currentDateFormat ?? "MM/dd/yyyy", culture, DateTimeStyles.None, out DateTime parsedDate)) + { + return parsedDate; + } + + return DependencyProperty.UnsetValue; + } } } diff --git a/UnityLauncherPro/Data/DownloadProgress.cs b/UnityLauncherPro/Data/DownloadProgress.cs new file mode 100644 index 0000000..cf4ba8e --- /dev/null +++ b/UnityLauncherPro/Data/DownloadProgress.cs @@ -0,0 +1,14 @@ +namespace UnityLauncherPro +{ + public readonly struct DownloadProgress + { + public long TotalRead { get; } + public long TotalBytes { get; } + + public DownloadProgress(long totalRead, long totalBytes) + { + TotalRead = totalRead; + TotalBytes = totalBytes; + } + } +} \ No newline at end of file diff --git a/UnityLauncherPro/Data/MessageType.cs b/UnityLauncherPro/Data/MessageType.cs new file mode 100644 index 0000000..febb9be --- /dev/null +++ b/UnityLauncherPro/Data/MessageType.cs @@ -0,0 +1,9 @@ +namespace UnityLauncherPro.Data +{ + public enum MessageType + { + Info, + Warning, + Error + } +} diff --git a/UnityLauncherPro/Data/Project.cs b/UnityLauncherPro/Data/Project.cs index 6bf8621..5f422d3 100644 --- a/UnityLauncherPro/Data/Project.cs +++ b/UnityLauncherPro/Data/Project.cs @@ -16,6 +16,7 @@ public class Project : IValueConverter public string TargetPlatform { set; get; } // TODO rename to Platform public string[] TargetPlatforms { set; get; } public bool folderExists { set; get; } + public string SRP { set; get; } // Scriptable Render Pipeline, TODO add version info? // WPF keeps calling this method from AppendFormatHelper, GetNameCore..? not sure if need to return something else or default would be faster? public override string ToString() diff --git a/UnityLauncherPro/Data/ThemeColor.cs b/UnityLauncherPro/Data/ThemeColor.cs index 24a6232..2dcbd02 100644 --- a/UnityLauncherPro/Data/ThemeColor.cs +++ b/UnityLauncherPro/Data/ThemeColor.cs @@ -1,5 +1,4 @@ using System; -using System.ComponentModel; using System.Globalization; using System.Windows.Data; using System.Windows.Media; diff --git a/UnityLauncherPro/Data/UnityInstallation.cs b/UnityLauncherPro/Data/UnityInstallation.cs index 3647bf6..c43d7f8 100644 --- a/UnityLauncherPro/Data/UnityInstallation.cs +++ b/UnityLauncherPro/Data/UnityInstallation.cs @@ -9,13 +9,10 @@ public class UnityInstallation : IValueConverter public long VersionCode { set; get; } // version as number, cached for sorting public string Path { set; get; } // exe path public DateTime? Installed { set; get; } - public string PlatformsCombined { set; get; } public string[] Platforms { set; get; } public int ProjectCount { set; get; } - public bool IsPreferred { set; get; } - public string ReleaseType { set; get; } // Alpha, Beta, LTS.. TODO could be enum // https://stackoverflow.com/a/5551986/5452781 diff --git a/UnityLauncherPro/Data/UnityVersion.cs b/UnityLauncherPro/Data/UnityVersion.cs new file mode 100644 index 0000000..e4a0649 --- /dev/null +++ b/UnityLauncherPro/Data/UnityVersion.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; + +namespace UnityLauncherPro +{ + public class UnityVersion + { + public string Version { get; set; } + public UnityVersionStream Stream { get; set; } + public DateTime ReleaseDate { get; set; } + public string directURL { get; set; } = null; // if found from unofficial releases list + + public static UnityVersion FromJson(string json) + { + var values = ParseJsonToDictionary(json); + + return new UnityVersion + { + Version = values.ContainsKey("version") ? values["version"] : null, + Stream = ParseStream(values.ContainsKey("stream") ? values["stream"] : null), + ReleaseDate = DateTime.TryParse(values.ContainsKey("releaseDate") ? values["releaseDate"] : null, out var date) + ? date + : default + }; + } + + public string ToJson() + { + return $"{{ \"version\": \"{Version}\", \"stream\": \"{Stream}\", \"releaseDate\": \"{ReleaseDate:yyyy-MM-ddTHH:mm:ss}\" }}"; + } + + private static Dictionary ParseJsonToDictionary(string json) + { + var result = new Dictionary(); + json = json.Trim(new char[] { '{', '}', ' ' }); + var keyValuePairs = json.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + + foreach (var pair in keyValuePairs) + { + var keyValue = pair.Split(new[] { ':' }, 2); + if (keyValue.Length == 2) + { + var key = keyValue[0].Trim(new char[] { ' ', '"' }); + var value = keyValue[1].Trim(new char[] { ' ', '"' }); + result[key] = value; + } + } + + return result; + } + + private static UnityVersionStream ParseStream(string stream) + { + return Enum.TryParse(stream, true, out UnityVersionStream result) ? result : UnityVersionStream.Tech; + } + } +} diff --git a/UnityLauncherPro/Data/UnityVersionResponse.cs b/UnityLauncherPro/Data/UnityVersionResponse.cs new file mode 100644 index 0000000..0e360c1 --- /dev/null +++ b/UnityLauncherPro/Data/UnityVersionResponse.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; + +namespace UnityLauncherPro +{ + public class UnityVersionResponse + { + public int Offset { get; set; } + public int Limit { get; set; } + public int Total { get; set; } + public List Results { get; set; } + } +} \ No newline at end of file diff --git a/UnityLauncherPro/Data/UnityVersionStream.cs b/UnityLauncherPro/Data/UnityVersionStream.cs new file mode 100644 index 0000000..a0a3b0c --- /dev/null +++ b/UnityLauncherPro/Data/UnityVersionStream.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; + +namespace UnityLauncherPro +{ + public enum UnityVersionStream + { + Alpha, + Beta, + LTS, + Tech + } + + public class UnityVersionJSON + { + public string Version { get; set; } + public DateTime ReleaseDate { get; set; } + public UnityVersionStream Stream { get; set; } + public List Downloads { get; set; } + public string ShortRevision { get; set; } + } + + public class Download + { + public string Url { get; set; } + public string Type { get; set; } + public string Platform { get; set; } + public string Architecture { get; set; } + public DownloadSize DownloadSize { get; set; } + public List Modules { get; set; } + } + + public class DownloadSize + { + public long Value { get; set; } + public string Unit { get; set; } + } + + public class Module + { + public string Id { get; set; } + public string Name { get; set; } + public string Description { get; set; } + public string Url { get; set; } + } +} \ No newline at end of file diff --git a/UnityLauncherPro/Data/Updates.cs b/UnityLauncherPro/Data/Updates.cs deleted file mode 100644 index 2d06cbe..0000000 --- a/UnityLauncherPro/Data/Updates.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; - -namespace UnityLauncherPro -{ - public class Updates - { - public string Version { set; get; } - public DateTime ReleaseDate { set; get; } - } -} diff --git a/UnityLauncherPro/DownloadProgressWindow.xaml b/UnityLauncherPro/DownloadProgressWindow.xaml new file mode 100644 index 0000000..538534d --- /dev/null +++ b/UnityLauncherPro/DownloadProgressWindow.xaml @@ -0,0 +1,22 @@ + + + + + + + + - + - - - - - - + + + + + + + - + + @@ -564,6 +603,9 @@ + @@ -700,7 +742,8 @@