Skip to content

Commit

Permalink
Preliminary version update functionality.
Browse files Browse the repository at this point in the history
  • Loading branch information
Ruben2776 committed Oct 28, 2024
1 parent dbd6fef commit ef4e675
Show file tree
Hide file tree
Showing 9 changed files with 316 additions and 33 deletions.
4 changes: 4 additions & 0 deletions src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,9 @@
<PropertyGroup>
<Nullable>enable</Nullable>
<AvaloniaVersion>11.0.2</AvaloniaVersion>
<VersionPrefix>3.0.0</VersionPrefix>
<VersionSuffix>rc-preview-5</VersionSuffix>
<AssemblyVersion>3.0.0.5</AssemblyVersion>
<FileVersion>3.0</FileVersion>
</PropertyGroup>
</Project>
11 changes: 2 additions & 9 deletions src/PicView.Avalonia.MacOS/PicView.Avalonia.MacOS.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
<Trimming>full</Trimming>
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
<LangVersion>preview</LangVersion>
<AssemblyVersion>3.0</AssemblyVersion>
<FileVersion>3.0</FileVersion>
<Company>Ruben Hyldgaard Negendahl</Company>
<Authors>Ruben Hyldgaard Negendahl</Authors>
<Copyright>© Ruben Hyldgaard Negendahl</Copyright>
Expand All @@ -28,11 +26,6 @@
<DebugType>none</DebugType>
</PropertyGroup>

<PropertyGroup>
<VersionPrefix>3.0.0</VersionPrefix>
<VersionSuffix>rc-preview-4</VersionSuffix>
</PropertyGroup>


<PropertyGroup Condition="'$(Platform)' == 'x64'">
<PlatformTarget>x64</PlatformTarget>
Expand All @@ -43,8 +36,8 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Avalonia.Desktop" Version="11.2.0-rc1" />
<PackageReference Include="Avalonia.Themes.Simple" Version="11.2.0-rc1" />
<PackageReference Include="Avalonia.Desktop" Version="11.2.0-rc2" />
<PackageReference Include="Avalonia.Themes.Simple" Version="11.2.0-rc2" />
</ItemGroup>

<ItemGroup>
Expand Down
11 changes: 2 additions & 9 deletions src/PicView.Avalonia.Win32/PicView.Avalonia.Win32.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@
<AssemblyName>PicView</AssemblyName>
<StartupObject>PicView.Avalonia.Win32.Program</StartupObject>
<LangVersion>preview</LangVersion>
<AssemblyVersion>3.0</AssemblyVersion>
<FileVersion>3.0</FileVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DebugType>none</DebugType>
Expand All @@ -34,11 +32,6 @@
</AvaloniaResource>
</ItemGroup>

<PropertyGroup>
<VersionPrefix>3.0.0</VersionPrefix>
<VersionSuffix>rc-preview-4</VersionSuffix>
</PropertyGroup>

<PropertyGroup Condition="'$(Platform)' == 'x64'">
<PlatformTarget>x64</PlatformTarget>
</PropertyGroup>
Expand All @@ -48,8 +41,8 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Avalonia.Desktop" Version="11.2.0-rc1" />
<PackageReference Include="Avalonia.Themes.Simple" Version="11.2.0-rc1" />
<PackageReference Include="Avalonia.Desktop" Version="11.2.0-rc2" />
<PackageReference Include="Avalonia.Themes.Simple" Version="11.2.0-rc2" />
</ItemGroup>

<ItemGroup>
Expand Down
8 changes: 4 additions & 4 deletions src/PicView.Avalonia/PicView.Avalonia.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,11 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Avalonia" Version="11.2.0-rc1" />
<PackageReference Include="Avalonia.Desktop" Version="11.2.0-rc1" />
<PackageReference Include="Avalonia.ReactiveUI" Version="11.2.0-rc1" />
<PackageReference Include="Avalonia" Version="11.2.0-rc2" />
<PackageReference Include="Avalonia.Desktop" Version="11.2.0-rc2" />
<PackageReference Include="Avalonia.ReactiveUI" Version="11.2.0-rc2" />
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.2.0-rc1" />
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.2.0-rc2" />
<PackageReference Include="Avalonia.Svg.Skia" Version="11.1.0.1" />
</ItemGroup>

