mirror of
https://github.com/4sval/FModel.git
synced 2026-03-21 17:24:26 -05:00
Merge pull request #503 from 4sval/no-update-modes
Some checks failed
FModel QA Builder / build (push) Has been cancelled
Some checks failed
FModel QA Builder / build (push) Has been cancelled
No update modes
This commit is contained in:
commit
7fda6bc3b8
|
|
@ -106,7 +106,7 @@ public partial class App
|
|||
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss} [FModel] [{Level:u3}] {Message:lj}{NewLine}{Exception}").CreateLogger();
|
||||
#endif
|
||||
|
||||
Log.Information("Version {Version}", Constants.APP_VERSION);
|
||||
Log.Information("Version {Version} ({CommitId})", Constants.APP_VERSION, Constants.APP_COMMIT_ID);
|
||||
Log.Information("{OS}", GetOperatingSystemProductName());
|
||||
Log.Information("{RuntimeVer}", RuntimeInformation.FrameworkDescription);
|
||||
Log.Information("Culture {SysLang}", CultureInfo.CurrentCulture);
|
||||
|
|
|
|||
|
|
@ -1,12 +1,20 @@
|
|||
using System.Numerics;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Numerics;
|
||||
using System.Reflection;
|
||||
using CUE4Parse.UE4.Objects.Core.Misc;
|
||||
using FModel.Extensions;
|
||||
|
||||
namespace FModel;
|
||||
|
||||
public static class Constants
|
||||
{
|
||||
public static readonly string APP_VERSION = Assembly.GetExecutingAssembly().GetName().Version?.ToString();
|
||||
public static readonly string APP_PATH = Path.GetFullPath(Environment.GetCommandLineArgs()[0]);
|
||||
public static readonly string APP_VERSION = FileVersionInfo.GetVersionInfo(APP_PATH).FileVersion;
|
||||
public static readonly string APP_COMMIT_ID = FileVersionInfo.GetVersionInfo(APP_PATH).ProductVersion.SubstringAfter('+');
|
||||
public static readonly string APP_SHORT_COMMIT_ID = APP_COMMIT_ID[..7];
|
||||
|
||||
public const string ZERO_64_CHAR = "0000000000000000000000000000000000000000000000000000000000000000";
|
||||
public static readonly FGuid ZERO_GUID = new(0U);
|
||||
|
||||
|
|
@ -21,6 +29,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 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";
|
||||
|
||||
|
|
|
|||
|
|
@ -147,11 +147,11 @@
|
|||
</Viewbox>
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem Header="Changelog" Command="{Binding MenuCommand}" CommandParameter="Help_Changelog">
|
||||
<MenuItem Header="Releases" Command="{Binding MenuCommand}" CommandParameter="Help_Releases">
|
||||
<MenuItem.Icon>
|
||||
<Viewbox Width="16" Height="16">
|
||||
<Canvas Width="24" Height="24">
|
||||
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.AccentForegroundBrush}}" Data="{StaticResource NoteIcon}" />
|
||||
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.AccentForegroundBrush}}" Data="{StaticResource GitHubIcon}" />
|
||||
</Canvas>
|
||||
</Viewbox>
|
||||
</MenuItem.Icon>
|
||||
|
|
@ -797,13 +797,17 @@
|
|||
<Style TargetType="StatusBarItem">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsAutoOpenSounds, Source={x:Static settings:UserSettings.Default}}" Value="False">
|
||||
<Setter Property="Visibility" Value="Hidden" />
|
||||
<Setter Property="Visibility" Value="Collapsed" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</StatusBarItem.Style>
|
||||
<TextBlock HorizontalAlignment="Center" FontWeight="SemiBold" Text="SND" />
|
||||
</StatusBarItem>
|
||||
|
||||
<StatusBarItem Margin="10 0 0 0">
|
||||
<TextBlock Text="{Binding LastUpdateCheck, Source={x:Static local:Settings.UserSettings.Default}, Converter={x:Static converters:RelativeDateTimeConverter.Instance}, StringFormat=Last Refresh: {0}}" />
|
||||
</StatusBarItem>
|
||||
</StackPanel>
|
||||
</StatusBarItem>
|
||||
</StatusBar>
|
||||
|
|
|
|||
|
|
@ -186,11 +186,18 @@ namespace FModel.Settings
|
|||
set => SetProperty(ref _updateMode, value);
|
||||
}
|
||||
|
||||
private string _commitHash = Constants.APP_VERSION;
|
||||
public string CommitHash
|
||||
private DateTime _lastUpdateCheck = DateTime.MinValue;
|
||||
public DateTime LastUpdateCheck
|
||||
{
|
||||
get => _commitHash;
|
||||
set => SetProperty(ref _commitHash, value);
|
||||
get => _lastUpdateCheck;
|
||||
set => SetProperty(ref _lastUpdateCheck, value);
|
||||
}
|
||||
|
||||
private DateTime _nextUpdateCheck = DateTime.Now;
|
||||
public DateTime NextUpdateCheck
|
||||
{
|
||||
get => _nextUpdateCheck;
|
||||
set => SetProperty(ref _nextUpdateCheck, value);
|
||||
}
|
||||
|
||||
private bool _keepDirectoryStructure = true;
|
||||
|
|
@ -265,8 +272,6 @@ namespace FModel.Settings
|
|||
|
||||
[JsonIgnore]
|
||||
public DirectorySettings CurrentDir { get; set; }
|
||||
[JsonIgnore]
|
||||
public string ShortCommitHash => CommitHash[..7];
|
||||
|
||||
/// <summary>
|
||||
/// TO DELETEEEEEEEEEEEEE
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ public class ApiEndpointViewModel
|
|||
public FortniteCentralApiEndpoint CentralApi { get; }
|
||||
public EpicApiEndpoint EpicApi { get; }
|
||||
public FModelApiEndpoint FModelApi { get; }
|
||||
public GitHubApiEndpoint GitHubApi { get; }
|
||||
public DynamicApiEndpoint DynamicApi { get; }
|
||||
|
||||
public ApiEndpointViewModel()
|
||||
|
|
@ -29,6 +30,7 @@ public class ApiEndpointViewModel
|
|||
CentralApi = new FortniteCentralApiEndpoint(_client);
|
||||
EpicApi = new EpicApiEndpoint(_client);
|
||||
FModelApi = new FModelApiEndpoint(_client);
|
||||
GitHubApi = new GitHubApiEndpoint(_client);
|
||||
DynamicApi = new DynamicApiEndpoint(_client);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ using FModel.Framework;
|
|||
using FModel.Services;
|
||||
using FModel.Settings;
|
||||
using FModel.ViewModels.ApiEndpoints.Models;
|
||||
using FModel.Views;
|
||||
using Newtonsoft.Json;
|
||||
using RestSharp;
|
||||
using Serilog;
|
||||
|
|
@ -118,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;
|
||||
|
|
@ -149,43 +152,20 @@ 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
|
||||
(!qa.Value && currentVersion == args.InstalledVersion && args.CurrentVersion == UserSettings.Default.CommitHash)) // stable - beta branch : same version + commit id = version
|
||||
if ((qa.Value && qa.CommitHash == Constants.APP_COMMIT_ID) || // qa branch : same commit id
|
||||
(!qa.Value && currentVersion == args.InstalledVersion)) // stable - beta branch : same version + commit id = version
|
||||
{
|
||||
if (UserSettings.Default.ShowChangelog)
|
||||
ShowChangelog(args);
|
||||
return;
|
||||
}
|
||||
|
||||
var downgrade = currentVersion < args.InstalledVersion;
|
||||
var messageBox = new MessageBoxModel
|
||||
{
|
||||
Text = $"The latest version of FModel {UserSettings.Default.UpdateMode.GetDescription()} is {(qa.Value ? qa.ShortCommitHash : args.CurrentVersion)}. You are using version {(qa.Value ? UserSettings.Default.ShortCommitHash : args.InstalledVersion)}. Do you want to {(downgrade ? "downgrade" : "update")} the application now?",
|
||||
Caption = $"{(downgrade ? "Downgrade" : "Update")} Available",
|
||||
Icon = MessageBoxImage.Question,
|
||||
Buttons = MessageBoxButtons.YesNo(),
|
||||
IsSoundEnabled = false
|
||||
};
|
||||
|
||||
MessageBox.Show(messageBox);
|
||||
if (messageBox.Result != MessageBoxResult.Yes) return;
|
||||
|
||||
try
|
||||
{
|
||||
if (AutoUpdater.DownloadUpdate(args))
|
||||
{
|
||||
UserSettings.Default.ShowChangelog = currentVersion != args.InstalledVersion;
|
||||
UserSettings.Default.CommitHash = qa.CommitHash;
|
||||
Application.Current.Shutdown();
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
UserSettings.Default.ShowChangelog = false;
|
||||
MessageBox.Show(exception.Message, exception.GetType().ToString(), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
const string message = "A new update is available!";
|
||||
Helper.OpenWindow<AdonisWindow>(message, () => new UpdateView { Title = message, ResizeMode = ResizeMode.NoResize }.ShowDialog());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
30
FModel/ViewModels/ApiEndpoints/GitHubApiEndpoint.cs
Normal file
30
FModel/ViewModels/ApiEndpoints/GitHubApiEndpoint.cs
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
using System.Threading.Tasks;
|
||||
using FModel.Framework;
|
||||
using FModel.ViewModels.ApiEndpoints.Models;
|
||||
using RestSharp;
|
||||
|
||||
namespace FModel.ViewModels.ApiEndpoints;
|
||||
|
||||
public class GitHubApiEndpoint : AbstractApiProvider
|
||||
{
|
||||
private GitHubCommit[] _commits;
|
||||
|
||||
public GitHubApiEndpoint(RestClient client) : base(client) { }
|
||||
|
||||
public async Task<GitHubCommit[]> GetCommitHistoryAsync(string branch = "dev", int page = 1, int limit = 20)
|
||||
{
|
||||
var request = new FRestRequest(Constants.GH_COMMITS_HISTORY);
|
||||
request.AddParameter("sha", branch);
|
||||
request.AddParameter("page", page);
|
||||
request.AddParameter("per_page", limit);
|
||||
var response = await _client.ExecuteAsync<GitHubCommit[]>(request).ConfigureAwait(false);
|
||||
return response.Data;
|
||||
}
|
||||
|
||||
public async Task<GitHubRelease> GetReleaseAsync(string tag)
|
||||
{
|
||||
var request = new FRestRequest($"{Constants.GH_RELEASES}/tags/{tag}");
|
||||
var response = await _client.ExecuteAsync<GitHubRelease>(request).ConfigureAwait(false);
|
||||
return response.Data;
|
||||
}
|
||||
}
|
||||
125
FModel/ViewModels/ApiEndpoints/Models/GitHubResponse.cs
Normal file
125
FModel/ViewModels/ApiEndpoints/Models/GitHubResponse.cs
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
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;
|
||||
|
||||
public class GitHubRelease
|
||||
{
|
||||
[J("assets")] public GitHubAsset[] Assets { get; private set; }
|
||||
}
|
||||
|
||||
public class GitHubAsset : ViewModel
|
||||
{
|
||||
[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; }
|
||||
[J("created_at")] public DateTime CreatedAt { get; private set; }
|
||||
[J("uploader")] public Author Uploader { get; private set; }
|
||||
|
||||
private bool _isLatest;
|
||||
public bool IsLatest
|
||||
{
|
||||
get => _isLatest;
|
||||
set => SetProperty(ref _isLatest, value);
|
||||
}
|
||||
}
|
||||
|
||||
public class GitHubCommit : ViewModel
|
||||
{
|
||||
private string _sha;
|
||||
[J("sha")]
|
||||
public string Sha
|
||||
{
|
||||
get => _sha;
|
||||
set
|
||||
{
|
||||
SetProperty(ref _sha, value);
|
||||
RaisePropertyChanged(nameof(IsCurrent));
|
||||
RaisePropertyChanged(nameof(ShortSha));
|
||||
}
|
||||
}
|
||||
|
||||
[J("commit")] public Commit Commit { get; set; }
|
||||
[J("author")] public Author Author { get; set; }
|
||||
|
||||
private GitHubAsset _asset;
|
||||
public GitHubAsset Asset
|
||||
{
|
||||
get => _asset;
|
||||
set
|
||||
{
|
||||
SetProperty(ref _asset, value);
|
||||
RaisePropertyChanged(nameof(IsDownloadable));
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsCurrent => Sha == Constants.APP_COMMIT_ID;
|
||||
public string ShortSha => Sha[..7];
|
||||
public bool IsDownloadable => Asset != null;
|
||||
|
||||
public void Download()
|
||||
{
|
||||
if (IsCurrent)
|
||||
{
|
||||
MessageBox.Show(new MessageBoxModel
|
||||
{
|
||||
Text = "You are already on the latest version.",
|
||||
Caption = "Update FModel",
|
||||
Icon = MessageBoxImage.Information,
|
||||
Buttons = [MessageBoxButtons.Ok()],
|
||||
IsSoundEnabled = false
|
||||
});
|
||||
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 }))
|
||||
{
|
||||
Application.Current.Shutdown();
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
UserSettings.Default.ShowChangelog = false;
|
||||
MessageBox.Show(exception.Message, exception.GetType().ToString(), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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("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; }
|
||||
}
|
||||
|
|
@ -10,7 +10,6 @@ using CUE4Parse.Compression;
|
|||
using CUE4Parse.Encryption.Aes;
|
||||
using CUE4Parse.UE4.Objects.Core.Misc;
|
||||
using CUE4Parse.UE4.VirtualFileSystem;
|
||||
using FModel.Extensions;
|
||||
using FModel.Framework;
|
||||
using FModel.Services;
|
||||
using FModel.Settings;
|
||||
|
|
@ -50,7 +49,7 @@ public class ApplicationViewModel : ViewModel
|
|||
public CopyCommand CopyCommand => _copyCommand ??= new CopyCommand(this);
|
||||
private CopyCommand _copyCommand;
|
||||
|
||||
public string InitialWindowTitle => $"FModel {UserSettings.Default.UpdateMode.GetDescription()}";
|
||||
public string InitialWindowTitle => $"FModel ({Constants.APP_SHORT_COMMIT_ID})";
|
||||
public string GameDisplayName => CUE4Parse.Provider.GameDisplayName ?? "Unknown";
|
||||
public string TitleExtra => $"({UserSettings.Default.CurrentDir.UeVersion}){(Build != EBuildKind.Release ? $" ({Build})" : "")}";
|
||||
|
||||
|
|
@ -144,7 +143,7 @@ public class ApplicationViewModel : ViewModel
|
|||
StartInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = "dotnet",
|
||||
Arguments = $"\"{Path.GetFullPath(Environment.GetCommandLineArgs()[0])}\"",
|
||||
Arguments = $"\"{path}\"",
|
||||
UseShellExecute = false,
|
||||
RedirectStandardOutput = false,
|
||||
RedirectStandardError = false,
|
||||
|
|
|
|||
|
|
@ -54,9 +54,8 @@ public class MenuCommand : ViewModelCommand<ApplicationViewModel>
|
|||
case "Help_Donate":
|
||||
Process.Start(new ProcessStartInfo { FileName = Constants.DONATE_LINK, UseShellExecute = true });
|
||||
break;
|
||||
case "Help_Changelog":
|
||||
UserSettings.Default.ShowChangelog = true;
|
||||
ApplicationService.ApiEndpointView.FModelApi.CheckForUpdates(UserSettings.Default.UpdateMode);
|
||||
case "Help_Releases":
|
||||
Helper.OpenWindow<AdonisWindow>("Releases", () => new UpdateView().Show());
|
||||
break;
|
||||
case "Help_BugsReport":
|
||||
Process.Start(new ProcessStartInfo { FileName = Constants.ISSUE_LINK, UseShellExecute = true });
|
||||
|
|
|
|||
40
FModel/ViewModels/Commands/RemindMeCommand.cs
Normal file
40
FModel/ViewModels/Commands/RemindMeCommand.cs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
using System;
|
||||
using FModel.Framework;
|
||||
using FModel.Settings;
|
||||
|
||||
namespace FModel.ViewModels.Commands;
|
||||
|
||||
public class RemindMeCommand : ViewModelCommand<UpdateViewModel>
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
74
FModel/ViewModels/UpdateViewModel.cs
Normal file
74
FModel/ViewModels/UpdateViewModel.cs
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Data;
|
||||
using FModel.Extensions;
|
||||
using FModel.Framework;
|
||||
using FModel.Services;
|
||||
using FModel.Settings;
|
||||
using FModel.ViewModels.ApiEndpoints.Models;
|
||||
using FModel.ViewModels.Commands;
|
||||
using FModel.Views.Resources.Converters;
|
||||
|
||||
namespace FModel.ViewModels;
|
||||
|
||||
public class UpdateViewModel : ViewModel
|
||||
{
|
||||
private ApiEndpointViewModel _apiEndpointView => ApplicationService.ApiEndpointView;
|
||||
|
||||
private RemindMeCommand _remindMeCommand;
|
||||
public RemindMeCommand RemindMeCommand => _remindMeCommand ??= new RemindMeCommand(this);
|
||||
|
||||
public RangeObservableCollection<GitHubCommit> Commits { get; }
|
||||
public ICollectionView CommitsView { get; }
|
||||
|
||||
public UpdateViewModel()
|
||||
{
|
||||
Commits = new RangeObservableCollection<GitHubCommit>();
|
||||
CommitsView = new ListCollectionView(Commits)
|
||||
{
|
||||
GroupDescriptions = { new PropertyGroupDescription("Commit.Author.Date", new DateTimeToDateConverter()) }
|
||||
};
|
||||
|
||||
if (UserSettings.Default.NextUpdateCheck < DateTime.Now)
|
||||
RemindMeCommand.Execute(this, null);
|
||||
}
|
||||
|
||||
public async Task Load()
|
||||
{
|
||||
Commits.AddRange(await _apiEndpointView.GitHubApi.GetCommitHistoryAsync());
|
||||
|
||||
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");
|
||||
var commit = Commits.FirstOrDefault(x => x.Sha == commitSha);
|
||||
if (commit != null)
|
||||
{
|
||||
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
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void DownloadLatest()
|
||||
{
|
||||
Commits.FirstOrDefault(x => x.Asset.IsLatest)?.Download();
|
||||
}
|
||||
}
|
||||
83
FModel/Views/Resources/Controls/CommitControl.xaml
Normal file
83
FModel/Views/Resources/Controls/CommitControl.xaml
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
<UserControl x:Class="FModel.Views.Resources.Controls.CommitControl"
|
||||
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:controls="clr-namespace:FModel.Views.Resources.Controls">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="../Resources.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<Border BorderThickness="1" CornerRadius="0.5"
|
||||
BorderBrush="{DynamicResource {x:Static adonisUi:Brushes.Layer4BackgroundBrush}}">
|
||||
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Grid Grid.Column="0" Margin="5">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="5" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock Grid.Row="0" Text="{Binding Commit.Message, Converter={x:Static converters:CommitMessageConverter.Instance}, ConverterParameter=Title}" FontWeight="Bold" />
|
||||
<TextBlock Grid.Row="1" Text="{Binding Commit.Message, Converter={x:Static converters:CommitMessageConverter.Instance}, ConverterParameter=Description}" TextWrapping="Wrap">
|
||||
<TextBlock.Style>
|
||||
<Style TargetType="TextBlock">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Commit.Message, Converter={x:Static converters:CommitMessageConverter.Instance}, ConverterParameter=Description}" Value="">
|
||||
<Setter Property="Visibility" Value="Collapsed"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TextBlock.Style>
|
||||
</TextBlock>
|
||||
|
||||
<Grid Grid.Row="3">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="16"/>
|
||||
<ColumnDefinition Width="5"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="5"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Ellipse Grid.Column="0">
|
||||
<Ellipse.Fill>
|
||||
<ImageBrush ImageSource="{Binding Author.AvatarUrl}" />
|
||||
</Ellipse.Fill>
|
||||
</Ellipse>
|
||||
<TextBlock Grid.Column="2" FontSize="11">
|
||||
<TextBlock.Text>
|
||||
<MultiBinding StringFormat="{}{0} committed {1}">
|
||||
<Binding Path="Commit.Author.Name" />
|
||||
<Binding Path="Commit.Author.Date" Converter="{x:Static converters:RelativeDateTimeConverter.Instance}" />
|
||||
</MultiBinding>
|
||||
</TextBlock.Text>
|
||||
</TextBlock>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<controls:CommitDownloaderControl Grid.Column="1" Commit="{Binding}">
|
||||
<controls:CommitDownloaderControl.Style>
|
||||
<Style TargetType="controls:CommitDownloaderControl">
|
||||
<Setter Property="Visibility" Value="Collapsed" />
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsDownloadable}" Value="True">
|
||||
<Setter Property="Visibility" Value="Visible"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</controls:CommitDownloaderControl.Style>
|
||||
</controls:CommitDownloaderControl>
|
||||
</Grid>
|
||||
</Border>
|
||||
</UserControl>
|
||||
|
||||
12
FModel/Views/Resources/Controls/CommitControl.xaml.cs
Normal file
12
FModel/Views/Resources/Controls/CommitControl.xaml.cs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
using System.Windows.Controls;
|
||||
|
||||
namespace FModel.Views.Resources.Controls;
|
||||
|
||||
public partial class CommitControl : UserControl
|
||||
{
|
||||
public CommitControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
|
||||
97
FModel/Views/Resources/Controls/CommitDownloaderControl.xaml
Normal file
97
FModel/Views/Resources/Controls/CommitDownloaderControl.xaml
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
<UserControl x:Class="FModel.Views.Resources.Controls.CommitDownloaderControl"
|
||||
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">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="../Resources.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="15" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="15" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Border Grid.Column="0"
|
||||
BorderThickness="1"
|
||||
CornerRadius="2.5"
|
||||
Padding="5,2"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center">
|
||||
<TextBlock FontSize="9" Foreground="{Binding BorderBrush, RelativeSource={RelativeSource AncestorType=Border}}">
|
||||
<TextBlock.Style>
|
||||
<Style TargetType="TextBlock">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Asset.IsLatest}" Value="True">
|
||||
<Setter Property="Text" Value="Latest" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding IsCurrent}" Value="True">
|
||||
<Setter Property="Text" Value="Current" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TextBlock.Style>
|
||||
</TextBlock>
|
||||
|
||||
<Border.Style>
|
||||
<Style TargetType="Border">
|
||||
<Setter Property="Visibility" Value="Collapsed" />
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Asset.IsLatest}" Value="True">
|
||||
<Setter Property="Visibility" Value="Visible" />
|
||||
<Setter Property="BorderBrush" Value="#3fb950" />
|
||||
<Setter Property="Background" Value="#0f3fb950" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding IsCurrent}" Value="True">
|
||||
<Setter Property="Visibility" Value="Visible" />
|
||||
<Setter Property="BorderBrush" Value="#3f92b9" />
|
||||
<Setter Property="Background" Value="#0f3f92b9" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Border.Style>
|
||||
</Border>
|
||||
|
||||
<Grid Grid.Column="2" HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="5" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Viewbox Grid.Column="0" Width="16" Height="16" VerticalAlignment="Center" HorizontalAlignment="Center">
|
||||
<Canvas Width="16" Height="16">
|
||||
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.DisabledForegroundBrush}}"
|
||||
Data="{StaticResource ArchiveIcon}" />
|
||||
</Canvas>
|
||||
</Viewbox>
|
||||
<StackPanel Grid.Column="2">
|
||||
<TextBlock Text="Size" FontSize="10" />
|
||||
<TextBlock FontSize="10" Text="{Binding Asset.Size, Converter={x:Static converters:SizeToStringConverter.Instance}}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<Button Grid.Column="4" Style="{DynamicResource {x:Static adonisUi:Styles.ToolbarButton}}" ToolTip="Download"
|
||||
Height="{Binding ActualHeight, RelativeSource={RelativeSource AncestorType=Grid}}"
|
||||
Width="{Binding ActualHeight, RelativeSource={RelativeSource Self}}"
|
||||
IsEnabled="{Binding IsCurrent, Converter={x:Static converters:InvertBooleanConverter.Instance}}"
|
||||
Click="OnDownload">
|
||||
<Viewbox Width="16" Height="16" VerticalAlignment="Center" HorizontalAlignment="Center">
|
||||
<Canvas Width="16" Height="16">
|
||||
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.DisabledForegroundBrush}}"
|
||||
Data="M2.75 14A1.75 1.75 0 0 1 1 12.25v-2.5a.75.75 0 0 1 1.5 0v2.5c0 .138.112.25.25.25h10.5a.25.25 0 0 0 .25-.25v-2.5a.75.75 0 0 1 1.5 0v2.5A1.75 1.75 0 0 1 13.25 14Z" />
|
||||
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.DisabledForegroundBrush}}"
|
||||
Data="M11.78 4.72a.749.749 0 1 1-1.06 1.06L8.75 3.811V9.5a.75.75 0 0 1-1.5 0V3.811L5.28 5.78a.749.749 0 1 1-1.06-1.06l3.25-3.25a.749.749 0 0 1 1.06 0l3.25 3.25Z" />
|
||||
</Canvas>
|
||||
</Viewbox>
|
||||
</Button>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
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 CommitProperty =
|
||||
DependencyProperty.Register(nameof(Commit), typeof(GitHubCommit), typeof(CommitDownloaderControl), new PropertyMetadata(null));
|
||||
|
||||
public GitHubCommit Commit
|
||||
{
|
||||
get { return (GitHubCommit)GetValue(CommitProperty); }
|
||||
set { SetValue(CommitProperty, value); }
|
||||
}
|
||||
|
||||
private void OnDownload(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Commit.Download();
|
||||
}
|
||||
}
|
||||
|
||||
25
FModel/Views/Resources/Converters/CommitMessageConverter.cs
Normal file
25
FModel/Views/Resources/Converters/CommitMessageConverter.cs
Normal file
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
24
FModel/Views/Resources/Converters/DateTimeToDateConverter.cs
Normal file
24
FModel/Views/Resources/Converters/DateTimeToDateConverter.cs
Normal file
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
24
FModel/Views/Resources/Converters/InvertBooleanConverter.cs
Normal file
24
FModel/Views/Resources/Converters/InvertBooleanConverter.cs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace FModel.Views.Resources.Converters;
|
||||
|
||||
public class InvertBooleanConverter : IValueConverter
|
||||
{
|
||||
public static readonly InvertBooleanConverter Instance = new();
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is bool boolean)
|
||||
{
|
||||
return !boolean;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
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.ToLocalTime();
|
||||
|
||||
int time;
|
||||
string unit;
|
||||
if (timeSpan.TotalSeconds < 30)
|
||||
return "Just now";
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
@ -68,6 +68,8 @@
|
|||
<Geometry x:Key="UnfoldIcon">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</Geometry>
|
||||
<Geometry x:Key="LocateMeIcon">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</Geometry>
|
||||
<Geometry x:Key="MeshIcon">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</Geometry>
|
||||
<Geometry x:Key="ArchiveIcon">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</Geometry>
|
||||
<Geometry x:Key="GitHubIcon">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</Geometry>
|
||||
|
||||
<Style x:Key="TabItemFillSpace" TargetType="TabItem" BasedOn="{StaticResource {x:Type TabItem}}">
|
||||
<Setter Property="Width">
|
||||
|
|
|
|||
114
FModel/Views/UpdateView.xaml
Normal file
114
FModel/Views/UpdateView.xaml
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
<adonisControls:AdonisWindow x:Class="FModel.Views.UpdateView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:FModel"
|
||||
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"
|
||||
WindowStartupLocation="CenterScreen" IconVisibility="Collapsed" ResizeMode="CanMinimize" Loaded="OnLoaded"
|
||||
MinHeight="{Binding Source={x:Static SystemParameters.MaximizedPrimaryScreenHeight}, Converter={converters:RatioConverter}, ConverterParameter='0.40'}"
|
||||
Width="{Binding Source={x:Static SystemParameters.MaximizedPrimaryScreenWidth}, Converter={converters:RatioConverter}, ConverterParameter='0.35'}">
|
||||
<adonisControls:AdonisWindow.Style>
|
||||
<Style TargetType="adonisControls:AdonisWindow" BasedOn="{StaticResource {x:Type adonisControls:AdonisWindow}}" >
|
||||
<Setter Property="Title" Value="Releases" />
|
||||
</Style>
|
||||
</adonisControls:AdonisWindow.Style>
|
||||
<adonisControls:AdonisWindow.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="Resources/Resources.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</adonisControls:AdonisWindow.Resources>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock Grid.Row="0" TextWrapping="Wrap" HorizontalAlignment="Center" TextAlignment="Center" Margin="10">
|
||||
All releases listed below are available for download. They are sorted by date, with the latest release at the top.
|
||||
We regularly remove old ones to keep the list clean and up to date with the latest UE releases.
|
||||
If you wish to manually check for updates, this window is accessible via the Help > Releases menu.
|
||||
</TextBlock>
|
||||
|
||||
<Grid Grid.Row="1" HorizontalAlignment="Center">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="5" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<!-- <Grid.Style> -->
|
||||
<!-- <Style TargetType="Grid"> -->
|
||||
<!-- <Setter Property="Visibility" Value="Visible" /> -->
|
||||
<!-- <Style.Triggers> -->
|
||||
<!-- <DataTrigger Binding="{Binding Title, RelativeSource={RelativeSource AncestorType=adonisControls:AdonisWindow}}" Value="Releases"> -->
|
||||
<!-- <Setter Property="Visibility" Value="Collapsed" /> -->
|
||||
<!-- </DataTrigger> -->
|
||||
<!-- </Style.Triggers> -->
|
||||
<!-- </Style> -->
|
||||
<!-- </Grid.Style> -->
|
||||
|
||||
<Button Grid.Column="0" Style="{DynamicResource {x:Static adonisUi:Styles.AccentButton}}"
|
||||
VerticalAlignment="Top" Height="{Binding ActualHeight, ElementName=RemindButton}"
|
||||
Click="OnDownloadLatest">
|
||||
Download Latest Release
|
||||
</Button>
|
||||
<StackPanel Grid.Column="2">
|
||||
<adonisControls:SplitButton x:Name="RemindButton" Content="Remind Me Now ..." Command="{Binding RemindMeCommand}">
|
||||
<adonisControls:SplitButton.SplitMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem Header="In 3 Days" Command="{Binding RemindMeCommand}" CommandParameter="Days" />
|
||||
<MenuItem Header="Next Week" Command="{Binding RemindMeCommand}" CommandParameter="Week" />
|
||||
<MenuItem Header="Next Month" Command="{Binding RemindMeCommand}" CommandParameter="Month" />
|
||||
<MenuItem Header="Never" Command="{Binding RemindMeCommand}" CommandParameter="Never" />
|
||||
</ContextMenu>
|
||||
</adonisControls:SplitButton.SplitMenu>
|
||||
</adonisControls:SplitButton>
|
||||
<TextBlock VerticalAlignment="Bottom" HorizontalAlignment="Right" FontSize="10" Margin="0 2.5 0 0"
|
||||
Text="{Binding NextUpdateCheck, Source={x:Static local:Settings.UserSettings.Default}, StringFormat=Next Refresh: {0:MMM d, yyyy}}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<Separator Grid.Row="2" Style="{StaticResource CustomSeparator}" Tag="History" />
|
||||
<ScrollViewer Grid.Row="3" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
|
||||
<ItemsControl ItemsSource="{Binding CommitsView}">
|
||||
<ItemsControl.GroupStyle>
|
||||
<GroupStyle>
|
||||
<GroupStyle.ContainerStyle>
|
||||
<Style TargetType="GroupItem">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="GroupItem">
|
||||
<GroupBox adonisExtensions:LayerExtension.Layer="3"
|
||||
Header="{Binding Name}"
|
||||
HeaderStringFormat="Commits on {0:MMM d, yyyy}"
|
||||
Margin="0 0 0 5">
|
||||
<ItemsPresenter />
|
||||
</GroupBox>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</GroupStyle.ContainerStyle>
|
||||
<GroupStyle.Panel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Vertical" />
|
||||
</ItemsPanelTemplate>
|
||||
</GroupStyle.Panel>
|
||||
</GroupStyle>
|
||||
</ItemsControl.GroupStyle>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<controls:CommitControl Margin="0 0 0 1" />
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</adonisControls:AdonisWindow>
|
||||
|
||||
27
FModel/Views/UpdateView.xaml.cs
Normal file
27
FModel/Views/UpdateView.xaml.cs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
using System.Windows;
|
||||
using FModel.ViewModels;
|
||||
using FModel.Views.Resources.Controls;
|
||||
|
||||
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 OnDownloadLatest(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (DataContext is not UpdateViewModel viewModel) return;
|
||||
viewModel.DownloadLatest();
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user