From 631530dbf7cd05083389071a7f370386347e4f11 Mon Sep 17 00:00:00 2001 From: GMatrixGames Date: Wed, 29 May 2024 14:39:59 -0400 Subject: [PATCH 01/65] Outline Shader Drifting --- CUE4Parse | 2 +- FModel/Resources/outline.vert | 15 ++++++++------- FModel/Views/Snooper/Shading/Material.cs | 2 +- FModel/Views/Snooper/Shading/TextureHelper.cs | 1 + 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/CUE4Parse b/CUE4Parse index 4e955153..38c1e582 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit 4e955153559be8dc156d15fc93ff8c1016d3ebfe +Subproject commit 38c1e5823978ff8c6d7d7db2bb6fb21f39f8944a diff --git a/FModel/Resources/outline.vert b/FModel/Resources/outline.vert index 396b6b14..0a930758 100644 --- a/FModel/Resources/outline.vert +++ b/FModel/Resources/outline.vert @@ -27,10 +27,18 @@ vec2 unpackBoneIDsAndWeights(int packedData) return vec2(float((packedData >> 16) & 0xFFFF), float(packedData & 0xFFFF)); } +vec4 calculateScale(vec4 bindPos, vec4 bindNormal) +{ + vec4 worldPos = vInstanceMatrix * bindPos; + float scaleFactor = length(uViewPos - worldPos.xyz) * 0.0035; + return transpose(inverse(vInstanceMatrix)) * bindNormal * scaleFactor; +} + void main() { vec4 bindPos = vec4(mix(vPos, vMorphTargetPos, uMorphTime), 1.0); vec4 bindNormal = vec4(vNormal, 1.0); + bindPos.xyz += calculateScale(bindPos, bindNormal).xyz; vec4 finalPos = vec4(0.0); vec4 finalNormal = vec4(0.0); @@ -53,8 +61,6 @@ void main() finalNormal += transpose(inverse(boneMatrix)) * bindNormal * weight; } } - finalPos = normalize(finalPos); - finalNormal = normalize(finalNormal); } else { @@ -62,10 +68,5 @@ void main() finalNormal = bindNormal; } - vec4 worldPos = vInstanceMatrix * finalPos; - float scaleFactor = length(uViewPos - worldPos.xyz) * 0.0035; - vec4 nor = transpose(inverse(vInstanceMatrix)) * finalNormal * scaleFactor; - finalPos.xyz += nor.xyz; - gl_Position = uProjection * uView * vInstanceMatrix * finalPos; } diff --git a/FModel/Views/Snooper/Shading/Material.cs b/FModel/Views/Snooper/Shading/Material.cs index 08eeffe5..8b0c9f03 100644 --- a/FModel/Views/Snooper/Shading/Material.cs +++ b/FModel/Views/Snooper/Shading/Material.cs @@ -98,7 +98,7 @@ public class Material : IDisposable } { // ambient occlusion + color boost - if (Parameters.TryGetTexture2d(out var original, "M", "AEM", "AO", "Mask") && + if (Parameters.TryGetTexture2d(out var original, "M", "AEM", "AO") && !original.Name.Equals("T_BlackMask") && options.TryGetTexture(original, false, out var transformed)) { HasAo = true; diff --git a/FModel/Views/Snooper/Shading/TextureHelper.cs b/FModel/Views/Snooper/Shading/TextureHelper.cs index 1ee8995d..541c7e2b 100644 --- a/FModel/Views/Snooper/Shading/TextureHelper.cs +++ b/FModel/Views/Snooper/Shading/TextureHelper.cs @@ -21,6 +21,7 @@ public static class TextureHelper case "COSMICSHAKE": case "PHOENIX": case "ATOMICHEART": + case "MULTIVERSUS": { texture.SwizzleMask = [ From 5d991e27b10bf3e423f2cebcab613296253638da Mon Sep 17 00:00:00 2001 From: Marlon Date: Tue, 11 Jun 2024 02:09:53 +0200 Subject: [PATCH 02/65] fix --- CUE4Parse | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CUE4Parse b/CUE4Parse index 38c1e582..54639261 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit 38c1e5823978ff8c6d7d7db2bb6fb21f39f8944a +Subproject commit 54639261ecd47dd6206734fe133442bc256cdc93 From 3fa30b5979975c40db74ff7501711375b8b41c30 Mon Sep 17 00:00:00 2001 From: Marlon Date: Tue, 11 Jun 2024 02:10:18 +0200 Subject: [PATCH 03/65] fix --- FModel/ViewModels/ApplicationViewModel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FModel/ViewModels/ApplicationViewModel.cs b/FModel/ViewModels/ApplicationViewModel.cs index 3e5bef8f..1d314969 100644 --- a/FModel/ViewModels/ApplicationViewModel.cs +++ b/FModel/ViewModels/ApplicationViewModel.cs @@ -208,7 +208,7 @@ public class ApplicationViewModel : ViewModel foreach (var entry in zip.Entries) { var entryPath = Path.Combine(zipDir, entry.FullName); - await using var entryFs = File.OpenRead(entryPath); + await using var entryFs = File.Create(entryPath); await using var entryStream = entry.Open(); await entryStream.CopyToAsync(entryFs); } From 1ccb2aa83be8dd8726a33848469769e2054aaed8 Mon Sep 17 00:00:00 2001 From: Marlon Date: Tue, 11 Jun 2024 02:11:39 +0200 Subject: [PATCH 04/65] nuget updates --- FModel/FModel.csproj | 8 ++++---- FModel/Framework/FRestRequest.cs | 8 ++++---- FModel/ViewModels/ApiEndpointViewModel.cs | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/FModel/FModel.csproj b/FModel/FModel.csproj index 1094a287..38aa6f91 100644 --- a/FModel/FModel.csproj +++ b/FModel/FModel.csproj @@ -148,19 +148,19 @@ - + - + - - + + diff --git a/FModel/Framework/FRestRequest.cs b/FModel/Framework/FRestRequest.cs index 549a00e3..b09cf30c 100644 --- a/FModel/Framework/FRestRequest.cs +++ b/FModel/Framework/FRestRequest.cs @@ -1,19 +1,19 @@ -using System; +using System; using RestSharp; namespace FModel.Framework; public class FRestRequest : RestRequest { - private const int _timeout = 3 * 1000; + private const int TimeoutSeconds = 5; public FRestRequest(string url, Method method = Method.Get) : base(url, method) { - Timeout = _timeout; + Timeout = TimeSpan.FromSeconds(TimeoutSeconds); } public FRestRequest(Uri uri, Method method = Method.Get) : base(uri, method) { - Timeout = _timeout; + Timeout = TimeSpan.FromSeconds(TimeoutSeconds); } } diff --git a/FModel/ViewModels/ApiEndpointViewModel.cs b/FModel/ViewModels/ApiEndpointViewModel.cs index 00927593..47146eae 100644 --- a/FModel/ViewModels/ApiEndpointViewModel.cs +++ b/FModel/ViewModels/ApiEndpointViewModel.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using System.Threading.Tasks; using FModel.Framework; @@ -12,7 +12,7 @@ public class ApiEndpointViewModel private readonly RestClient _client = new (new RestClientOptions { UserAgent = $"FModel/{Constants.APP_VERSION}", - MaxTimeout = 3 * 1000 + Timeout = TimeSpan.FromSeconds(5) }, configureSerialization: s => s.UseSerializer()); public FortniteApiEndpoint FortniteApi { get; } From 86ee2b98f3e86f291ddd90c1228276a3444db6da Mon Sep 17 00:00:00 2001 From: Marlon Date: Tue, 11 Jun 2024 02:11:51 +0200 Subject: [PATCH 05/65] updated EpicManifestParser --- FModel/FModel.csproj | 2 +- FModel/ViewModels/CUE4ParseViewModel.cs | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/FModel/FModel.csproj b/FModel/FModel.csproj index 38aa6f91..be042452 100644 --- a/FModel/FModel.csproj +++ b/FModel/FModel.csproj @@ -152,7 +152,7 @@ - + diff --git a/FModel/ViewModels/CUE4ParseViewModel.cs b/FModel/ViewModels/CUE4ParseViewModel.cs index 18ebeb30..23c1c7a3 100644 --- a/FModel/ViewModels/CUE4ParseViewModel.cs +++ b/FModel/ViewModels/CUE4ParseViewModel.cs @@ -216,26 +216,26 @@ public class CUE4ParseViewModel : ViewModel ChunkCacheDirectory = cacheDir, ManifestCacheDirectory = cacheDir, ChunkBaseUrl = "http://epicgames-download1.akamaized.net/Builds/Fortnite/CloudDir/", - Zlibng = ZlibHelper.Instance + Zlibng = ZlibHelper.Instance, + CacheChunksAsIs = false }; var startTs = Stopwatch.GetTimestamp(); var (manifest, _) = manifestInfo.DownloadAndParseAsync(manifestOptions, cancellationToken: cancellationToken).GetAwaiter().GetResult(); var parseTime = Stopwatch.GetElapsedTime(startTs); - const bool cacheChunksAsIs = false; foreach (var fileManifest in manifest.FileManifestList) { if (fileManifest.FileName.Equals("Cloud/IoStoreOnDemand.ini", StringComparison.OrdinalIgnoreCase)) { - IoStoreOnDemand.Read(new StreamReader(fileManifest.GetStream(cacheChunksAsIs))); + IoStoreOnDemand.Read(new StreamReader(fileManifest.GetStream())); continue; } if (!_fnLive.IsMatch(fileManifest.FileName)) continue; - p.RegisterVfs(fileManifest.FileName, [fileManifest.GetStream(cacheChunksAsIs)] - , it => new FStreamArchive(it, manifest.FileManifestList.First(x => x.FileName.Equals(it)).GetStream(cacheChunksAsIs), p.Versions)); + p.RegisterVfs(fileManifest.FileName, [fileManifest.GetStream()] + , it => new FStreamArchive(it, manifest.FileManifestList.First(x => x.FileName.Equals(it)).GetStream(), p.Versions)); } FLogger.Append(ELog.Information, () => From bd378594b1e0f40e98b2200e775485c4c741e1fa Mon Sep 17 00:00:00 2001 From: Asval Date: Thu, 13 Jun 2024 15:18:50 +0200 Subject: [PATCH 06/65] fixed #476 --- CUE4Parse | 2 +- FModel/Views/SettingsView.xaml | 14 +++++++------- FModel/Views/Snooper/Shading/TextureHelper.cs | 1 + 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/CUE4Parse b/CUE4Parse index 54639261..38b73387 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit 54639261ecd47dd6206734fe133442bc256cdc93 +Subproject commit 38b733876fe96bfd45f2e29e97244e19136f2dc6 diff --git a/FModel/Views/SettingsView.xaml b/FModel/Views/SettingsView.xaml index 991e945e..7a15eec9 100644 --- a/FModel/Views/SettingsView.xaml +++ b/FModel/Views/SettingsView.xaml @@ -55,7 +55,7 @@ - + + + + diff --git a/FModel/Views/Resources/Controls/CommitControl.xaml.cs b/FModel/Views/Resources/Controls/CommitControl.xaml.cs new file mode 100644 index 00000000..198c05ae --- /dev/null +++ b/FModel/Views/Resources/Controls/CommitControl.xaml.cs @@ -0,0 +1,12 @@ +using System.Windows.Controls; + +namespace FModel.Views.Resources.Controls; + +public partial class CommitControl : UserControl +{ + public CommitControl() + { + InitializeComponent(); + } +} + diff --git a/FModel/Views/Resources/Converters/CommitMessageConverter.cs b/FModel/Views/Resources/Converters/CommitMessageConverter.cs new file mode 100644 index 00000000..22b32fd3 --- /dev/null +++ b/FModel/Views/Resources/Converters/CommitMessageConverter.cs @@ -0,0 +1,25 @@ +using System; +using System.Globalization; +using System.Windows.Data; + +namespace FModel.Views.Resources.Converters; + +public class CommitMessageConverter : IValueConverter +{ + public static readonly CommitMessageConverter Instance = new(); + + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is string commitMessage) + { + var parts = commitMessage.Split("\n\n"); + return parameter?.ToString() == "Title" ? parts[0] : parts.Length > 1 ? parts[1] : string.Empty; + } + return value; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } +} diff --git a/FModel/Views/Resources/Converters/DateTimeToDateConverter.cs b/FModel/Views/Resources/Converters/DateTimeToDateConverter.cs new file mode 100644 index 00000000..1c5bea71 --- /dev/null +++ b/FModel/Views/Resources/Converters/DateTimeToDateConverter.cs @@ -0,0 +1,24 @@ +using System; +using System.Globalization; +using System.Windows.Data; + +namespace FModel.Views.Resources.Converters; + +public class DateTimeToDateConverter : IValueConverter +{ + public static readonly DateTimeToDateConverter Instance = new(); + + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is DateTime dateTime) + { + return DateOnly.FromDateTime(dateTime); + } + return value; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } +} diff --git a/FModel/Views/Resources/Converters/RelativeDateTimeConverter.cs b/FModel/Views/Resources/Converters/RelativeDateTimeConverter.cs new file mode 100644 index 00000000..818bb4f9 --- /dev/null +++ b/FModel/Views/Resources/Converters/RelativeDateTimeConverter.cs @@ -0,0 +1,62 @@ +using System; +using System.Globalization; +using System.Windows.Data; + +namespace FModel.Views.Resources.Converters; + +public class RelativeDateTimeConverter : IValueConverter +{ + public static readonly RelativeDateTimeConverter Instance = new(); + + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is DateTime dateTime) + { + var timeSpan = DateTime.Now - dateTime; + + int time; + string unit; + if (timeSpan.TotalMinutes < 1) + { + time = timeSpan.Seconds; + unit = "second"; + } + else if (timeSpan.TotalHours < 1) + { + time = timeSpan.Minutes; + unit = "minute"; + } + else switch (timeSpan.TotalDays) + { + case < 1: + time = timeSpan.Hours; + unit = "hour"; + break; + case < 7: + time = timeSpan.Days; + unit = "day"; + break; + case < 30: + time = timeSpan.Days / 7; + unit = "week"; + break; + case < 365: + time = timeSpan.Days / 30; + unit = "month"; + break; + default: + time = timeSpan.Days / 365; + unit = "year"; + break; + } + + return $"{time} {unit}{(time > 1 ? "s" : string.Empty)} ago"; + } + return value; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } +} diff --git a/FModel/Views/Resources/Resources.xaml b/FModel/Views/Resources/Resources.xaml index aa279955..d560ab09 100644 --- a/FModel/Views/Resources/Resources.xaml +++ b/FModel/Views/Resources/Resources.xaml @@ -68,6 +68,7 @@ M12 5.83l2.46 2.46c.39.39 1.02.39 1.41 0 .39-.39.39-1.02 0-1.41L12.7 3.7c-.39-.39-1.02-.39-1.41 0L8.12 6.88c-.39.39-.39 1.02 0 1.41.39.39 1.02.39 1.41 0L12 5.83zm0 12.34l-2.46-2.46c-.39-.39-1.02-.39-1.41 0-.39.39-.39 1.02 0 1.41l3.17 3.18c.39.39 1.02.39 1.41 0l3.17-3.17c.39-.39.39-1.02 0-1.41-.39-.39-1.02-.39-1.41 0L12 18.17z M11.71,17.99C8.53,17.84,6,15.22,6,12c0-3.31,2.69-6,6-6c3.22,0,5.84,2.53,5.99,5.71l-2.1-0.63C15.48,9.31,13.89,8,12,8 c-2.21,0-4,1.79-4,4c0,1.89,1.31,3.48,3.08,3.89L11.71,17.99z M22,12c0,0.3-0.01,0.6-0.04,0.9l-1.97-0.59C20,12.21,20,12.1,20,12 c0-4.42-3.58-8-8-8s-8,3.58-8,8s3.58,8,8,8c0.1,0,0.21,0,0.31-0.01l0.59,1.97C12.6,21.99,12.3,22,12,22C6.48,22,2,17.52,2,12 C2,6.48,6.48,2,12,2S22,6.48,22,12z M18.23,16.26l2.27-0.76c0.46-0.15,0.45-0.81-0.01-0.95l-7.6-2.28 c-0.38-0.11-0.74,0.24-0.62,0.62l2.28,7.6c0.14,0.47,0.8,0.48,0.95,0.01l0.76-2.27l3.91,3.91c0.2,0.2,0.51,0.2,0.71,0l1.27-1.27 c0.2-0.2,0.2-0.51,0-0.71L18.23,16.26z M1.8 6q-.525 0-.887-.35Q.55 5.3.55 4.8V4q0-1.425 1.012-2.438Q2.575.55 4 .55h.8q.5 0 .85.362.35.363.35.888 0 .5-.35.85T4.8 3H4q-.425 0-.712.287Q3 3.575 3 4v.8q0 .5-.35.85T1.8 6ZM4 23.45q-1.425 0-2.438-1.012Q.55 21.425.55 20v-.8q0-.5.363-.85.362-.35.887-.35.5 0 .85.35t.35.85v.8q0 .425.288.712Q3.575 21 4 21h.8q.5 0 .85.35t.35.85q0 .525-.35.887-.35.363-.85.363Zm15.2 0q-.5 0-.85-.363-.35-.362-.35-.887 0-.5.35-.85t.85-.35h.8q.425 0 .712-.288Q21 20.425 21 20v-.8q0-.5.35-.85t.85-.35q.525 0 .888.35.362.35.362.85v.8q0 1.425-1.012 2.438Q21.425 23.45 20 23.45ZM22.2 6q-.5 0-.85-.35T21 4.8V4q0-.425-.288-.713Q20.425 3 20 3h-.8q-.5 0-.85-.35T18 1.8q0-.525.35-.888.35-.362.85-.362h.8q1.425 0 2.438 1.012Q23.45 2.575 23.45 4v.8q0 .5-.362.85-.363.35-.888.35ZM12 17.35l1-.575v-4.1l3.55-2.075V9.425l-1-.575L12 10.925 8.45 8.85l-1 .575V10.6L11 12.675v4.1Zm-1.325 2.325-4.55-2.65q-.625-.35-.975-.963-.35-.612-.35-1.337V9.45q0-.725.35-1.337.35-.613.975-.963l4.55-2.65Q11.3 4.15 12 4.15t1.325.35l4.55 2.65q.625.35.975.963.35.612.35 1.337v5.275q0 .725-.35 1.337-.35.613-.975.963l-4.55 2.65q-.625.35-1.325.35t-1.325-.35Z + M3.5 1.75v11.5c0 .09.048.173.126.217a.75.75 0 0 1-.752 1.298A1.748 1.748 0 0 1 2 13.25V1.75C2 .784 2.784 0 3.75 0h5.586c.464 0 .909.185 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v8.586A1.75 1.75 0 0 1 12.25 15h-.5a.75.75 0 0 1 0-1.5h.5a.25.25 0 0 0 .25-.25V4.664a.25.25 0 0 0-.073-.177L9.513 1.573a.25.25 0 0 0-.177-.073H7.25a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1 0-1.5h-3a.25.25 0 0 0-.25.25Zm3.75 8.75h.5c.966 0 1.75.784 1.75 1.75v3a.75.75 0 0 1-.75.75h-2.5a.75.75 0 0 1-.75-.75v-3c0-.966.784-1.75 1.75-1.75ZM6 5.25a.75.75 0 0 1 .75-.75h.5a.75.75 0 0 1 0 1.5h-.5A.75.75 0 0 1 6 5.25Zm.75 2.25h.5a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1 0-1.5ZM8 6.75A.75.75 0 0 1 8.75 6h.5a.75.75 0 0 1 0 1.5h-.5A.75.75 0 0 1 8 6.75ZM8.75 3h.5a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1 0-1.5ZM8 9.75A.75.75 0 0 1 8.75 9h.5a.75.75 0 0 1 0 1.5h-.5A.75.75 0 0 1 8 9.75Zm-1 2.5v2.25h1v-2.25a.25.25 0 0 0-.25-.25h-.5a.25.25 0 0 0-.25.25Z + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FModel/Views/UpdateView.xaml.cs b/FModel/Views/UpdateView.xaml.cs new file mode 100644 index 00000000..61d3f290 --- /dev/null +++ b/FModel/Views/UpdateView.xaml.cs @@ -0,0 +1,30 @@ +using System.Diagnostics; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Navigation; +using FModel.Services; +using FModel.ViewModels; + +namespace FModel.Views; + +public partial class UpdateView +{ + public UpdateView() + { + DataContext = new UpdateViewModel(); + InitializeComponent(); + } + + private async void OnLoaded(object sender, RoutedEventArgs e) + { + if (DataContext is not UpdateViewModel viewModel) return; + await viewModel.Load(); + } + + private void OnRequestNavigate(object sender, RequestNavigateEventArgs e) + { + Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri) { UseShellExecute = true }); + e.Handled = true; + } +} + From bbb495b485fe6ee873500328af0c97e944e8ce61 Mon Sep 17 00:00:00 2001 From: Asval Date: Wed, 25 Sep 2024 18:32:23 +0200 Subject: [PATCH 39/65] versioned backups --- CUE4Parse | 2 +- FModel/ViewModels/BackupManagerViewModel.cs | 32 ++++--- FModel/ViewModels/Commands/LoadCommand.cs | 100 +++++++++++++++----- 3 files changed, 96 insertions(+), 38 deletions(-) diff --git a/CUE4Parse b/CUE4Parse index a01c1442..4f0c1da5 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit a01c144292b1f941b3d67b66ff4b723d4a90d336 +Subproject commit 4f0c1da58127d7b6d46b18c6242971dd140b0bc5 diff --git a/FModel/ViewModels/BackupManagerViewModel.cs b/FModel/ViewModels/BackupManagerViewModel.cs index 14497692..814258c1 100644 --- a/FModel/ViewModels/BackupManagerViewModel.cs +++ b/FModel/ViewModels/BackupManagerViewModel.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Threading.Tasks; using System.Windows; using System.Windows.Data; +using CUE4Parse.FileProvider.Objects; using CUE4Parse.UE4.VirtualFileSystem; using FModel.Framework; using FModel.Services; @@ -20,6 +21,8 @@ namespace FModel.ViewModels; public class BackupManagerViewModel : ViewModel { + public const uint FBKP_MAGIC = 0x504B4246; + private ThreadWorkerViewModel _threadWorkerView => ApplicationService.ThreadWorkerView; private ApiEndpointViewModel _apiEndpointView => ApplicationService.ApiEndpointView; private ApplicationViewModel _applicationView => ApplicationService.ApplicationView; @@ -64,23 +67,21 @@ public class BackupManagerViewModel : ViewModel var backupFolder = Path.Combine(UserSettings.Default.OutputDirectory, "Backups"); var fileName = $"{_gameName}_{DateTime.Now:MM'_'dd'_'yyyy}.fbkp"; var fullPath = Path.Combine(backupFolder, fileName); + var func = new Func(x => !x.Path.EndsWith(".uexp") && !x.Path.EndsWith(".ubulk") && !x.Path.EndsWith(".uptnl")); using var fileStream = new FileStream(fullPath, FileMode.Create); using var compressedStream = LZ4Stream.Encode(fileStream, LZ4Level.L00_FAST); using var writer = new BinaryWriter(compressedStream); + writer.Write(FBKP_MAGIC); + writer.Write((byte) EBackupVersion.Latest); + writer.Write(_applicationView.CUE4Parse.Provider.Files.Values.Count(func)); + foreach (var asset in _applicationView.CUE4Parse.Provider.Files.Values) { - if (asset is not VfsEntry entry || entry.Path.EndsWith(".uexp") || - entry.Path.EndsWith(".ubulk") || entry.Path.EndsWith(".uptnl")) - continue; - - writer.Write((long) 0); - writer.Write((long) 0); - writer.Write(entry.Size); - writer.Write(entry.IsEncrypted); - writer.Write(0); - writer.Write($"/{entry.Path.ToLower()}"); - writer.Write(0); + if (!func(asset)) continue; + writer.Write(asset.Size); + writer.Write(asset.IsEncrypted); + writer.Write($"/{asset.Path.ToLower()}"); } SaveCheck(fullPath, fileName, "created", "create"); @@ -116,3 +117,12 @@ public class BackupManagerViewModel : ViewModel } } } + +public enum EBackupVersion : byte +{ + BeforeVersionWasAdded = 0, + Initial, + + LatestPlusOne, + Latest = LatestPlusOne - 1 +} diff --git a/FModel/ViewModels/Commands/LoadCommand.cs b/FModel/ViewModels/Commands/LoadCommand.cs index 3dfa13b1..2bb6a989 100644 --- a/FModel/ViewModels/Commands/LoadCommand.cs +++ b/FModel/ViewModels/Commands/LoadCommand.cs @@ -154,7 +154,16 @@ public class LoadCommand : ViewModelCommand FLogger.Append(ELog.Information, () => FLogger.Text($"Backup file older than current game is '{openFileDialog.FileName.SubstringAfterLast("\\")}'", Constants.WHITE, true)); - using var fileStream = new FileStream(openFileDialog.FileName, FileMode.Open); + var mode = UserSettings.Default.LoadingMode; + var entries = ParseBackup(openFileDialog.FileName, mode, cancellationToken); + + _applicationView.Status.UpdateStatusLabel($"{mode.ToString()[6..]} Folders & Packages"); + _applicationView.CUE4Parse.AssetsFolder.BulkPopulate(entries); + } + + private List ParseBackup(string path, ELoadingMode mode, CancellationToken cancellationToken = default) + { + using var fileStream = new FileStream(path, FileMode.Open); using var memoryStream = new MemoryStream(); if (fileStream.ReadUInt32() == _IS_LZ4) @@ -169,25 +178,41 @@ public class LoadCommand : ViewModelCommand using var archive = new FStreamArchive(fileStream.Name, memoryStream); var entries = new List(); - var mode = UserSettings.Default.LoadingMode; switch (mode) { case ELoadingMode.AllButNew: { - var paths = new Dictionary(); - while (archive.Position < archive.Length) + var paths = new HashSet(); + var magic = archive.Read(); + if (magic != BackupManagerViewModel.FBKP_MAGIC) { - cancellationToken.ThrowIfCancellationRequested(); + archive.Position -= sizeof(uint); + while (archive.Position < archive.Length) + { + cancellationToken.ThrowIfCancellationRequested(); - archive.Position += 29; - paths[archive.ReadString().ToLower()[1..]] = 0; - archive.Position += 4; + archive.Position += 29; + paths.Add(archive.ReadString().ToLower()[1..]); + archive.Position += 4; + } + } + else + { + var version = archive.Read(); + var count = archive.Read(); + for (var i = 0; i < count; i++) + { + cancellationToken.ThrowIfCancellationRequested(); + + archive.Position += sizeof(long) + sizeof(byte); + paths.Add(archive.ReadString().ToLower()[1..]); + } } foreach (var (key, value) in _applicationView.CUE4Parse.Provider.Files) { cancellationToken.ThrowIfCancellationRequested(); - if (value is not VfsEntry entry || paths.ContainsKey(key) || entry.Path.EndsWith(".uexp") || + if (value is not VfsEntry entry || paths.Contains(key) || entry.Path.EndsWith(".uexp") || entry.Path.EndsWith(".ubulk") || entry.Path.EndsWith(".uptnl")) continue; entries.Add(entry); @@ -198,31 +223,54 @@ public class LoadCommand : ViewModelCommand } case ELoadingMode.AllButModified: { - while (archive.Position < archive.Length) + var magic = archive.Read(); + if (magic != BackupManagerViewModel.FBKP_MAGIC) { - cancellationToken.ThrowIfCancellationRequested(); + archive.Position -= sizeof(uint); + while (archive.Position < archive.Length) + { + cancellationToken.ThrowIfCancellationRequested(); - archive.Position += 16; - var uncompressedSize = archive.Read(); - var isEncrypted = archive.ReadFlag(); - archive.Position += 4; - var fullPath = archive.ReadString().ToLower()[1..]; - archive.Position += 4; + archive.Position += 16; + var uncompressedSize = archive.Read(); + var isEncrypted = archive.ReadFlag(); + archive.Position += 4; + var fullPath = archive.ReadString().ToLower()[1..]; + archive.Position += 4; - if (fullPath.EndsWith(".uexp") || fullPath.EndsWith(".ubulk") || fullPath.EndsWith(".uptnl") || - !_applicationView.CUE4Parse.Provider.Files.TryGetValue(fullPath, out var asset) || asset is not VfsEntry entry || - entry.Size == uncompressedSize && entry.IsEncrypted == isEncrypted) - continue; - - entries.Add(entry); - _applicationView.Status.UpdateStatusLabel(entry.Vfs.Name); + AddEntry(fullPath, uncompressedSize, isEncrypted, entries); + } } + else + { + var version = archive.Read(); + var count = archive.Read(); + for (var i = 0; i < count; i++) + { + cancellationToken.ThrowIfCancellationRequested(); + var uncompressedSize = archive.Read(); + var isEncrypted = archive.ReadFlag(); + var fullPath = archive.ReadString().ToLower()[1..]; + + AddEntry(fullPath, uncompressedSize, isEncrypted, entries); + } + } break; } } - _applicationView.Status.UpdateStatusLabel($"{mode.ToString()[6..]} Folders & Packages"); - _applicationView.CUE4Parse.AssetsFolder.BulkPopulate(entries); + return entries; + } + + private void AddEntry(string path, long uncompressedSize, bool isEncrypted, List entries) + { + if (path.EndsWith(".uexp") || path.EndsWith(".ubulk") || path.EndsWith(".uptnl") || + !_applicationView.CUE4Parse.Provider.Files.TryGetValue(path, out var asset) || asset is not VfsEntry entry || + entry.Size == uncompressedSize && entry.IsEncrypted == isEncrypted) + return; + + entries.Add(entry); + _applicationView.Status.UpdateStatusLabel(entry.Vfs.Name); } } From 6d4c76f2a4a01ae782a998fbb4f8261803932e6b Mon Sep 17 00:00:00 2001 From: Asval Date: Sun, 22 Sep 2024 20:23:59 +0200 Subject: [PATCH 40/65] ctrl s --- FModel/Constants.cs | 1 + FModel/MainWindow.xaml.cs | 2 + .../ApiEndpoints/FModelApiEndpoint.cs | 11 +++ .../ApiEndpoints/Models/FModelResponse.cs | 22 +++++ FModel/ViewModels/UpdateViewModel.cs | 29 +++++++ .../Resources/Controls/CommitControl.xaml | 81 +++++++++++++++++++ .../Resources/Controls/CommitControl.xaml.cs | 12 +++ .../Converters/CommitMessageConverter.cs | 25 ++++++ .../Converters/DateTimeToDateConverter.cs | 24 ++++++ .../Converters/RelativeDateTimeConverter.cs | 62 ++++++++++++++ FModel/Views/Resources/Resources.xaml | 1 + FModel/Views/UpdateView.xaml | 66 +++++++++++++++ FModel/Views/UpdateView.xaml.cs | 30 +++++++ 13 files changed, 366 insertions(+) create mode 100644 FModel/ViewModels/UpdateViewModel.cs create mode 100644 FModel/Views/Resources/Controls/CommitControl.xaml create mode 100644 FModel/Views/Resources/Controls/CommitControl.xaml.cs create mode 100644 FModel/Views/Resources/Converters/CommitMessageConverter.cs create mode 100644 FModel/Views/Resources/Converters/DateTimeToDateConverter.cs create mode 100644 FModel/Views/Resources/Converters/RelativeDateTimeConverter.cs create mode 100644 FModel/Views/UpdateView.xaml create mode 100644 FModel/Views/UpdateView.xaml.cs diff --git a/FModel/Constants.cs b/FModel/Constants.cs index a0bf4597..409ddba4 100644 --- a/FModel/Constants.cs +++ b/FModel/Constants.cs @@ -21,6 +21,7 @@ public static class Constants public const string BLUE = "#528BCC"; public const string ISSUE_LINK = "https://github.com/4sval/FModel/discussions/categories/q-a"; + public const string COMMITS_LINK = "https://api.github.com/repos/4sval/FModel/commits"; public const string DONATE_LINK = "https://fmodel.app/donate"; public const string DISCORD_LINK = "https://fmodel.app/discord"; diff --git a/FModel/MainWindow.xaml.cs b/FModel/MainWindow.xaml.cs index 6dcede02..150ed139 100644 --- a/FModel/MainWindow.xaml.cs +++ b/FModel/MainWindow.xaml.cs @@ -45,6 +45,8 @@ public partial class MainWindow private async void OnLoaded(object sender, RoutedEventArgs e) { + var result = new UpdateView().ShowDialog(); + var newOrUpdated = UserSettings.Default.ShowChangelog; #if !DEBUG ApplicationService.ApiEndpointView.FModelApi.CheckForUpdates(UserSettings.Default.UpdateMode, true); diff --git a/FModel/ViewModels/ApiEndpoints/FModelApiEndpoint.cs b/FModel/ViewModels/ApiEndpoints/FModelApiEndpoint.cs index 1fbe18f0..99a695f9 100644 --- a/FModel/ViewModels/ApiEndpoints/FModelApiEndpoint.cs +++ b/FModel/ViewModels/ApiEndpoints/FModelApiEndpoint.cs @@ -22,6 +22,7 @@ namespace FModel.ViewModels.ApiEndpoints; public class FModelApiEndpoint : AbstractApiProvider { + private GitHubCommit[] _commits; private News _news; private Info _infos; private Donator[] _donators; @@ -32,6 +33,16 @@ public class FModelApiEndpoint : AbstractApiProvider public FModelApiEndpoint(RestClient client) : base(client) { } + public async Task GetGitHubCommitHistoryAsync(string branch = "dev", int page = 1, int limit = 20) + { + var request = new FRestRequest(Constants.COMMITS_LINK); + request.AddParameter("sha", branch); + request.AddParameter("page", page); + request.AddParameter("per_page", limit); + var response = await _client.ExecuteAsync(request).ConfigureAwait(false); + return response.Data; + } + public async Task GetNewsAsync(CancellationToken token, string game) { var request = new FRestRequest($"https://api.fmodel.app/v1/news/{Constants.APP_VERSION}"); diff --git a/FModel/ViewModels/ApiEndpoints/Models/FModelResponse.cs b/FModel/ViewModels/ApiEndpoints/Models/FModelResponse.cs index 6c9b8dc4..bb5900e5 100644 --- a/FModel/ViewModels/ApiEndpoints/Models/FModelResponse.cs +++ b/FModel/ViewModels/ApiEndpoints/Models/FModelResponse.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Diagnostics; using CUE4Parse.UE4.Versions; @@ -8,6 +9,27 @@ using J = Newtonsoft.Json.JsonPropertyAttribute; namespace FModel.ViewModels.ApiEndpoints.Models; +public class GitHubCommit +{ + [J("sha")] public string Sha { get; private set; } + [J("commit")] public Commit Commit { get; private set; } + [J("author")] public Author Author { get; private set; } +} + +public class Commit +{ + [J("author")] public Author Author { get; set; } + [J("message")] public string Message { get; set; } +} + +public class Author +{ + [J("name")] public string Name { get; set; } + [J("date")] public DateTime Date { get; set; } + [J("avatar_url")] public string AvatarUrl { get; set; } + [J("html_url")] public string HtmlUrl { get; set; } +} + [DebuggerDisplay("{" + nameof(Messages) + "}")] public class News { diff --git a/FModel/ViewModels/UpdateViewModel.cs b/FModel/ViewModels/UpdateViewModel.cs new file mode 100644 index 00000000..4a287efa --- /dev/null +++ b/FModel/ViewModels/UpdateViewModel.cs @@ -0,0 +1,29 @@ +using System.ComponentModel; +using System.Threading.Tasks; +using System.Windows.Data; +using FModel.Framework; +using FModel.Services; +using FModel.ViewModels.ApiEndpoints.Models; +using FModel.Views.Resources.Converters; + +namespace FModel.ViewModels; + +public class UpdateViewModel : ViewModel +{ + public RangeObservableCollection Commits { get; } + public ICollectionView CommitsView { get; } + + public UpdateViewModel() + { + Commits = new RangeObservableCollection(); + CommitsView = new ListCollectionView(Commits) + { + GroupDescriptions = { new PropertyGroupDescription("Commit.Author.Date", new DateTimeToDateConverter()) } + }; + } + + public async Task Load() + { + Commits.AddRange(await ApplicationService.ApiEndpointView.FModelApi.GetGitHubCommitHistoryAsync()); + } +} diff --git a/FModel/Views/Resources/Controls/CommitControl.xaml b/FModel/Views/Resources/Controls/CommitControl.xaml new file mode 100644 index 00000000..97b6b4be --- /dev/null +++ b/FModel/Views/Resources/Controls/CommitControl.xaml @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FModel/Views/Resources/Controls/CommitControl.xaml.cs b/FModel/Views/Resources/Controls/CommitControl.xaml.cs new file mode 100644 index 00000000..198c05ae --- /dev/null +++ b/FModel/Views/Resources/Controls/CommitControl.xaml.cs @@ -0,0 +1,12 @@ +using System.Windows.Controls; + +namespace FModel.Views.Resources.Controls; + +public partial class CommitControl : UserControl +{ + public CommitControl() + { + InitializeComponent(); + } +} + diff --git a/FModel/Views/Resources/Converters/CommitMessageConverter.cs b/FModel/Views/Resources/Converters/CommitMessageConverter.cs new file mode 100644 index 00000000..22b32fd3 --- /dev/null +++ b/FModel/Views/Resources/Converters/CommitMessageConverter.cs @@ -0,0 +1,25 @@ +using System; +using System.Globalization; +using System.Windows.Data; + +namespace FModel.Views.Resources.Converters; + +public class CommitMessageConverter : IValueConverter +{ + public static readonly CommitMessageConverter Instance = new(); + + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is string commitMessage) + { + var parts = commitMessage.Split("\n\n"); + return parameter?.ToString() == "Title" ? parts[0] : parts.Length > 1 ? parts[1] : string.Empty; + } + return value; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } +} diff --git a/FModel/Views/Resources/Converters/DateTimeToDateConverter.cs b/FModel/Views/Resources/Converters/DateTimeToDateConverter.cs new file mode 100644 index 00000000..1c5bea71 --- /dev/null +++ b/FModel/Views/Resources/Converters/DateTimeToDateConverter.cs @@ -0,0 +1,24 @@ +using System; +using System.Globalization; +using System.Windows.Data; + +namespace FModel.Views.Resources.Converters; + +public class DateTimeToDateConverter : IValueConverter +{ + public static readonly DateTimeToDateConverter Instance = new(); + + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is DateTime dateTime) + { + return DateOnly.FromDateTime(dateTime); + } + return value; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } +} diff --git a/FModel/Views/Resources/Converters/RelativeDateTimeConverter.cs b/FModel/Views/Resources/Converters/RelativeDateTimeConverter.cs new file mode 100644 index 00000000..818bb4f9 --- /dev/null +++ b/FModel/Views/Resources/Converters/RelativeDateTimeConverter.cs @@ -0,0 +1,62 @@ +using System; +using System.Globalization; +using System.Windows.Data; + +namespace FModel.Views.Resources.Converters; + +public class RelativeDateTimeConverter : IValueConverter +{ + public static readonly RelativeDateTimeConverter Instance = new(); + + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is DateTime dateTime) + { + var timeSpan = DateTime.Now - dateTime; + + int time; + string unit; + if (timeSpan.TotalMinutes < 1) + { + time = timeSpan.Seconds; + unit = "second"; + } + else if (timeSpan.TotalHours < 1) + { + time = timeSpan.Minutes; + unit = "minute"; + } + else switch (timeSpan.TotalDays) + { + case < 1: + time = timeSpan.Hours; + unit = "hour"; + break; + case < 7: + time = timeSpan.Days; + unit = "day"; + break; + case < 30: + time = timeSpan.Days / 7; + unit = "week"; + break; + case < 365: + time = timeSpan.Days / 30; + unit = "month"; + break; + default: + time = timeSpan.Days / 365; + unit = "year"; + break; + } + + return $"{time} {unit}{(time > 1 ? "s" : string.Empty)} ago"; + } + return value; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } +} diff --git a/FModel/Views/Resources/Resources.xaml b/FModel/Views/Resources/Resources.xaml index aa279955..d560ab09 100644 --- a/FModel/Views/Resources/Resources.xaml +++ b/FModel/Views/Resources/Resources.xaml @@ -68,6 +68,7 @@ M12 5.83l2.46 2.46c.39.39 1.02.39 1.41 0 .39-.39.39-1.02 0-1.41L12.7 3.7c-.39-.39-1.02-.39-1.41 0L8.12 6.88c-.39.39-.39 1.02 0 1.41.39.39 1.02.39 1.41 0L12 5.83zm0 12.34l-2.46-2.46c-.39-.39-1.02-.39-1.41 0-.39.39-.39 1.02 0 1.41l3.17 3.18c.39.39 1.02.39 1.41 0l3.17-3.17c.39-.39.39-1.02 0-1.41-.39-.39-1.02-.39-1.41 0L12 18.17z M11.71,17.99C8.53,17.84,6,15.22,6,12c0-3.31,2.69-6,6-6c3.22,0,5.84,2.53,5.99,5.71l-2.1-0.63C15.48,9.31,13.89,8,12,8 c-2.21,0-4,1.79-4,4c0,1.89,1.31,3.48,3.08,3.89L11.71,17.99z M22,12c0,0.3-0.01,0.6-0.04,0.9l-1.97-0.59C20,12.21,20,12.1,20,12 c0-4.42-3.58-8-8-8s-8,3.58-8,8s3.58,8,8,8c0.1,0,0.21,0,0.31-0.01l0.59,1.97C12.6,21.99,12.3,22,12,22C6.48,22,2,17.52,2,12 C2,6.48,6.48,2,12,2S22,6.48,22,12z M18.23,16.26l2.27-0.76c0.46-0.15,0.45-0.81-0.01-0.95l-7.6-2.28 c-0.38-0.11-0.74,0.24-0.62,0.62l2.28,7.6c0.14,0.47,0.8,0.48,0.95,0.01l0.76-2.27l3.91,3.91c0.2,0.2,0.51,0.2,0.71,0l1.27-1.27 c0.2-0.2,0.2-0.51,0-0.71L18.23,16.26z M1.8 6q-.525 0-.887-.35Q.55 5.3.55 4.8V4q0-1.425 1.012-2.438Q2.575.55 4 .55h.8q.5 0 .85.362.35.363.35.888 0 .5-.35.85T4.8 3H4q-.425 0-.712.287Q3 3.575 3 4v.8q0 .5-.35.85T1.8 6ZM4 23.45q-1.425 0-2.438-1.012Q.55 21.425.55 20v-.8q0-.5.363-.85.362-.35.887-.35.5 0 .85.35t.35.85v.8q0 .425.288.712Q3.575 21 4 21h.8q.5 0 .85.35t.35.85q0 .525-.35.887-.35.363-.85.363Zm15.2 0q-.5 0-.85-.363-.35-.362-.35-.887 0-.5.35-.85t.85-.35h.8q.425 0 .712-.288Q21 20.425 21 20v-.8q0-.5.35-.85t.85-.35q.525 0 .888.35.362.35.362.85v.8q0 1.425-1.012 2.438Q21.425 23.45 20 23.45ZM22.2 6q-.5 0-.85-.35T21 4.8V4q0-.425-.288-.713Q20.425 3 20 3h-.8q-.5 0-.85-.35T18 1.8q0-.525.35-.888.35-.362.85-.362h.8q1.425 0 2.438 1.012Q23.45 2.575 23.45 4v.8q0 .5-.362.85-.363.35-.888.35ZM12 17.35l1-.575v-4.1l3.55-2.075V9.425l-1-.575L12 10.925 8.45 8.85l-1 .575V10.6L11 12.675v4.1Zm-1.325 2.325-4.55-2.65q-.625-.35-.975-.963-.35-.612-.35-1.337V9.45q0-.725.35-1.337.35-.613.975-.963l4.55-2.65Q11.3 4.15 12 4.15t1.325.35l4.55 2.65q.625.35.975.963.35.612.35 1.337v5.275q0 .725-.35 1.337-.35.613-.975.963l-4.55 2.65q-.625.35-1.325.35t-1.325-.35Z + M3.5 1.75v11.5c0 .09.048.173.126.217a.75.75 0 0 1-.752 1.298A1.748 1.748 0 0 1 2 13.25V1.75C2 .784 2.784 0 3.75 0h5.586c.464 0 .909.185 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v8.586A1.75 1.75 0 0 1 12.25 15h-.5a.75.75 0 0 1 0-1.5h.5a.25.25 0 0 0 .25-.25V4.664a.25.25 0 0 0-.073-.177L9.513 1.573a.25.25 0 0 0-.177-.073H7.25a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1 0-1.5h-3a.25.25 0 0 0-.25.25Zm3.75 8.75h.5c.966 0 1.75.784 1.75 1.75v3a.75.75 0 0 1-.75.75h-2.5a.75.75 0 0 1-.75-.75v-3c0-.966.784-1.75 1.75-1.75ZM6 5.25a.75.75 0 0 1 .75-.75h.5a.75.75 0 0 1 0 1.5h-.5A.75.75 0 0 1 6 5.25Zm.75 2.25h.5a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1 0-1.5ZM8 6.75A.75.75 0 0 1 8.75 6h.5a.75.75 0 0 1 0 1.5h-.5A.75.75 0 0 1 8 6.75ZM8.75 3h.5a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1 0-1.5ZM8 9.75A.75.75 0 0 1 8.75 9h.5a.75.75 0 0 1 0 1.5h-.5A.75.75 0 0 1 8 9.75Zm-1 2.5v2.25h1v-2.25a.25.25 0 0 0-.25-.25h-.5a.25.25 0 0 0-.25.25Z + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FModel/Views/UpdateView.xaml.cs b/FModel/Views/UpdateView.xaml.cs new file mode 100644 index 00000000..61d3f290 --- /dev/null +++ b/FModel/Views/UpdateView.xaml.cs @@ -0,0 +1,30 @@ +using System.Diagnostics; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Navigation; +using FModel.Services; +using FModel.ViewModels; + +namespace FModel.Views; + +public partial class UpdateView +{ + public UpdateView() + { + DataContext = new UpdateViewModel(); + InitializeComponent(); + } + + private async void OnLoaded(object sender, RoutedEventArgs e) + { + if (DataContext is not UpdateViewModel viewModel) return; + await viewModel.Load(); + } + + private void OnRequestNavigate(object sender, RequestNavigateEventArgs e) + { + Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri) { UseShellExecute = true }); + e.Handled = true; + } +} + From 6a527c3a2fc0e3bde22aece6a16ca91d2b056488 Mon Sep 17 00:00:00 2001 From: Asval Date: Wed, 25 Sep 2024 18:42:09 +0200 Subject: [PATCH 41/65] fix --- FModel/Views/Resources/Converters/RelativeDateTimeConverter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FModel/Views/Resources/Converters/RelativeDateTimeConverter.cs b/FModel/Views/Resources/Converters/RelativeDateTimeConverter.cs index 818bb4f9..60525aa7 100644 --- a/FModel/Views/Resources/Converters/RelativeDateTimeConverter.cs +++ b/FModel/Views/Resources/Converters/RelativeDateTimeConverter.cs @@ -12,7 +12,7 @@ public class RelativeDateTimeConverter : IValueConverter { if (value is DateTime dateTime) { - var timeSpan = DateTime.Now - dateTime; + var timeSpan = DateTime.Now - dateTime.ToLocalTime(); int time; string unit; From 7e35306b0174a99e2ebd1020d7fc38c4a48dd287 Mon Sep 17 00:00:00 2001 From: Asval Date: Sat, 28 Sep 2024 20:10:08 +0200 Subject: [PATCH 42/65] history ui done --- FModel/Constants.cs | 4 +- .../ApiEndpoints/FModelApiEndpoint.cs | 9 ++- .../ApiEndpoints/Models/FModelResponse.cs | 30 +++++++- FModel/ViewModels/UpdateViewModel.cs | 31 +++++++- .../Resources/Controls/CommitControl.xaml | 46 ++++++------ .../Controls/CommitDownloaderControl.xaml | 53 ++++++++++++++ .../Controls/CommitDownloaderControl.xaml.cs | 23 ++++++ FModel/Views/UpdateView.xaml | 72 ++++++++++--------- 8 files changed, 210 insertions(+), 58 deletions(-) create mode 100644 FModel/Views/Resources/Controls/CommitDownloaderControl.xaml create mode 100644 FModel/Views/Resources/Controls/CommitDownloaderControl.xaml.cs diff --git a/FModel/Constants.cs b/FModel/Constants.cs index 409ddba4..94911598 100644 --- a/FModel/Constants.cs +++ b/FModel/Constants.cs @@ -21,7 +21,9 @@ public static class Constants public const string BLUE = "#528BCC"; public const string ISSUE_LINK = "https://github.com/4sval/FModel/discussions/categories/q-a"; - public const string COMMITS_LINK = "https://api.github.com/repos/4sval/FModel/commits"; + public const string GH_REPO = "https://api.github.com/repos/4sval/FModel"; + public const string GH_COMMITS_HISTORY = GH_REPO + "/commits"; + public const string GH_RELEASES = GH_REPO + "/releases"; public const string DONATE_LINK = "https://fmodel.app/donate"; public const string DISCORD_LINK = "https://fmodel.app/discord"; diff --git a/FModel/ViewModels/ApiEndpoints/FModelApiEndpoint.cs b/FModel/ViewModels/ApiEndpoints/FModelApiEndpoint.cs index 99a695f9..2d5fdc07 100644 --- a/FModel/ViewModels/ApiEndpoints/FModelApiEndpoint.cs +++ b/FModel/ViewModels/ApiEndpoints/FModelApiEndpoint.cs @@ -35,7 +35,7 @@ public class FModelApiEndpoint : AbstractApiProvider public async Task GetGitHubCommitHistoryAsync(string branch = "dev", int page = 1, int limit = 20) { - var request = new FRestRequest(Constants.COMMITS_LINK); + var request = new FRestRequest(Constants.GH_COMMITS_HISTORY); request.AddParameter("sha", branch); request.AddParameter("page", page); request.AddParameter("per_page", limit); @@ -43,6 +43,13 @@ public class FModelApiEndpoint : AbstractApiProvider return response.Data; } + public async Task GetGitHubReleaseAsync(string tag) + { + var request = new FRestRequest($"{Constants.GH_RELEASES}/tags/{tag}"); + var response = await _client.ExecuteAsync(request).ConfigureAwait(false); + return response.Data; + } + public async Task GetNewsAsync(CancellationToken token, string game) { var request = new FRestRequest($"https://api.fmodel.app/v1/news/{Constants.APP_VERSION}"); diff --git a/FModel/ViewModels/ApiEndpoints/Models/FModelResponse.cs b/FModel/ViewModels/ApiEndpoints/Models/FModelResponse.cs index bb5900e5..bae4f4b2 100644 --- a/FModel/ViewModels/ApiEndpoints/Models/FModelResponse.cs +++ b/FModel/ViewModels/ApiEndpoints/Models/FModelResponse.cs @@ -4,16 +4,44 @@ using System.Diagnostics; using CUE4Parse.UE4.Versions; using FModel.Creator; using FModel.Extensions; +using FModel.Framework; using SkiaSharp; using J = Newtonsoft.Json.JsonPropertyAttribute; namespace FModel.ViewModels.ApiEndpoints.Models; -public class GitHubCommit +public class GitHubRelease +{ + [J("assets")] public GitHubAsset[] Assets { get; private set; } +} + +public class GitHubAsset +{ + [J("name")] public string Name { get; private set; } + [J("size")] public int Size { get; private set; } + [J("download_count")] public int DownloadCount { get; private set; } + [J("browser_download_url")] public string BrowserDownloadUrl { get; private set; } +} + +public class GitHubCommit : ViewModel { [J("sha")] public string Sha { get; private set; } [J("commit")] public Commit Commit { get; private set; } [J("author")] public Author Author { get; private set; } + + private GitHubAsset _asset; + public GitHubAsset Asset + { + get => _asset; + set + { + SetProperty(ref _asset, value); + RaisePropertyChanged(nameof(IsDownloadable)); + } + } + + public string ShortSha => Sha[..7]; + public bool IsDownloadable => Asset != null; } public class Commit diff --git a/FModel/ViewModels/UpdateViewModel.cs b/FModel/ViewModels/UpdateViewModel.cs index 4a287efa..876a4558 100644 --- a/FModel/ViewModels/UpdateViewModel.cs +++ b/FModel/ViewModels/UpdateViewModel.cs @@ -1,15 +1,21 @@ using System.ComponentModel; +using System.IO; +using System.Linq; using System.Threading.Tasks; using System.Windows.Data; +using FModel.Extensions; using FModel.Framework; using FModel.Services; using FModel.ViewModels.ApiEndpoints.Models; using FModel.Views.Resources.Converters; +using Newtonsoft.Json; namespace FModel.ViewModels; public class UpdateViewModel : ViewModel { + private ApiEndpointViewModel _apiEndpointView => ApplicationService.ApiEndpointView; + public RangeObservableCollection Commits { get; } public ICollectionView CommitsView { get; } @@ -24,6 +30,29 @@ public class UpdateViewModel : ViewModel public async Task Load() { - Commits.AddRange(await ApplicationService.ApiEndpointView.FModelApi.GetGitHubCommitHistoryAsync()); +#if DEBUG + Commits.AddRange(JsonConvert.DeserializeObject(await File.ReadAllTextAsync(@"C:\Users\valen\Downloads\history.json"))); +#else + Commits.AddRange(await _apiEndpointView.FModelApi.GetGitHubCommitHistoryAsync()); +#endif + _ = PostLoad(); + } + + private async Task PostLoad() + { +#if DEBUG + var qa = JsonConvert.DeserializeObject(await File.ReadAllTextAsync(@"C:\Users\valen\Downloads\qa.json")); +#else + var qa = await _apiEndpointView.FModelApi.GetGitHubReleaseAsync("qa"); +#endif + foreach (var asset in qa.Assets) + { + var commitSha = asset.Name.SubstringBeforeLast(".zip"); + var commit = Commits.FirstOrDefault(x => x.Sha == commitSha); + if (commit != null) + { + commit.Asset = asset; + } + } } } diff --git a/FModel/Views/Resources/Controls/CommitControl.xaml b/FModel/Views/Resources/Controls/CommitControl.xaml index 97b6b4be..33d288bd 100644 --- a/FModel/Views/Resources/Controls/CommitControl.xaml +++ b/FModel/Views/Resources/Controls/CommitControl.xaml @@ -2,7 +2,8 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:converters="clr-namespace:FModel.Views.Resources.Converters" - xmlns:adonisUi="clr-namespace:AdonisUI;assembly=AdonisUI"> + xmlns:adonisUi="clr-namespace:AdonisUI;assembly=AdonisUI" + xmlns:controls="clr-namespace:FModel.Views.Resources.Controls"> @@ -10,17 +11,15 @@ - - - - - - + + + + + + - - + @@ -65,17 +64,20 @@ - - - + + + + + + + diff --git a/FModel/Views/Resources/Controls/CommitDownloaderControl.xaml b/FModel/Views/Resources/Controls/CommitDownloaderControl.xaml new file mode 100644 index 00000000..71082c8f --- /dev/null +++ b/FModel/Views/Resources/Controls/CommitDownloaderControl.xaml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FModel/Views/Resources/Controls/CommitDownloaderControl.xaml.cs b/FModel/Views/Resources/Controls/CommitDownloaderControl.xaml.cs new file mode 100644 index 00000000..c3e950e0 --- /dev/null +++ b/FModel/Views/Resources/Controls/CommitDownloaderControl.xaml.cs @@ -0,0 +1,23 @@ +using System.Windows; +using System.Windows.Controls; +using FModel.ViewModels.ApiEndpoints.Models; + +namespace FModel.Views.Resources.Controls; + +public partial class CommitDownloaderControl : UserControl +{ + public CommitDownloaderControl() + { + InitializeComponent(); + } + + public static readonly DependencyProperty CommitAssetProperty = + DependencyProperty.Register("CommitAsset", typeof(GitHubAsset), typeof(CommitDownloaderControl), new PropertyMetadata(null)); + + public GitHubAsset CommitAsset + { + get { return (GitHubAsset)GetValue(CommitAssetProperty); } + set { SetValue(CommitAssetProperty, value); } + } +} + diff --git a/FModel/Views/UpdateView.xaml b/FModel/Views/UpdateView.xaml index a149194a..c9d2567e 100644 --- a/FModel/Views/UpdateView.xaml +++ b/FModel/Views/UpdateView.xaml @@ -2,11 +2,10 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:converters="clr-namespace:FModel.Views.Resources.Converters" - xmlns:adonisUi="clr-namespace:AdonisUI;assembly=AdonisUI" + xmlns:adonisExtensions="clr-namespace:AdonisUI.Extensions;assembly=AdonisUI" xmlns:adonisControls="clr-namespace:AdonisUI.Controls;assembly=AdonisUI" xmlns:controls="clr-namespace:FModel.Views.Resources.Controls" MinHeight="{Binding Source={x:Static SystemParameters.MaximizedPrimaryScreenHeight}, Converter={converters:RatioConverter}, ConverterParameter='0.20'}" - MaxHeight="{Binding Source={x:Static SystemParameters.MaximizedPrimaryScreenHeight}, Converter={converters:RatioConverter}, ConverterParameter='0.80'}" Width="{Binding Source={x:Static SystemParameters.MaximizedPrimaryScreenWidth}, Converter={converters:RatioConverter}, ConverterParameter='0.50'}" Loaded="OnLoaded"> @@ -31,36 +30,45 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + From fdf3deed7655382c65a933118979b3a815d85dda Mon Sep 17 00:00:00 2001 From: Asval Date: Sat, 28 Sep 2024 20:19:15 +0200 Subject: [PATCH 43/65] poc --- .../Views/Resources/Controls/CommitDownloaderControl.xaml | 3 ++- .../Resources/Controls/CommitDownloaderControl.xaml.cs | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/FModel/Views/Resources/Controls/CommitDownloaderControl.xaml b/FModel/Views/Resources/Controls/CommitDownloaderControl.xaml index 71082c8f..f6f19e4d 100644 --- a/FModel/Views/Resources/Controls/CommitDownloaderControl.xaml +++ b/FModel/Views/Resources/Controls/CommitDownloaderControl.xaml @@ -38,7 +38,8 @@ - + + + + + + + + + + + - + + + + @@ -69,6 +87,6 @@ - + diff --git a/FModel/Views/UpdateView.xaml.cs b/FModel/Views/UpdateView.xaml.cs index 61d3f290..a1c284a4 100644 --- a/FModel/Views/UpdateView.xaml.cs +++ b/FModel/Views/UpdateView.xaml.cs @@ -1,8 +1,4 @@ -using System.Diagnostics; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Navigation; -using FModel.Services; +using System.Windows; using FModel.ViewModels; namespace FModel.Views; @@ -20,11 +16,5 @@ public partial class UpdateView if (DataContext is not UpdateViewModel viewModel) return; await viewModel.Load(); } - - private void OnRequestNavigate(object sender, RequestNavigateEventArgs e) - { - Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri) { UseShellExecute = true }); - e.Handled = true; - } } From e668c539471c16a9fb08d0bc65f54dc3a0691b8f Mon Sep 17 00:00:00 2001 From: LongerWarrior Date: Fri, 4 Oct 2024 01:32:57 +0300 Subject: [PATCH 52/65] bump --- CUE4Parse | 2 +- FModel/ViewModels/CUE4ParseViewModel.cs | 35 ++++++++++++++----------- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/CUE4Parse b/CUE4Parse index f30b4807..69c71336 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit f30b4807467a6d91bdb10210ff20db5812160bbf +Subproject commit 69c713361fb53c07a5c55a771555817d2bd28159 diff --git a/FModel/ViewModels/CUE4ParseViewModel.cs b/FModel/ViewModels/CUE4ParseViewModel.cs index 7b6a4c5a..57ee9ec2 100644 --- a/FModel/ViewModels/CUE4ParseViewModel.cs +++ b/FModel/ViewModels/CUE4ParseViewModel.cs @@ -15,6 +15,7 @@ using CUE4Parse.Compression; using CUE4Parse.Encryption.Aes; using CUE4Parse.FileProvider; using CUE4Parse.FileProvider.Vfs; +using CUE4Parse.GameTypes.ApexMobile.Encryption.Aes; using CUE4Parse.GameTypes.DBD.Encryption.Aes; using CUE4Parse.GameTypes.DeltaForce.Encryption.Aes; using CUE4Parse.GameTypes.DreamStar.Encryption.Aes; @@ -23,8 +24,9 @@ using CUE4Parse.GameTypes.FunkoFusion.Encryption.Aes; using CUE4Parse.GameTypes.MJS.Encryption.Aes; using CUE4Parse.GameTypes.NetEase.MAR.Encryption.Aes; using CUE4Parse.GameTypes.PAXDEI.Encryption.Aes; -using CUE4Parse.GameTypes.Rennsport.Encryption.Aes; -using CUE4Parse.GameTypes.UDWN.Encryption.Aes; +using CUE4Parse.GameTypes.Rennsport.Encryption.Aes; +using CUE4Parse.GameTypes.Snowbreak.Encryption.Aes; +using CUE4Parse.GameTypes.UDWN.Encryption.Aes; using CUE4Parse.GameTypes.THPS.Encryption.Aes; using CUE4Parse.MappingsProvider; using CUE4Parse.UE4.AssetRegistry; @@ -50,7 +52,6 @@ using CUE4Parse.UE4.Wwise; using CUE4Parse_Conversion; using CUE4Parse_Conversion.Sounds; - using EpicManifestParser; using FModel.Creator; @@ -192,6 +193,8 @@ public class CUE4ParseViewModel : ViewModel Provider.ReadScriptData = UserSettings.Default.ReadScriptData; Provider.CustomEncryption = Provider.Versions.Game switch { + EGame.GAME_ApexLegendsMobile => ApexLegendsMobileAes.DecryptApexMobile, + EGame.GAME_Snowbreak => SnowbreakAes.SnowbreakDecrypt, EGame.GAME_MarvelRivals => MarvelAes.MarvelDecrypt, EGame.GAME_Undawn => ToaaAes.ToaaDecrypt, EGame.GAME_DeadByDaylight => DBDAes.DbDDecrypt, @@ -200,8 +203,8 @@ public class CUE4ParseViewModel : ViewModel EGame.GAME_DreamStar => DreamStarAes.DreamStarDecrypt, EGame.GAME_DeltaForceHawkOps => DeltaForceAes.DeltaForceDecrypt, EGame.GAME_MonsterJamShowdown => MonsterJamShowdownAes.MonsterJamShowdownDecrypt, - EGame.GAME_Rennsport => RennsportAes.RennsportDecrypt, - EGame.GAME_FunkoFusion => FunkoFusionAes.FunkoFusionDecrypt, + EGame.GAME_Rennsport => RennsportAes.RennsportDecrypt, + EGame.GAME_FunkoFusion => FunkoFusionAes.FunkoFusionDecrypt, EGame.GAME_TonyHawkProSkater12 => THPS12Aes.THPS12Decrypt, _ => Provider.CustomEncryption }; @@ -606,7 +609,7 @@ public class CUE4ParseViewModel : ViewModel case "umap": { var exports = Provider.LoadAllObjects(fullPath); - TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(exports, Formatting.Indented), saveProperties, updateUi); + TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(exports, Formatting.Indented), saveProperties, updateUi); if (HasFlag(bulk, EBulkType.Properties)) break; // do not search for viewable exports if we are dealing with jsons foreach (var e in exports) @@ -684,16 +687,16 @@ public class CUE4ParseViewModel : ViewModel } break; - } - case "bin" when fileName.Contains("GlobalShaderCache"): - { - if (Provider.TryCreateReader(fullPath, out var archive)) - { - var registry = new FGlobalShaderCache(archive); - TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(registry, Formatting.Indented), saveProperties, updateUi); - } - - break; + } + case "bin" when fileName.Contains("GlobalShaderCache", StringComparison.OrdinalIgnoreCase): + { + if (Provider.TryCreateReader(fullPath, out var archive)) + { + var registry = new FGlobalShaderCache(archive); + TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(registry, Formatting.Indented), saveProperties, updateUi); + } + + break; } case "bnk": case "pck": From 0060635e6677ea0aaa8d4c8e804d75261a4cc006 Mon Sep 17 00:00:00 2001 From: Asval Date: Sun, 6 Oct 2024 02:37:04 +0200 Subject: [PATCH 53/65] done? --- FModel/MainWindow.xaml | 14 +- FModel/Settings/UserSettings.cs | 14 ++ .../ApiEndpoints/FModelApiEndpoint.cs | 3 + .../ApiEndpoints/GitHubApiEndpoint.cs | 6 - .../ApiEndpoints/Models/GitHubResponse.cs | 38 +++++ FModel/ViewModels/Commands/RemindMeCommand.cs | 40 +++++ FModel/ViewModels/UpdateViewModel.cs | 17 ++- .../Controls/CommitDownloaderControl.xaml | 16 +- .../Controls/CommitDownloaderControl.xaml.cs | 38 +---- .../Converters/RelativeDateTimeConverter.cs | 3 + FModel/Views/Resources/Resources.xaml | 1 + FModel/Views/UpdateView.xaml | 140 ++++++++++-------- FModel/Views/UpdateView.xaml.cs | 7 + 13 files changed, 214 insertions(+), 123 deletions(-) create mode 100644 FModel/ViewModels/Commands/RemindMeCommand.cs diff --git a/FModel/MainWindow.xaml b/FModel/MainWindow.xaml index d4e261ab..57d1b200 100644 --- a/FModel/MainWindow.xaml +++ b/FModel/MainWindow.xaml @@ -151,13 +151,7 @@ - - - - - - - + @@ -803,13 +797,17 @@ + + + + diff --git a/FModel/Settings/UserSettings.cs b/FModel/Settings/UserSettings.cs index f5f703a1..178abe5a 100644 --- a/FModel/Settings/UserSettings.cs +++ b/FModel/Settings/UserSettings.cs @@ -186,6 +186,20 @@ namespace FModel.Settings set => SetProperty(ref _updateMode, value); } + private DateTime _lastUpdateCheck = DateTime.MinValue; + public DateTime LastUpdateCheck + { + get => _lastUpdateCheck; + set => SetProperty(ref _lastUpdateCheck, value); + } + + private DateTime _nextUpdateCheck = DateTime.Now; + public DateTime NextUpdateCheck + { + get => _nextUpdateCheck; + set => SetProperty(ref _nextUpdateCheck, value); + } + private string _commitHash = Constants.APP_VERSION; public string CommitHash { diff --git a/FModel/ViewModels/ApiEndpoints/FModelApiEndpoint.cs b/FModel/ViewModels/ApiEndpoints/FModelApiEndpoint.cs index 9d0e28ac..494f08e0 100644 --- a/FModel/ViewModels/ApiEndpoints/FModelApiEndpoint.cs +++ b/FModel/ViewModels/ApiEndpoints/FModelApiEndpoint.cs @@ -119,6 +119,8 @@ public class FModelApiEndpoint : AbstractApiProvider public void CheckForUpdates(EUpdateMode updateMode, bool launch = false) { + if (DateTime.Now < UserSettings.Default.NextUpdateCheck) return; + if (launch) { AutoUpdater.ParseUpdateInfoEvent += ParseUpdateInfoEvent; @@ -150,6 +152,7 @@ public class FModelApiEndpoint : AbstractApiProvider { if (args is { CurrentVersion: { } }) { + UserSettings.Default.LastUpdateCheck = DateTime.Now; var qa = (CustomMandatory) args.Mandatory; var currentVersion = new System.Version(args.CurrentVersion); if ((qa.Value && qa.CommitHash == UserSettings.Default.CommitHash) || // qa branch : same commit id diff --git a/FModel/ViewModels/ApiEndpoints/GitHubApiEndpoint.cs b/FModel/ViewModels/ApiEndpoints/GitHubApiEndpoint.cs index 7414a7ca..e6b2761d 100644 --- a/FModel/ViewModels/ApiEndpoints/GitHubApiEndpoint.cs +++ b/FModel/ViewModels/ApiEndpoints/GitHubApiEndpoint.cs @@ -18,9 +18,6 @@ public class GitHubApiEndpoint : AbstractApiProvider request.AddParameter("page", page); request.AddParameter("per_page", limit); var response = await _client.ExecuteAsync(request).ConfigureAwait(false); -#if DEBUG - System.IO.File.WriteAllTextAsync(@"C:\Users\valen\Downloads\history.json", Newtonsoft.Json.JsonConvert.SerializeObject(response.Data)); -#endif return response.Data; } @@ -28,9 +25,6 @@ public class GitHubApiEndpoint : AbstractApiProvider { var request = new FRestRequest($"{Constants.GH_RELEASES}/tags/{tag}"); var response = await _client.ExecuteAsync(request).ConfigureAwait(false); -#if DEBUG - System.IO.File.WriteAllTextAsync(@"C:\Users\valen\Downloads\qa.json", Newtonsoft.Json.JsonConvert.SerializeObject(response.Data)); -#endif return response.Data; } } diff --git a/FModel/ViewModels/ApiEndpoints/Models/GitHubResponse.cs b/FModel/ViewModels/ApiEndpoints/Models/GitHubResponse.cs index b6288897..ddffba50 100644 --- a/FModel/ViewModels/ApiEndpoints/Models/GitHubResponse.cs +++ b/FModel/ViewModels/ApiEndpoints/Models/GitHubResponse.cs @@ -1,6 +1,13 @@ using System; +using System.Windows; +using AdonisUI.Controls; +using AutoUpdaterDotNET; using FModel.Framework; using FModel.Settings; +using MessageBox = AdonisUI.Controls.MessageBox; +using MessageBoxButton = AdonisUI.Controls.MessageBoxButton; +using MessageBoxImage = AdonisUI.Controls.MessageBoxImage; +using MessageBoxResult = AdonisUI.Controls.MessageBoxResult; using J = Newtonsoft.Json.JsonPropertyAttribute; namespace FModel.ViewModels.ApiEndpoints.Models; @@ -58,6 +65,37 @@ public class GitHubCommit : ViewModel public bool IsCurrent => Sha == UserSettings.Default.CommitHash; public string ShortSha => Sha[..7]; public bool IsDownloadable => Asset != null; + + public void Download() + { + if (IsCurrent) return; + + var messageBox = new MessageBoxModel + { + Text = $"Are you sure you want to update to version '{ShortSha}'?{(!Asset.IsLatest ? "\nThis is not the latest version." : "")}", + Caption = "Update FModel", + Icon = MessageBoxImage.Question, + Buttons = MessageBoxButtons.YesNo(), + IsSoundEnabled = false + }; + + MessageBox.Show(messageBox); + if (messageBox.Result != MessageBoxResult.Yes) return; + + try + { + if (AutoUpdater.DownloadUpdate(new UpdateInfoEventArgs { DownloadURL = Asset.BrowserDownloadUrl })) + { + UserSettings.Default.CommitHash = Sha; + Application.Current.Shutdown(); + } + } + catch (Exception exception) + { + UserSettings.Default.ShowChangelog = false; + MessageBox.Show(exception.Message, exception.GetType().ToString(), MessageBoxButton.OK, MessageBoxImage.Error); + } + } } public class Commit diff --git a/FModel/ViewModels/Commands/RemindMeCommand.cs b/FModel/ViewModels/Commands/RemindMeCommand.cs new file mode 100644 index 00000000..7c78a952 --- /dev/null +++ b/FModel/ViewModels/Commands/RemindMeCommand.cs @@ -0,0 +1,40 @@ +using System; +using FModel.Framework; +using FModel.Settings; + +namespace FModel.ViewModels.Commands; + +public class RemindMeCommand : ViewModelCommand +{ + public RemindMeCommand(UpdateViewModel contextViewModel) : base(contextViewModel) + { + } + + public override void Execute(UpdateViewModel contextViewModel, object parameter) + { + switch (parameter) + { + case "Days": + // check for update in 3 days + UserSettings.Default.NextUpdateCheck = DateTime.Now.AddDays(3); + break; + case "Week": + // check for update next week (a week starts on Monday) + var delay = DayOfWeek.Monday - DateTime.Now.DayOfWeek; + UserSettings.Default.NextUpdateCheck = DateTime.Now.AddDays(delay); + break; + case "Month": + // check for update next month (if today is 31st, it will be 1st of next month) + UserSettings.Default.NextUpdateCheck = DateTime.Now.AddDays(1 - DateTime.Now.Day).AddMonths(1); + break; + case "Never": + // never check for updates + UserSettings.Default.NextUpdateCheck = DateTime.MaxValue; + break; + default: + // reset + UserSettings.Default.NextUpdateCheck = DateTime.Now; + break; + } + } +} diff --git a/FModel/ViewModels/UpdateViewModel.cs b/FModel/ViewModels/UpdateViewModel.cs index 64bef9c2..429678e9 100644 --- a/FModel/ViewModels/UpdateViewModel.cs +++ b/FModel/ViewModels/UpdateViewModel.cs @@ -6,6 +6,7 @@ using FModel.Extensions; using FModel.Framework; using FModel.Services; using FModel.ViewModels.ApiEndpoints.Models; +using FModel.ViewModels.Commands; using FModel.Views.Resources.Converters; namespace FModel.ViewModels; @@ -14,6 +15,9 @@ public class UpdateViewModel : ViewModel { private ApiEndpointViewModel _apiEndpointView => ApplicationService.ApiEndpointView; + private RemindMeCommand _remindMeCommand; + public RemindMeCommand RemindMeCommand => _remindMeCommand ??= new RemindMeCommand(this); + public RangeObservableCollection Commits { get; } public ICollectionView CommitsView { get; } @@ -28,15 +32,11 @@ public class UpdateViewModel : ViewModel public async Task Load() { -#if DEBUG - Commits.AddRange(Newtonsoft.Json.JsonConvert.DeserializeObject(await System.IO.File.ReadAllTextAsync(@"C:\Users\valen\Downloads\history.json"))); - var qa = Newtonsoft.Json.JsonConvert.DeserializeObject(await System.IO.File.ReadAllTextAsync(@"C:\Users\valen\Downloads\qa.json")); -#else Commits.AddRange(await _apiEndpointView.GitHubApi.GetCommitHistoryAsync()); - var qa = await _apiEndpointView.GitHubApi.GetReleaseAsync("qa"); -#endif + var qa = await _apiEndpointView.GitHubApi.GetReleaseAsync("qa"); qa.Assets.OrderByDescending(x => x.CreatedAt).First().IsLatest = true; + foreach (var asset in qa.Assets) { var commitSha = asset.Name.SubstringBeforeLast(".zip"); @@ -47,4 +47,9 @@ public class UpdateViewModel : ViewModel } } } + + public void DownloadLatest() + { + Commits.FirstOrDefault(x => x.Asset.IsLatest)?.Download(); + } } diff --git a/FModel/Views/Resources/Controls/CommitDownloaderControl.xaml b/FModel/Views/Resources/Controls/CommitDownloaderControl.xaml index 57faa1ed..256ce0a4 100644 --- a/FModel/Views/Resources/Controls/CommitDownloaderControl.xaml +++ b/FModel/Views/Resources/Controls/CommitDownloaderControl.xaml @@ -29,12 +29,12 @@ @@ -44,16 +44,16 @@ diff --git a/FModel/Views/Resources/Controls/CommitDownloaderControl.xaml.cs b/FModel/Views/Resources/Controls/CommitDownloaderControl.xaml.cs index 89464610..b779543a 100644 --- a/FModel/Views/Resources/Controls/CommitDownloaderControl.xaml.cs +++ b/FModel/Views/Resources/Controls/CommitDownloaderControl.xaml.cs @@ -1,14 +1,6 @@ -using System; -using System.Windows; +using System.Windows; using System.Windows.Controls; -using AdonisUI.Controls; -using AutoUpdaterDotNET; -using FModel.Settings; using FModel.ViewModels.ApiEndpoints.Models; -using MessageBox = AdonisUI.Controls.MessageBox; -using MessageBoxButton = AdonisUI.Controls.MessageBoxButton; -using MessageBoxImage = AdonisUI.Controls.MessageBoxImage; -using MessageBoxResult = AdonisUI.Controls.MessageBoxResult; namespace FModel.Views.Resources.Controls; @@ -30,33 +22,7 @@ public partial class CommitDownloaderControl : UserControl private void OnDownload(object sender, RoutedEventArgs e) { - if (Commit.IsCurrent) return; - - var messageBox = new MessageBoxModel - { - Text = $"Are you sure you want to update to version '{Commit.ShortSha}'?{(!Commit.Asset.IsLatest ? "\nThis is not the latest version." : "")}", - Caption = "Update FModel", - Icon = MessageBoxImage.Question, - Buttons = MessageBoxButtons.YesNo(), - IsSoundEnabled = false - }; - - MessageBox.Show(messageBox); - if (messageBox.Result != MessageBoxResult.Yes) return; - - try - { - if (AutoUpdater.DownloadUpdate(new UpdateInfoEventArgs { DownloadURL = Commit.Asset.BrowserDownloadUrl })) - { - UserSettings.Default.CommitHash = Commit.Sha; - Application.Current.Shutdown(); - } - } - catch (Exception exception) - { - UserSettings.Default.ShowChangelog = false; - MessageBox.Show(exception.Message, exception.GetType().ToString(), MessageBoxButton.OK, MessageBoxImage.Error); - } + Commit.Download(); } } diff --git a/FModel/Views/Resources/Converters/RelativeDateTimeConverter.cs b/FModel/Views/Resources/Converters/RelativeDateTimeConverter.cs index 177e22f1..ac9aaa34 100644 --- a/FModel/Views/Resources/Converters/RelativeDateTimeConverter.cs +++ b/FModel/Views/Resources/Converters/RelativeDateTimeConverter.cs @@ -16,6 +16,9 @@ public class RelativeDateTimeConverter : IValueConverter int time; string unit; + if (timeSpan.TotalSeconds < 30) + return "Just now"; + if (timeSpan.TotalMinutes < 1) { time = timeSpan.Seconds; diff --git a/FModel/Views/Resources/Resources.xaml b/FModel/Views/Resources/Resources.xaml index d560ab09..03e061d9 100644 --- a/FModel/Views/Resources/Resources.xaml +++ b/FModel/Views/Resources/Resources.xaml @@ -69,6 +69,7 @@ M11.71,17.99C8.53,17.84,6,15.22,6,12c0-3.31,2.69-6,6-6c3.22,0,5.84,2.53,5.99,5.71l-2.1-0.63C15.48,9.31,13.89,8,12,8 c-2.21,0-4,1.79-4,4c0,1.89,1.31,3.48,3.08,3.89L11.71,17.99z M22,12c0,0.3-0.01,0.6-0.04,0.9l-1.97-0.59C20,12.21,20,12.1,20,12 c0-4.42-3.58-8-8-8s-8,3.58-8,8s3.58,8,8,8c0.1,0,0.21,0,0.31-0.01l0.59,1.97C12.6,21.99,12.3,22,12,22C6.48,22,2,17.52,2,12 C2,6.48,6.48,2,12,2S22,6.48,22,12z M18.23,16.26l2.27-0.76c0.46-0.15,0.45-0.81-0.01-0.95l-7.6-2.28 c-0.38-0.11-0.74,0.24-0.62,0.62l2.28,7.6c0.14,0.47,0.8,0.48,0.95,0.01l0.76-2.27l3.91,3.91c0.2,0.2,0.51,0.2,0.71,0l1.27-1.27 c0.2-0.2,0.2-0.51,0-0.71L18.23,16.26z M1.8 6q-.525 0-.887-.35Q.55 5.3.55 4.8V4q0-1.425 1.012-2.438Q2.575.55 4 .55h.8q.5 0 .85.362.35.363.35.888 0 .5-.35.85T4.8 3H4q-.425 0-.712.287Q3 3.575 3 4v.8q0 .5-.35.85T1.8 6ZM4 23.45q-1.425 0-2.438-1.012Q.55 21.425.55 20v-.8q0-.5.363-.85.362-.35.887-.35.5 0 .85.35t.35.85v.8q0 .425.288.712Q3.575 21 4 21h.8q.5 0 .85.35t.35.85q0 .525-.35.887-.35.363-.85.363Zm15.2 0q-.5 0-.85-.363-.35-.362-.35-.887 0-.5.35-.85t.85-.35h.8q.425 0 .712-.288Q21 20.425 21 20v-.8q0-.5.35-.85t.85-.35q.525 0 .888.35.362.35.362.85v.8q0 1.425-1.012 2.438Q21.425 23.45 20 23.45ZM22.2 6q-.5 0-.85-.35T21 4.8V4q0-.425-.288-.713Q20.425 3 20 3h-.8q-.5 0-.85-.35T18 1.8q0-.525.35-.888.35-.362.85-.362h.8q1.425 0 2.438 1.012Q23.45 2.575 23.45 4v.8q0 .5-.362.85-.363.35-.888.35ZM12 17.35l1-.575v-4.1l3.55-2.075V9.425l-1-.575L12 10.925 8.45 8.85l-1 .575V10.6L11 12.675v4.1Zm-1.325 2.325-4.55-2.65q-.625-.35-.975-.963-.35-.612-.35-1.337V9.45q0-.725.35-1.337.35-.613.975-.963l4.55-2.65Q11.3 4.15 12 4.15t1.325.35l4.55 2.65q.625.35.975.963.35.612.35 1.337v5.275q0 .725-.35 1.337-.35.613-.975.963l-4.55 2.65q-.625.35-1.325.35t-1.325-.35Z M3.5 1.75v11.5c0 .09.048.173.126.217a.75.75 0 0 1-.752 1.298A1.748 1.748 0 0 1 2 13.25V1.75C2 .784 2.784 0 3.75 0h5.586c.464 0 .909.185 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v8.586A1.75 1.75 0 0 1 12.25 15h-.5a.75.75 0 0 1 0-1.5h.5a.25.25 0 0 0 .25-.25V4.664a.25.25 0 0 0-.073-.177L9.513 1.573a.25.25 0 0 0-.177-.073H7.25a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1 0-1.5h-3a.25.25 0 0 0-.25.25Zm3.75 8.75h.5c.966 0 1.75.784 1.75 1.75v3a.75.75 0 0 1-.75.75h-2.5a.75.75 0 0 1-.75-.75v-3c0-.966.784-1.75 1.75-1.75ZM6 5.25a.75.75 0 0 1 .75-.75h.5a.75.75 0 0 1 0 1.5h-.5A.75.75 0 0 1 6 5.25Zm.75 2.25h.5a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1 0-1.5ZM8 6.75A.75.75 0 0 1 8.75 6h.5a.75.75 0 0 1 0 1.5h-.5A.75.75 0 0 1 8 6.75ZM8.75 3h.5a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1 0-1.5ZM8 9.75A.75.75 0 0 1 8.75 9h.5a.75.75 0 0 1 0 1.5h-.5A.75.75 0 0 1 8 9.75Zm-1 2.5v2.25h1v-2.25a.25.25 0 0 0-.25-.25h-.5a.25.25 0 0 0-.25.25Z + M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z - + - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FModel/Views/UpdateView.xaml.cs b/FModel/Views/UpdateView.xaml.cs index a1c284a4..3b9ca455 100644 --- a/FModel/Views/UpdateView.xaml.cs +++ b/FModel/Views/UpdateView.xaml.cs @@ -1,5 +1,6 @@ using System.Windows; using FModel.ViewModels; +using FModel.Views.Resources.Controls; namespace FModel.Views; @@ -16,5 +17,11 @@ public partial class UpdateView if (DataContext is not UpdateViewModel viewModel) return; await viewModel.Load(); } + + private void OnDownloadLatest(object sender, RoutedEventArgs e) + { + if (DataContext is not UpdateViewModel viewModel) return; + viewModel.DownloadLatest(); + } } From 784704b64539fecbe8488847a7c681fd3779cc0c Mon Sep 17 00:00:00 2001 From: Asval Date: Sun, 6 Oct 2024 03:13:03 +0200 Subject: [PATCH 54/65] add past 20 commits releases just in case --- .../ApiEndpoints/FModelApiEndpoint.cs | 1 + .../ApiEndpoints/Models/GitHubResponse.cs | 6 ++++-- FModel/ViewModels/UpdateViewModel.cs | 14 +++++++++++++ FModel/Views/UpdateView.xaml | 20 +++++++++---------- 4 files changed, 29 insertions(+), 12 deletions(-) diff --git a/FModel/ViewModels/ApiEndpoints/FModelApiEndpoint.cs b/FModel/ViewModels/ApiEndpoints/FModelApiEndpoint.cs index 494f08e0..b87911e0 100644 --- a/FModel/ViewModels/ApiEndpoints/FModelApiEndpoint.cs +++ b/FModel/ViewModels/ApiEndpoints/FModelApiEndpoint.cs @@ -153,6 +153,7 @@ public class FModelApiEndpoint : AbstractApiProvider if (args is { CurrentVersion: { } }) { UserSettings.Default.LastUpdateCheck = DateTime.Now; + var qa = (CustomMandatory) args.Mandatory; var currentVersion = new System.Version(args.CurrentVersion); if ((qa.Value && qa.CommitHash == UserSettings.Default.CommitHash) || // qa branch : same commit id diff --git a/FModel/ViewModels/ApiEndpoints/Models/GitHubResponse.cs b/FModel/ViewModels/ApiEndpoints/Models/GitHubResponse.cs index ddffba50..85c15e17 100644 --- a/FModel/ViewModels/ApiEndpoints/Models/GitHubResponse.cs +++ b/FModel/ViewModels/ApiEndpoints/Models/GitHubResponse.cs @@ -24,6 +24,7 @@ public class GitHubAsset : ViewModel [J("download_count")] public int DownloadCount { get; private set; } [J("browser_download_url")] public string BrowserDownloadUrl { get; private set; } [J("created_at")] public DateTime CreatedAt { get; private set; } + [J("uploader")] public Author Uploader { get; private set; } private bool _isLatest; public bool IsLatest @@ -48,8 +49,8 @@ public class GitHubCommit : ViewModel } } - [J("commit")] public Commit Commit { get; private set; } - [J("author")] public Author Author { get; private set; } + [J("commit")] public Commit Commit { get; set; } + [J("author")] public Author Author { get; set; } private GitHubAsset _asset; public GitHubAsset Asset @@ -107,6 +108,7 @@ public class Commit public class Author { [J("name")] public string Name { get; set; } + [J("login")] public string Login { get; set; } [J("date")] public DateTime Date { get; set; } [J("avatar_url")] public string AvatarUrl { get; set; } [J("html_url")] public string HtmlUrl { get; set; } diff --git a/FModel/ViewModels/UpdateViewModel.cs b/FModel/ViewModels/UpdateViewModel.cs index 429678e9..96d0a49f 100644 --- a/FModel/ViewModels/UpdateViewModel.cs +++ b/FModel/ViewModels/UpdateViewModel.cs @@ -45,6 +45,20 @@ public class UpdateViewModel : ViewModel { commit.Asset = asset; } + else + { + Commits.Add(new GitHubCommit + { + Sha = commitSha, + Commit = new Commit + { + Message = "No commit message", + Author = new Author { Name = asset.Uploader.Login, Date = asset.CreatedAt } + }, + Author = asset.Uploader, + Asset = asset + }); + } } } diff --git a/FModel/Views/UpdateView.xaml b/FModel/Views/UpdateView.xaml index 6a1f5165..6d378592 100644 --- a/FModel/Views/UpdateView.xaml +++ b/FModel/Views/UpdateView.xaml @@ -42,16 +42,16 @@ - - - + + + + + + + + + +