Expand Down
10 changes: 10 additions & 0 deletions src/PicView.Avalonia/Update/UpdateInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace PicView.Avalonia.Update;

public class UpdateInfo
{
public string Version { get; set; }
public string X64Portable { get; set; }
public string X64Install { get; set; }
public string Arm64Portable { get; set; }
public string Arm64Install { get; set; }
}
269 changes: 269 additions & 0 deletions src/PicView.Avalonia/Update/UpdateManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,269 @@
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.Win32;
using PicView.Avalonia.UI;
using PicView.Avalonia.ViewModels;
using PicView.Core.Config;
using PicView.Core.FileHandling;

namespace PicView.Avalonia.Update;

[JsonSourceGenerationOptions(AllowTrailingCommas = true)]
[JsonSerializable(typeof(UpdateInfo))]
public partial class UpdateSourceGenerationContext : JsonSerializerContext;

public static class UpdateManager
{
public static void CheckForUpdates()
{
}

public static async Task UpdateCurrentVersion(MainViewModel vm)
{
var currentDirectory = new DirectoryInfo(Environment.ProcessPath);
var currentVersion = VersionHelper.GetCurrentVersionAsVersion();
var url = "https://picview.org/update.json";
var tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid() + "PicView");
Directory.CreateDirectory(tempPath);
var tempJsonFileDestination = Path.Combine(tempPath, "update.json");

#if DEBUG
// Change it to lower to test it
currentVersion = new Version("3.0.0.3");
#endif

// Download the JSON file
using var jsonFileDownloader = new HttpHelper.HttpClientDownloadWithProgress(url, tempJsonFileDestination);
try
{
await jsonFileDownloader.StartDownloadAsync();
}
catch (Exception e)
{
#if DEBUG
Console.WriteLine(e);
#endif
await TooltipHelper.ShowTooltipMessageAsync(e.Message);
return;
}

// Read and deserialize the JSON
UpdateInfo? updateInfo;
try
{
var jsonString = await File.ReadAllTextAsync(tempJsonFileDestination);
if (JsonSerializer.Deserialize(
jsonString, typeof(UpdateInfo),
UpdateSourceGenerationContext.Default) is not UpdateInfo serializedUpdateInfo)
{
#if DEBUG
Console.WriteLine("Update information is missing or corrupted.");
#endif
await TooltipHelper.ShowTooltipMessageAsync("Update information is missing or corrupted.");
return;
}

updateInfo = serializedUpdateInfo;
}
catch (Exception e)
{
#if DEBUG
Console.WriteLine(e);
#endif
await TooltipHelper.ShowTooltipMessageAsync("Failed to parse update information: \n" + e.Message);
return;
}

if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
var isAdmin = false;
try
{
isAdmin = currentDirectory.GetAccessControl().AreAccessRulesProtected;
}
catch (Exception)
{
isAdmin = false;
}

var isInstalled = CheckIfIsInstalled();

var architecture = RuntimeInformation.ProcessArchitecture switch
{
Architecture.X64 => isInstalled ? InstalledArchitecture.X64Install : InstalledArchitecture.X64Portable,
Architecture.Arm64 => isInstalled
? InstalledArchitecture.Arm64Install
: InstalledArchitecture.Arm64Portable,
_ => InstalledArchitecture.X64Install
};

var remoteVersion = new Version(updateInfo.Version);
if (remoteVersion <= currentVersion)
{
return;
}

if (isAdmin)
{
// Restart the application as admin
var process = new Process
{
StartInfo = new ProcessStartInfo
{
Verb = "runas",
UseShellExecute = true,
FileName = "PicView.exe",
Arguments = $"update,{architecture},{currentVersion},{tempPath}",
WorkingDirectory = AppDomain.CurrentDomain.BaseDirectory
}
};
process.Start();
Environment.Exit(0);
}
else
{
switch (architecture)
{
case InstalledArchitecture.Arm64Install:
var fileName = Path.GetFileName(updateInfo.X64Install);
var tempFileDownloadPath = Path.Combine(tempPath, fileName);
await StartFileDownloader(vm, updateInfo.Arm64Install, tempFileDownloadPath);
var process = new Process
{
StartInfo = new ProcessStartInfo
{
Verb = "runas",
UseShellExecute = true,
FileName = tempFileDownloadPath
}
};
process.Start();
return;
case InstalledArchitecture.Arm64Portable:
fileName = Path.GetFileName(updateInfo.X64Portable);
tempFileDownloadPath = Path.Combine(tempPath, fileName);
await StartFileDownloader(vm, updateInfo.Arm64Portable, tempFileDownloadPath);
vm.PlatformService.LocateOnDisk(tempFileDownloadPath);
return;
case InstalledArchitecture.X64Install:
fileName = Path.GetFileName(updateInfo.X64Install);
tempFileDownloadPath = Path.Combine(tempPath, fileName);
await StartFileDownloader(vm, updateInfo.X64Install, tempFileDownloadPath);
process = new Process
{
StartInfo = new ProcessStartInfo
{
Verb = "runas",
UseShellExecute = true,
FileName = tempFileDownloadPath
}
};
process.Start();
return;
case InstalledArchitecture.X64Portable:
fileName = Path.GetFileName(updateInfo.X64Portable);
tempFileDownloadPath = Path.Combine(tempPath, fileName);
await StartFileDownloader(vm, updateInfo.X64Portable, tempFileDownloadPath);
vm.PlatformService.LocateOnDisk(tempFileDownloadPath);
return;
}
}
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
// TODO
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
// TODO
}
}

