diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ba5e6aa..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,52 +9,183 @@ 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 + 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 @@ -68,13 +198,13 @@ jobs: # List commits since last tag COMMITS=$(git log $PREV_TAG..HEAD --pretty=format:"* %s" --no-merges) fi - echo "Commits since last release: $COMMITS" - - # Save commits to environment file for later use + # 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 }} @@ -87,10 +217,12 @@ jobs: ### 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 }} @@ -99,3 +231,15 @@ jobs: asset_path: ./UnityLauncherPro.zip 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 22ec5bb..c81ac2a 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ # UnityLauncherPro [![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! ## Features @@ -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.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/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/GetProjects.cs b/UnityLauncherPro/GetProjects.cs index caabb2e..3011595 100644 --- a/UnityLauncherPro/GetProjects.cs +++ b/UnityLauncherPro/GetProjects.cs @@ -15,7 +15,7 @@ public static class GetProjects // convert target platform name into valid buildtarget platform name, NOTE this depends on unity version, now only 2019 and later are supported public static Dictionary remapPlatformNames = new Dictionary { { "StandaloneWindows64", "Win64" }, { "StandaloneWindows", "Win" }, { "Android", "Android" }, { "WebGL", "WebGL" } }; - public static List Scan(bool getGitBranch = false, bool getPlasticBranch = false, bool getArguments = false, bool showMissingFolders = false, bool showTargetPlatform = false, StringCollection AllProjectPaths = null, bool searchGitbranchRecursivly = false, bool showSRP = false) + public static List Scan(bool getGitBranch = false, bool getPlasticBranch = false, bool getArguments = false, bool showMissingFolders = false, bool showTargetPlatform = false, StringCollection AllProjectPaths = null, bool searchGitbranchRecursively = false, bool showSRP = false) { List projectsFound = new List(); @@ -53,12 +53,12 @@ public static List Scan(bool getGitBranch = false, bool getPlasticBranc projectPath = (string)key.GetValue(valueName); } - var p = GetProjectInfo(projectPath, getGitBranch, getPlasticBranch, getArguments, showMissingFolders, showTargetPlatform, searchGitbranchRecursivly, showSRP); + var p = GetProjectInfo(projectPath, getGitBranch, getPlasticBranch, getArguments, showMissingFolders, showTargetPlatform, searchGitbranchRecursively, showSRP); //Console.WriteLine(projectPath+" "+p.TargetPlatform); // if want to hide project and folder path for screenshot - //p.Title = "Example Project "; - //p.Path = "C:/Projects/ExamplePath/MyProj"; + //p.Title = "Example Project"; + //p.Path = "C:/Projects/MyProj"; if (p != null) { @@ -94,7 +94,7 @@ public static List Scan(bool getGitBranch = false, bool getPlasticBranc // if not found from registry, add to recent projects list if (found == false) { - var p = GetProjectInfo(projectPath, getGitBranch, getPlasticBranch, getArguments, showMissingFolders, showTargetPlatform, searchGitbranchRecursivly, showSRP); + var p = GetProjectInfo(projectPath, getGitBranch, getPlasticBranch, getArguments, showMissingFolders, showTargetPlatform, searchGitbranchRecursively, showSRP); if (p != null) projectsFound.Add(p); } } @@ -120,7 +120,7 @@ public static List Scan(bool getGitBranch = false, bool getPlasticBranc return projectsFound; } // Scan() - static Project GetProjectInfo(string projectPath, bool getGitBranch = false, bool getPlasticBranch = false, bool getArguments = false, bool showMissingFolders = false, bool showTargetPlatform = false, bool searchGitbranchRecursivly = false, bool showSRP = false) + static Project GetProjectInfo(string projectPath, bool getGitBranch = false, bool getPlasticBranch = false, bool getArguments = false, bool showMissingFolders = false, bool showTargetPlatform = false, bool searchGitbranchRecursively = false, bool showSRP = false) { bool folderExists = Directory.Exists(projectPath); @@ -165,11 +165,12 @@ static Project GetProjectInfo(string projectPath, bool getGitBranch = false, boo string gitBranch = ""; if (getGitBranch == true) { - gitBranch = folderExists ? Tools.ReadGitBranchInfo(projectPath, searchGitbranchRecursivly) : null; + gitBranch = folderExists ? Tools.ReadGitBranchInfo(projectPath, searchGitbranchRecursively) : null; + // check for plastic, if enabled if (getPlasticBranch == true && gitBranch == null) { - gitBranch = folderExists ? Tools.ReadPlasticBranchInfo(projectPath) : null; + gitBranch = folderExists ? Tools.ReadPlasticBranchInfo(projectPath, searchGitbranchRecursively) : null; } } diff --git a/UnityLauncherPro/GetUnityUpdates.cs b/UnityLauncherPro/GetUnityUpdates.cs index 0cdf33e..631b7e7 100644 --- a/UnityLauncherPro/GetUnityUpdates.cs +++ b/UnityLauncherPro/GetUnityUpdates.cs @@ -42,11 +42,12 @@ public static async Task> FetchAll(bool useUnofficialList = f allVersions = unofficialVersions.Concat(allVersions).ToList(); } - if (newVersions.Count > 0) + if (newVersions.Count > 0 || (useUnofficialList && unofficialReleaseURLs.Count > 0)) { SaveCachedVersions(allVersions); } + return allVersions; } diff --git a/UnityLauncherPro/MainWindow.xaml b/UnityLauncherPro/MainWindow.xaml index 54de073..49083d2 100644 --- a/UnityLauncherPro/MainWindow.xaml +++ b/UnityLauncherPro/MainWindow.xaml @@ -7,9 +7,10 @@ xmlns:System="clr-namespace:System;assembly=mscorlib" xmlns:converters="clr-namespace:UnityLauncherPro.Converters" x:Class="UnityLauncherPro.MainWindow" mc:Ignorable="d" - Title="UnityLauncherPro" Height="650" Width="880" WindowStartupLocation="CenterScreen" Background="{DynamicResource ThemeDarkestBackground}" MinWidth="780" MinHeight="650" AllowsTransparency="True" WindowStyle="None" Margin="0" KeyDown="OnWindowKeyDown" Closing="Window_Closing" SizeChanged="Window_SizeChanged" Icon="Images/icon.ico" SourceInitialized="Window_SourceInitialized" MouseDown="Window_MouseDown"> + Title="UnityLauncherPro" Height="670" Width="880" WindowStartupLocation="CenterScreen" Background="{DynamicResource ThemeDarkestBackground}" MinWidth="780" MinHeight="650" AllowsTransparency="True" WindowStyle="None" Margin="0" KeyDown="OnWindowKeyDown" Closing="Window_Closing" SizeChanged="Window_SizeChanged" Icon="Images/icon.ico" SourceInitialized="Window_SourceInitialized" MouseDown="Window_MouseDown"> + @@ -142,13 +143,30 @@ - + + + + + @@ -210,13 +228,18 @@ + + + + + @@ -580,6 +603,9 @@ + @@ -742,12 +768,18 @@ - + - - + + + + + + @@ -824,7 +856,8 @@ - + + diff --git a/UnityLauncherPro/MainWindow.xaml.cs b/UnityLauncherPro/MainWindow.xaml.cs index 819606f..5bce4e5 100644 --- a/UnityLauncherPro/MainWindow.xaml.cs +++ b/UnityLauncherPro/MainWindow.xaml.cs @@ -4,6 +4,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Collections.Specialized; using System.ComponentModel; using System.Configuration; using System.Diagnostics; @@ -22,6 +23,7 @@ using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Shell; +using System.Windows.Threading; using UnityLauncherPro.Data; using UnityLauncherPro.Helpers; using UnityLauncherPro.Properties; @@ -41,7 +43,7 @@ public partial class MainWindow : Window public static readonly string projectNameFile = "ProjectName.txt"; public static string preferredVersion = null; public static int projectNameSetting = 0; // 0 = folder or ProjectName.txt if exists, 1=ProductName - public static readonly string initScriptFileFullPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Scripts", "InitializeProject.cs"); + public static readonly string initScriptFileFullPath = Tools.GetSafeFilePath("Scripts", "InitializeProject.cs"); const string contextRegRoot = "Software\\Classes\\Directory\\Background\\shell"; const string githubURL = "https://github.com/unitycoder/UnityLauncherPro"; @@ -66,8 +68,6 @@ public partial class MainWindow : Window string defaultDateFormat = "dd/MM/yyyy HH:mm:ss"; string adbLogCatArgs = defaultAdbLogCatArgs; - Dictionary origResourceColors = new Dictionary(); - string currentBuildReportProjectPath = null; string currentBuildPluginsRelativePath = null; //List> buildReports = new List>(); @@ -114,8 +114,6 @@ void Init() { lblVersion.Content = "Build: " + Version.Stamp; } - - CheckCustomIcon(); } void Start() @@ -125,6 +123,7 @@ void Start() UpdateUnityInstallationsList(); HandleCommandLineLaunch(); + // check for duplicate instance, and activate that instead if (chkAllowSingleInstanceOnly.IsChecked == true) { @@ -136,8 +135,11 @@ void Start() // Send a wake-up message to the running instance ActivateRunningInstance(); - // Exit the current instance - App.Current.Shutdown(); + // Exit the current instance (if not coming from Explorer launch) + if (Directory.GetCurrentDirectory().ToLower() != @"c:\windows\system32") + { + App.Current.Shutdown(); + } } else { @@ -150,11 +152,14 @@ void Start() //Properties.Settings.Default.projectPaths = null; //Properties.Settings.Default.Save(); - projectsSource = GetProjects.Scan(getGitBranch: (bool)chkShowGitBranchColumn.IsChecked, getPlasticBranch: (bool)chkCheckPlasticBranch.IsChecked, getArguments: (bool)chkShowLauncherArgumentsColumn.IsChecked, showMissingFolders: (bool)chkShowMissingFolderProjects.IsChecked, showTargetPlatform: (bool)chkShowPlatform.IsChecked, AllProjectPaths: Properties.Settings.Default.projectPaths, searchGitbranchRecursivly: (bool)chkGetGitBranchRecursively.IsChecked, showSRP: (bool)chkCheckSRP.IsChecked); + + + + projectsSource = GetProjects.Scan(getGitBranch: (bool)chkShowGitBranchColumn.IsChecked, getPlasticBranch: (bool)chkCheckPlasticBranch.IsChecked, getArguments: (bool)chkShowLauncherArgumentsColumn.IsChecked, showMissingFolders: (bool)chkShowMissingFolderProjects.IsChecked, showTargetPlatform: (bool)chkShowPlatform.IsChecked, AllProjectPaths: Properties.Settings.Default.projectPaths, searchGitbranchRecursively: (bool)chkGetGitBranchRecursively.IsChecked, showSRP: (bool)chkCheckSRP.IsChecked); //Console.WriteLine("projectsSource.Count: " + projectsSource.Count); - gridRecent.Items.Clear(); + //gridRecent.Items.Clear(); // not needed? gridRecent.ItemsSource = projectsSource; // clear updates grid @@ -168,12 +173,6 @@ void Start() // build notifyicon (using windows.forms) notifyIcon.MouseClick += new System.Windows.Forms.MouseEventHandler(NotifyIcon_MouseClick); - // get original colors - foreach (DictionaryEntry item in Application.Current.Resources.MergedDictionaries[0]) - { - origResourceColors[item.Key.ToString()] = (SolidColorBrush)item.Value; - } - ApplyTheme(txtCustomThemeFile.Text); // for autostart with minimized @@ -197,8 +196,10 @@ void Start() if (Settings.Default.disableUnityHubLaunch == true) StartHubPipe(); + CheckCustomIcon(); + isInitializing = false; - } + } // Start() private static NamedPipeServerStream hubPipeServer; private CancellationTokenSource _hubCancellationTokenSource; @@ -276,8 +277,32 @@ void HandleCommandLineLaunch() string[] args = Environment.GetCommandLineArgs(); if (args != null && args.Length > 2) { + + // first argument needs to be -projectPath var commandLineArgs = args[1]; + + // if install argument, then just try to install this file (APK) + if (commandLineArgs == "-install") + { + Console.WriteLine("Launching from commandline..."); + + // path + var apkPath = args[2]; + + // resolve full path if path parameter isn't a rooted path + //if (!Path.IsPathRooted(apkPath)) + //{ + // apkPath = Directory.GetCurrentDirectory() + apkPath; + //} + //MessageBox.Show("APK install not implemented yet: " + apkPath); + // try installing it + Tools.InstallAPK(apkPath); + Environment.Exit(0); + } + else + + if (commandLineArgs == "-projectPath") { Console.WriteLine("Launching from commandline..."); @@ -309,13 +334,15 @@ void HandleCommandLineLaunch() // NOTE if keydown, window doesnt become active and focused if (string.IsNullOrEmpty(version) || (Keyboard.Modifiers & ModifierKeys.Shift) != 0) { - if (Directory.Exists(Path.Combine(proj.Path, "Assets")) == true) + // if Assets folder exists, then its existing project + if (Directory.Exists(Path.Combine(proj.Path, "Assets")) == true && (Directory.GetFiles(Path.Combine(proj.Path, "Assets")).Length > 0)) { - Tools.DisplayUpgradeDialog(proj, null, false); + bool useInitScript = (bool)chkUseInitScript.IsChecked; + + Tools.DisplayUpgradeDialog(proj, null, useInitScript); } - else // no assets folder here, then its new project + else // no Assets folder here OR Assets folder is empty, then its new project { - //Tools.DisplayUpgradeDialog(proj, null); CreateNewEmptyProject(proj.Path); } } @@ -328,7 +355,7 @@ void HandleCommandLineLaunch() } // quit after launch if enabled in settings - if (Properties.Settings.Default.closeAfterExplorer == true) + if (Settings.Default.closeAfterExplorer == true) { Environment.Exit(0); } @@ -412,16 +439,16 @@ private bool ProjectFilter(object item) bool found = true; foreach (var word in searchWords) { - bool titleMatched = proj.Title.IndexOf(word, 0, StringComparison.CurrentCultureIgnoreCase) != -1; - bool pathMatched = searchProjectPathAlso && proj.Path.IndexOf(word, 0, StringComparison.CurrentCultureIgnoreCase) != -1; + bool titleMatched = proj.Title.IndexOf(word, 0, StringComparison.OrdinalIgnoreCase) != -1; + bool pathMatched = searchProjectPathAlso && proj.Path.IndexOf(word, 0, StringComparison.OrdinalIgnoreCase) != -1; found = found && (titleMatched || pathMatched); } return found; } else // single word search { - bool titleMatched = proj.Title.IndexOf(_filterString, 0, StringComparison.CurrentCultureIgnoreCase) != -1; - bool pathMatched = searchProjectPathAlso && proj.Path.IndexOf(_filterString, 0, StringComparison.CurrentCultureIgnoreCase) != -1; + bool titleMatched = proj.Title.IndexOf(_filterString, 0, StringComparison.OrdinalIgnoreCase) != -1; + bool pathMatched = searchProjectPathAlso && proj.Path.IndexOf(_filterString, 0, StringComparison.OrdinalIgnoreCase) != -1; return titleMatched || pathMatched; } @@ -493,6 +520,7 @@ void LoadSettings() chkMinimizeToTaskbar.IsChecked = Settings.Default.minimizeToTaskbar; chkRegisterExplorerMenu.IsChecked = Settings.Default.registerExplorerMenu; + chkRegisterInstallAPKMenu.IsChecked = Settings.Default.registerExplorerMenuAPK; // update settings window chkQuitAfterCommandline.IsChecked = Settings.Default.closeAfterExplorer; @@ -844,6 +872,11 @@ async Task CallGetUnityUpdates() updatesSource = items.ToArray(); if (updatesSource == null) return; dataGridUpdates.ItemsSource = updatesSource; + // if search string is set, then filter it (after data is loaded) + if (string.IsNullOrEmpty(txtSearchBoxUpdates.Text) == false) + { + FilterUpdates(); + } } async void GoLookForUpdatesForThisUnity() @@ -857,7 +890,10 @@ async void GoLookForUpdatesForThisUnity() if (dataGridUpdates.ItemsSource != null) { tabControl.SelectedIndex = 2; - txtSearchBoxUpdates.Text = ""; // need to clear old results first + // need to clear old results first + txtSearchBoxUpdates.Text = ""; + // reset filter + rdoAll.IsChecked = true; // NOTE for now, just set filter to current version, minus patch version "2021.1.7f1" > "2021.1" txtSearchBoxUpdates.Text = unity.Version.Substring(0, unity.Version.LastIndexOf('.')); @@ -871,7 +907,7 @@ public void RefreshRecentProjects() // take currently selected project row lastSelectedProjectIndex = gridRecent.SelectedIndex; // rescan recent projects - projectsSource = GetProjects.Scan(getGitBranch: (bool)chkShowGitBranchColumn.IsChecked, getPlasticBranch: (bool)chkCheckPlasticBranch.IsChecked, getArguments: (bool)chkShowLauncherArgumentsColumn.IsChecked, showMissingFolders: (bool)chkShowMissingFolderProjects.IsChecked, showTargetPlatform: (bool)chkShowPlatform.IsChecked, AllProjectPaths: Settings.Default.projectPaths, searchGitbranchRecursivly: (bool)chkGetGitBranchRecursively.IsChecked, showSRP: (bool)chkCheckSRP.IsChecked); + projectsSource = GetProjects.Scan(getGitBranch: (bool)chkShowGitBranchColumn.IsChecked, getPlasticBranch: (bool)chkCheckPlasticBranch.IsChecked, getArguments: (bool)chkShowLauncherArgumentsColumn.IsChecked, showMissingFolders: (bool)chkShowMissingFolderProjects.IsChecked, showTargetPlatform: (bool)chkShowPlatform.IsChecked, AllProjectPaths: Settings.Default.projectPaths, searchGitbranchRecursively: (bool)chkGetGitBranchRecursively.IsChecked, showSRP: (bool)chkCheckSRP.IsChecked); gridRecent.ItemsSource = projectsSource; // fix sorting on refresh @@ -1151,6 +1187,7 @@ private void RemoveProjectFromList(bool confirm = false) gridRecent.SelectedIndex = 0; } + // NOTE this doesnt remove from settings list? } private async void OnTabSelectionChanged(object sender, SelectionChangedEventArgs e) @@ -1168,6 +1205,11 @@ private async void OnTabSelectionChanged(object sender, SelectionChangedEventArg updatesSource = items.ToArray(); if (updatesSource == null) return; dataGridUpdates.ItemsSource = updatesSource; + // if search string is set, then filter it (after data is loaded) + if (string.IsNullOrEmpty(txtSearchBoxUpdates.Text) == false) + { + FilterUpdates(); + } } } } @@ -1280,7 +1322,7 @@ private void BtnUpgradeProject_Click(object sender, RoutedEventArgs e) var proj = GetSelectedProject(); if (proj == null) return; - Tools.DisplayUpgradeDialog(proj, this, false); + Tools.DisplayUpgradeDialog(proj: proj, owner: this, useInitScript: false); } private void GridRecent_Loaded(object sender, RoutedEventArgs e) @@ -1288,7 +1330,8 @@ private void GridRecent_Loaded(object sender, RoutedEventArgs e) // if coming from explorer launch, and missing unity version, projectsource is still null? if (projectsSource != null) SetStatus("Ready (" + projectsSource.Count + " projects)"); RefreshSorting(); - Tools.SetFocusToGrid(gridRecent); + //Tools.SetFocusToGrid(gridRecent); + Dispatcher.InvokeAsync(() => Tools.SetFocusToGrid(gridRecent), DispatcherPriority.ApplicationIdle); } void RefreshSorting() @@ -2011,8 +2054,10 @@ private void BtnBrowseProjectRootFolder_Click(object sender, RoutedEventArgs e) private void TxtRootFolderForNewProjects_TextChanged(object sender, TextChangedEventArgs e) { - Properties.Settings.Default.newProjectsRoot = txtRootFolderForNewProjects.Text; - Properties.Settings.Default.Save(); + if (this.IsActive == false) return; // dont run code on window init + + Settings.Default.newProjectsRoot = txtRootFolderForNewProjects.Text; + Settings.Default.Save(); } @@ -2086,7 +2131,7 @@ void CreateNewEmptyProject(string targetFolder = null) Console.WriteLine("Create project " + NewProject.newVersion + " : " + rootFolder); if (string.IsNullOrEmpty(rootFolder)) return; - var p = Tools.FastCreateProject(NewProject.newVersion, rootFolder, NewProject.newProjectName, NewProject.templateZipPath, NewProject.platformsForThisUnity, NewProject.selectedPlatform, (bool)chkUseInitScript.IsChecked, initScriptFileFullPath); + var p = Tools.FastCreateProject(NewProject.newVersion, rootFolder, NewProject.newProjectName, NewProject.templateZipPath, NewProject.platformsForThisUnity, NewProject.selectedPlatform, (bool)chkUseInitScript.IsChecked, initScriptFileFullPath, NewProject.forceDX11); // add to list (just in case new project fails to start, then folder is already generated..) if (p != null) AddNewProjectToList(p); @@ -2149,6 +2194,8 @@ private void ChkStreamerMode_Checked(object sender, RoutedEventArgs e) { RefreshRecentProjects(); } + + SetStatus("Streamer mode " + (isChecked ? "enabled" : "disabled"), MessageType.Info); } private void ChkShowPlatform_Checked(object sender, RoutedEventArgs e) @@ -2229,8 +2276,8 @@ private void ChkEnableProjectRename_Checked(object sender, RoutedEventArgs e) { if (this.IsActive == false) return; // dont run code on window init - Properties.Settings.Default.enableProjectRename = (bool)chkEnableProjectRename.IsChecked; - Properties.Settings.Default.Save(); + Settings.Default.enableProjectRename = (bool)chkEnableProjectRename.IsChecked; + Settings.Default.Save(); } private void MenuItemKillProcess_Click(object sender, RoutedEventArgs e) @@ -2632,8 +2679,10 @@ private void MenuStartWebGLServer_Click(object sender, RoutedEventArgs e) private void TxtWebglRelativePath_TextChanged(object sender, TextChangedEventArgs e) { - Properties.Settings.Default.webglBuildPath = txtWebglRelativePath.Text; - Properties.Settings.Default.Save(); + if (this.IsActive == false) return; // dont run code on window init + + Settings.Default.webglBuildPath = txtWebglRelativePath.Text; + Settings.Default.Save(); } private void MenuItemBrowsePersistentDataPath_Click(object sender, RoutedEventArgs e) @@ -2675,56 +2724,60 @@ private void MenuItemBrowsePersistentDataPath_Click(object sender, RoutedEventAr } } - void ApplyTheme(string themeFile) + private void ApplyTheme(string themeFileName) { - if (chkUseCustomTheme.IsChecked == false) return; - - //Console.WriteLine("Load theme: " + themefile); + if (chkUseCustomTheme.IsChecked != true) + return; - themeFile = "Themes/" + themeFile; + // 1) Compute the full, safe path to the INI + string themePath = Tools.GetSafeFilePath("Themes", themeFileName); - if (File.Exists(themeFile) == true) + // 2) Try to load it + if (File.Exists(themePath)) { - var colors = File.ReadAllLines(themeFile); - - // parse lines - for (int i = 0, length = colors.Length; i < length; i++) + var lines = File.ReadAllLines(themePath); + for (int i = 0; i < lines.Length; i++) { - // skip comments - if (colors[i].IndexOf('#') == 0) continue; - // split row (name and color) - var row = colors[i].Split('='); - // skip bad rows - if (row.Length != 2) continue; + string line = lines[i].Trim(); + // skip empty or comment + if (string.IsNullOrEmpty(line) || line.StartsWith("#")) + continue; + + var parts = line.Split(new[] { '=' }, 2); + if (parts.Length != 2) + continue; + + string key = parts[0].Trim(); + string value = parts[1].Trim(); - // parse color try { - //Console.WriteLine(row[0] +"="+ row[1].Trim()); - var col = new BrushConverter().ConvertFrom(row[1].Trim()); - // apply color - Application.Current.Resources[row[0]] = (SolidColorBrush)col; + var brush = (SolidColorBrush)new BrushConverter().ConvertFrom(value); + Application.Current.Resources[key] = brush; } - catch (Exception e) + catch (Exception ex) { - Console.WriteLine(e); - SetStatus("Failed to parse color value: " + row[1]); + Console.WriteLine(ex); + SetStatus($"Failed to parse color value: {value}"); } - } } else { - Console.WriteLine("Theme file not found: " + themeFile); - SetStatus("Theme file not found: " + themeFile); + Console.WriteLine($"Theme file not found: {themePath}"); + SetStatus($"Theme file not found: {themePath}"); } } + void ResetTheme() { - foreach (KeyValuePair item in origResourceColors) + foreach (DictionaryEntry item in Application.Current.Resources.MergedDictionaries[0]) { - Application.Current.Resources[item.Key] = item.Value; + if (item.Key is string key && item.Value is SolidColorBrush brush) + { + Application.Current.Resources[key] = brush; + } } } @@ -2757,8 +2810,8 @@ private void BtnReloadTheme_Click(object sender, RoutedEventArgs e) private void TxtCustomThemeFile_LostFocus(object sender, RoutedEventArgs e) { var s = (TextBox)sender; - Properties.Settings.Default.themeFile = s.Text; - Properties.Settings.Default.Save(); + Settings.Default.themeFile = s.Text; + Settings.Default.Save(); } private void TxtCustomThemeFile_PreviewKeyDown(object sender, KeyEventArgs e) @@ -3195,6 +3248,8 @@ private void MenuCreateDesktopShortCut_Click(object sender, RoutedEventArgs e) private void TxtShortcutBatchFileFolder_TextChanged(object sender, TextChangedEventArgs e) { + if (this.IsActive == false) return; // dont run code on window init + var folder = ((TextBox)sender).Text; if (Directory.Exists(folder)) { @@ -3479,6 +3534,7 @@ public void SetStatus(string msg, MessageType messageType = MessageType.Info) } txtStatus.Text = msg; + txtStatus.ToolTip = msg; } public void SetBuildStatus(System.Windows.Media.Color color) @@ -3548,7 +3604,7 @@ private void menuInstallLastAPK_Click(object sender, RoutedEventArgs e) } // install the apk using ADB using cmd (-r = replace app) - var cmd = "cmd.exe";// /C adb install -r \"{playerPath}\""; + var cmd = "cmd.exe"; var pars = $"/C adb install -r \"{playerPath}\""; string packageName = null; @@ -3856,22 +3912,15 @@ private void OnPipeConnection(IAsyncResult result) private void CheckCustomIcon() { string customIconPath = Path.Combine(Environment.CurrentDirectory, "icon.ico"); - //Console.WriteLine(customIconPath); - if (File.Exists(customIconPath)) { try { // Load the custom icon using System.Drawing.Icon - using (var icon = new System.Drawing.Icon(customIconPath)) + using (var icon = new Icon(customIconPath)) { // Convert the icon to a BitmapSource and assign it to the WPF window's Icon property - this.Icon = Imaging.CreateBitmapSourceFromHIcon( - icon.Handle, - Int32Rect.Empty, - BitmapSizeOptions.FromEmptyOptions() // Use BitmapSizeOptions here - ); - + this.Icon = Imaging.CreateBitmapSourceFromHIcon(icon.Handle, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); // window icon IconImage.Source = this.Icon; // tray icon @@ -3914,7 +3963,7 @@ private async void chkDisableUnityHubLaunch_Checked(object sender, RoutedEventAr { if (!this.IsActive) return; // Don't run code during window initialization - Console.WriteLine((bool)chkDisableUnityHubLaunch.IsChecked); + //Console.WriteLine((bool)chkDisableUnityHubLaunch.IsChecked); if ((bool)chkDisableUnityHubLaunch.IsChecked) { @@ -3973,7 +4022,89 @@ private async Task CloseHubPipeAsync() } } + private void chkRegisterInstallAPKMenu_Checked(object sender, RoutedEventArgs e) + { + if (this.IsActive == false) return; // dont run code on window init + + if ((bool)chkRegisterInstallAPKMenu.IsChecked) + { + Tools.AddContextMenuRegistryAPKInstall(contextRegRoot); + } + else // remove + { + Tools.RemoveContextMenuRegistryAPKInstall(contextRegRoot); + } + + Settings.Default.registerExplorerMenuAPK = (bool)chkRegisterInstallAPKMenu.IsChecked; + Settings.Default.Save(); + + } + + private void btnExcludeFolderForDefender_Click(object sender, RoutedEventArgs e) + { + var foldersToExclude = new List(); + foreach (var unity in unityInstallationsSource) + { + var unityEditorFolder = Path.GetDirectoryName(unity.Path); + //Console.WriteLine(unityEditorFolder); + if (Directory.Exists(unityEditorFolder)) + { + foldersToExclude.Add(unityEditorFolder); + } + } + + Tools.RunExclusionElevated(foldersToExclude); + } + + private void menuExcludeFromDefender_Click(object sender, RoutedEventArgs e) + { + var proj = GetSelectedProject(); + if (proj == null) return; + if (Directory.Exists(proj.Path) == false) return; + + var foldersToExclude = new List(); + foldersToExclude.Add(proj.Path); + var res = Tools.RunExclusionElevated(foldersToExclude, silent: true); + var tempPath = ((chkStreamerMode.IsChecked == true) ? "***" : proj.Path); + if (res == false) + { + SetStatus("Failed to add exclusion for: " + tempPath); + } + else + { + SetStatus("Added exclusion for project path: " + tempPath); + } + } + + private void btnPurgeMissingFolders_Click(object sender, RoutedEventArgs e) + { + var validPaths = new List(); + int removedCount = 0; + foreach (string path in Settings.Default.projectPaths) + { + if (!string.IsNullOrEmpty(path) && Directory.Exists(path)) + { + validPaths.Add(path); + } + else + { + Console.WriteLine("Path not found: " + path); + removedCount++; + } + } + + // Replace the old collection with the filtered one + var newCollection = new StringCollection(); + foreach (string path in validPaths) + { + newCollection.Add(path); + } + Settings.Default.projectPaths = newCollection; + Settings.Default.Save(); + + SetStatus("Purged " + removedCount + " items", MessageType.Info); + } //private void menuProjectProperties_Click(object sender, RoutedEventArgs e) //{ diff --git a/UnityLauncherPro/NewProject.xaml b/UnityLauncherPro/NewProject.xaml index b42bb4c..f8d009c 100644 --- a/UnityLauncherPro/NewProject.xaml +++ b/UnityLauncherPro/NewProject.xaml @@ -5,7 +5,7 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:UnityLauncherPro" mc:Ignorable="d" - Title="Create New Project" Height="480" Width="450" Background="{DynamicResource ThemeDarkestBackground}" PreviewKeyDown="Window_PreviewKeyDown" ResizeMode="NoResize" WindowStartupLocation="CenterOwner" ShowInTaskbar="True"> + Title="Create New Project" Height="480" Width="500" Background="{DynamicResource ThemeDarkestBackground}" PreviewKeyDown="Window_PreviewKeyDown" ResizeMode="NoResize" WindowStartupLocation="CenterOwner" ShowInTaskbar="True"> @@ -20,24 +20,28 @@ - - - + + + + - - - + + + + +