private static bool CheckIfIsInstalled()
{
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return false;
}

var x64Path = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) + "PicView.exe";
if (File.Exists(x64Path))
{
return true;
}

const string registryKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
try
{
using var key = Registry.LocalMachine.OpenSubKey(registryKey);
if (key == null)
{
return false;
}

foreach (var subKeyName in key.GetSubKeyNames())
{
using var subKey = key.OpenSubKey(subKeyName);

var installDir = subKey?.GetValue("InstallLocation")?.ToString();
if (installDir == null)
{
continue;
}

return Path.Exists(Path.Combine(installDir, "PicView.exe"));
}
}
catch (Exception e)
{
#if DEBUG
Trace.WriteLine($"{nameof(CheckIfIsInstalled)} exception, \n {e.Message}");
#endif
return false;
}

return false;
}

private static async Task StartFileDownloader(MainViewModel vm, string downloadUrl, string tempPath)
{
vm.PlatformService.StopTaskbarProgress();
using var jsonFileDownloader = new HttpHelper.HttpClientDownloadWithProgress(downloadUrl, tempPath);
try
{
jsonFileDownloader.ProgressChanged += (size, downloaded, percentage) =>
ProgressChanged(vm, size, downloaded, percentage);
await jsonFileDownloader.StartDownloadAsync();
}
catch (Exception e)
{
#if DEBUG
Console.WriteLine(e);
#endif
await TooltipHelper.ShowTooltipMessageAsync(e.Message);
}
finally
{
vm.PlatformService.StopTaskbarProgress();
}
}

private static void ProgressChanged(MainViewModel vm, long? totalfilesize, long? totalbytesdownloaded, double? progresspercentage)
{
if (totalfilesize is null || totalbytesdownloaded is null || progresspercentage is null)
{
return;
}
vm.PlatformService.SetTaskbarProgress((ulong)totalbytesdownloaded, (ulong)totalfilesize);
}

private enum InstalledArchitecture
{
X64Portable,
X64Install,
Arm64Portable,
Arm64Install
}
}
7 changes: 4 additions & 3 deletions src/PicView.Avalonia/Views/AboutView.axaml.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
using Avalonia.Controls;
using Avalonia.Media;
using Avalonia.Styling;
using PicView.Avalonia.Update;
using PicView.Avalonia.ViewModels;
using PicView.Core.Config;
using PicView.Core.ProcessHandling;

namespace PicView.Avalonia.Views;

Expand Down Expand Up @@ -41,9 +42,9 @@ public AboutView()
};

// TODO: replace with auto update service
UpdateButton.Click += (_, _) =>
UpdateButton.Click += async (_, _) =>
{
ProcessHelper.OpenLink("https://picview.org/avalonia-download");
await UpdateManager.UpdateCurrentVersion(DataContext as MainViewModel);
};
};
}
Expand Down
Loading

0 comments on commit ef4e675

Please sign in to comment.