mirror of
https://github.com/gwdevhub/Daybreak.git
synced 2026-09-17 13:55:02 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b01c09491f |
@@ -22,7 +22,7 @@ using LiteDB;
|
||||
using Daybreak.Services.Options;
|
||||
using Daybreak.Models;
|
||||
using Microsoft.CorrelationVector;
|
||||
using Services.IconRetrieve;
|
||||
using System.Logging;
|
||||
|
||||
namespace Daybreak.Configuration
|
||||
{
|
||||
@@ -61,7 +61,18 @@ namespace Daybreak.Configuration
|
||||
serviceProducer.RegisterScoped<IIconRetriever, IconRetriever>();
|
||||
serviceProducer.RegisterScoped<IPrivilegeManager, PrivilegeManager>();
|
||||
serviceProducer.RegisterScoped<IScreenManager, ScreenManager>();
|
||||
serviceProducer.RegisterLogWriter<ILogsManager, JsonLogsManager>();
|
||||
serviceProducer.RegisterSingleton<ILogsManager, JsonLogsManager>();
|
||||
serviceProducer.RegisterSingleton<IDebugLogsWriter, Services.Logging.DebugLogsWriter>();
|
||||
serviceProducer.RegisterSingleton<ILoggerFactory, LoggerFactory>(sp =>
|
||||
{
|
||||
var factory = new LoggerFactory();
|
||||
factory.AddProvider(new CVLoggerProvider(sp.GetService<ILogsWriter>()));
|
||||
return factory;
|
||||
});
|
||||
serviceProducer.RegisterSingleton<ILogsWriter, CompositeLogsWriter>(sp => new CompositeLogsWriter(
|
||||
sp.GetService<ILogsManager>(),
|
||||
sp.GetService<IDebugLogsWriter>()));
|
||||
|
||||
serviceProducer.RegisterScoped((sp) => new ScopeMetadata(new CorrelationVector()));
|
||||
}
|
||||
|
||||
@@ -83,6 +94,7 @@ namespace Daybreak.Configuration
|
||||
viewProducer.RegisterView<ScreenChoiceView>();
|
||||
viewProducer.RegisterView<VersionManagementView>();
|
||||
viewProducer.RegisterView<LogsView>();
|
||||
viewProducer.RegisterView<IconDownloadView>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ using Daybreak.Models.Builds;
|
||||
using Daybreak.Services.BuildTemplates;
|
||||
using Daybreak.Services.IconRetrieve;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Services.IconRetrieve;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<LangVersion>preview</LangVersion>
|
||||
<ApplicationIcon>Daybreak.ico</ApplicationIcon>
|
||||
<IncludePackageReferencesDuringMarkupCompilation>true</IncludePackageReferencesDuringMarkupCompilation>
|
||||
<Version>0.9.3.3</Version>
|
||||
<Version>0.9.3.4</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -45,6 +45,9 @@
|
||||
<Compile Update="Controls\Buttons\CancelButton.xaml.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Update="Views\IconDownloadView.xaml.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -68,6 +71,10 @@
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Update="Views\IconDownloadView.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="'$(Configuration)' == 'Release'">
|
||||
|
||||
@@ -143,7 +143,7 @@ namespace Daybreak.Models.Builds
|
||||
public static Skill Flurry { get; } = new() { Id = 344, Name = "Flurry", Profession = Profession.Warrior };
|
||||
public static Skill Frenzy { get; } = new() { Id = 346, Name = "Frenzy", Profession = Profession.Warrior };
|
||||
public static Skill Coward { get; } = new() { Id = 869, Name = "\"Coward!\"", Profession = Profession.Warrior };
|
||||
public static Skill OnYourKnees { get; } = new() { Id = 906, Name = "On Your Knees!", Profession = Profession.Warrior };
|
||||
public static Skill OnYourKnees { get; } = new() { Id = 906, Name = "\"On Your Knees!\"", Profession = Profession.Warrior };
|
||||
public static Skill YoureAllAlone { get; } = new() { Id = 1412, Name = "\"You're All Alone!\"", Profession = Profession.Warrior };
|
||||
public static Skill FrenziedDefense { get; } = new() { Id = 1700, Name = "Frenzied Defense", Profession = Profession.Warrior };
|
||||
public static Skill Grapple { get; } = new() { Id = 2011, Name = "Grapple", Profession = Profession.Warrior };
|
||||
@@ -702,7 +702,7 @@ namespace Daybreak.Models.Builds
|
||||
public static Skill Echo { get; } = new() { Id = 74, Name = "Echo", Profession = Profession.Mesmer };
|
||||
public static Skill ArcaneEcho { get; } = new() { Id = 75, Name = "Arcane Echo", Profession = Profession.Mesmer };
|
||||
public static Skill Epidemic { get; } = new() { Id = 78, Name = "Epidemic", Profession = Profession.Mesmer };
|
||||
public static Skill LyssasBalance { get; } = new() { Id = 877, Name = "Lyssa's Balance, Profession = Profession.Mesmer" };
|
||||
public static Skill LyssasBalance { get; } = new() { Id = 877, Name = "Lyssa's Balance", Profession = Profession.Mesmer };
|
||||
public static Skill SignetofDisenchantment { get; } = new() { Id = 882, Name = "Signet of Disenchantment", Profession = Profession.Mesmer };
|
||||
public static Skill ShatterStorm { get; } = new() { Id = 933, Name = "Shatter Storm", Profession = Profession.Mesmer };
|
||||
public static Skill ExpelHexes { get; } = new() { Id = 954, Name = "Expel Hexes", Profession = Profession.Mesmer };
|
||||
@@ -1053,7 +1053,7 @@ namespace Daybreak.Models.Builds
|
||||
public static Skill FeastofSouls { get; } = new() { Id = 980, Name = "Feast of Souls", Profession = Profession.Ritualist };
|
||||
public static Skill RitualLord { get; } = new() { Id = 1217, Name = "Ritual Lord", Profession = Profession.Ritualist };
|
||||
public static Skill AttunedWasSongkai { get; } = new() { Id = 1220, Name = "Attuned Was Songkai", Profession = Profession.Ritualist };
|
||||
public static Skill AnguishedWasLingwah { get; } = new() { Id = 1223, Name = "Anguished Was Lingwah, Profession = Profession.Ritualist" };
|
||||
public static Skill AnguishedWasLingwah { get; } = new() { Id = 1223, Name = "Anguished Was Lingwah", Profession = Profession.Ritualist };
|
||||
public static Skill ExplosiveGrowth { get; } = new() { Id = 1229, Name = "Explosive Growth", Profession = Profession.Ritualist };
|
||||
public static Skill BoonofCreation { get; } = new() { Id = 1230, Name = "Boon of Creation", Profession = Profession.Ritualist };
|
||||
public static Skill SpiritChanneling { get; } = new() { Id = 1231, Name = "Spirit Channeling", Profession = Profession.Ritualist };
|
||||
@@ -1483,8 +1483,8 @@ namespace Daybreak.Models.Builds
|
||||
public static Skill VolfenBlessing { get; } = new() { Id = 2379, Name = "Volfen Blessing", Profession = Profession.None };
|
||||
public static Skill TimeWard { get; } = new() { Id = 3422, Name = "Time Ward", Profession = Profession.Mesmer };
|
||||
public static Skill SoulTaker { get; } = new() { Id = 3423, Name = "Soul Taker", Profession = Profession.Necromancer };
|
||||
public static Skill OverTheLimit { get; } = new() { Id = 3424, Name = "Over The Limit", Profession = Profession.Elementalist };
|
||||
public static Skill JudgementStrike { get; } = new() { Id = 3425, Name = "Judgement Strike", Profession = Profession.Monk };
|
||||
public static Skill OverTheLimit { get; } = new() { Id = 3424, Name = "Over The Limit", AlternativeName = "Over the Limit", Profession = Profession.Elementalist };
|
||||
public static Skill JudgementStrike { get; } = new() { Id = 3425, Name = "Judgement Strike", AlternativeName = "Judgment Strike", Profession = Profession.Monk };
|
||||
public static Skill SevenWeaponsStance { get; } = new() { Id = 3426, Name = "Seven Weapons Stance", Profession = Profession.Warrior };
|
||||
public static Skill Togetherasone { get; } = new() { Id = 3427, Name = "\"Together as one!\"", Profession = Profession.Ranger };
|
||||
public static Skill ShadowTheft { get; } = new() { Id = 3428, Name = "Shadow Theft", Profession = Profession.Assassin };
|
||||
@@ -3022,6 +3022,7 @@ namespace Daybreak.Models.Builds
|
||||
public Profession Profession { get; private set; }
|
||||
public string Name { get; private set; }
|
||||
public int Id { get; private set; }
|
||||
public string AlternativeName { get; private set; }
|
||||
private Skill()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
using Models;
|
||||
using System.Threading;
|
||||
|
||||
namespace Services.IconRetrieve
|
||||
namespace Daybreak.Services.IconRetrieve
|
||||
{
|
||||
public interface IIconBrowser
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Daybreak.Utils;
|
||||
using Daybreak.Models.Builds;
|
||||
using Daybreak.Utils;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Web.WebView2.Wpf;
|
||||
using Models;
|
||||
@@ -7,13 +8,14 @@ using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Core.Extensions;
|
||||
using System.Extensions;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace Services.IconRetrieve
|
||||
namespace Daybreak.Services.IconRetrieve
|
||||
{
|
||||
public sealed class IconBrowser : IIconBrowser
|
||||
{
|
||||
@@ -23,6 +25,8 @@ namespace Services.IconRetrieve
|
||||
private const string BaseUrl = "https://wiki.guildwars.com";
|
||||
private const string QueryUrl = $"wiki/File:{NamePlaceholder}.jpg";
|
||||
private const string NamePlaceholder = "[SKILLNAME]";
|
||||
private const string IconsDirectoryName = "Icons";
|
||||
private const string IconsLocation = $"{IconsDirectoryName}/{NamePlaceholder}.jpg";
|
||||
|
||||
private readonly ConcurrentQueue<IconRequest> iconRequests = new();
|
||||
private readonly ILogger<IconBrowser> logger;
|
||||
@@ -62,7 +66,8 @@ namespace Services.IconRetrieve
|
||||
continue;
|
||||
}
|
||||
|
||||
this.logger.LogInformation($"Retrieving {request.Skill.Name} icon");
|
||||
var logger = this.logger.CreateScopedLogger(nameof(this.PeriodicallyServeRequests), request.Skill?.Name);
|
||||
logger.LogInformation($"Retrieving icon");
|
||||
while(this.webView2 is null)
|
||||
{
|
||||
if (this.cancellationToken.IsCancellationRequested)
|
||||
@@ -70,23 +75,21 @@ namespace Services.IconRetrieve
|
||||
return;
|
||||
}
|
||||
|
||||
this.logger.LogInformation($"Browser is not yet initialized. Waiting");
|
||||
logger.LogInformation($"Browser is not yet initialized. Waiting");
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
|
||||
await Application.Current.Dispatcher.InvokeAsync(async () =>
|
||||
{
|
||||
await this.webView2.EnsureCoreWebView2Async();
|
||||
}, DispatcherPriority.Render);
|
||||
|
||||
var curedSkillName = request.Skill.Name.Replace(" ", "_");
|
||||
var curedSkillName = request.Skill.AlternativeName.IsNullOrWhiteSpace() ?
|
||||
request.Skill.Name.Replace(" ", "_") :
|
||||
request.Skill.AlternativeName.Replace(" ", "_");
|
||||
var skillIconUrl = $"{BaseUrl}/{QueryUrl.Replace(NamePlaceholder, curedSkillName)}";
|
||||
this.logger.LogInformation($"Looking for icon at {skillIconUrl}");
|
||||
logger.LogInformation($"Looking for icon at {skillIconUrl}");
|
||||
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
this.webView2.Source = new Uri(skillIconUrl);
|
||||
});
|
||||
|
||||
for(var i = 0; i < 5; i++)
|
||||
{
|
||||
if (this.cancellationToken.IsCancellationRequested)
|
||||
@@ -94,24 +97,24 @@ namespace Services.IconRetrieve
|
||||
return;
|
||||
}
|
||||
|
||||
this.logger.LogInformation("Executing extraction script");
|
||||
logger.LogInformation("Executing extraction script");
|
||||
var responseTask = await Application.Current.Dispatcher.InvokeAsync(async () =>
|
||||
{
|
||||
return await this.webView2.ExecuteScriptAsync(Scripts.GetHrefFromSkillPage);
|
||||
});
|
||||
var response = await responseTask;
|
||||
this.logger.LogInformation("Parsing response");
|
||||
logger.LogInformation("Parsing response");
|
||||
var iconPayload = JsonConvert.DeserializeObject<IconPayload>(response);
|
||||
if (iconPayload is null)
|
||||
{
|
||||
this.logger.LogInformation("Bad response");
|
||||
logger.LogInformation("Bad response");
|
||||
await Task.Delay(1000);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (iconPayload.SkillUrl != skillIconUrl.Replace("\"", "%22"))
|
||||
{
|
||||
this.logger.LogInformation("Retrieved icon doesn't match");
|
||||
logger.LogInformation("Retrieved icon doesn't match");
|
||||
await Task.Delay(1000);
|
||||
continue;
|
||||
}
|
||||
@@ -120,18 +123,41 @@ namespace Services.IconRetrieve
|
||||
if (potentialBase64 == FaultyBase64 ||
|
||||
potentialBase64 == LargeFaultyBase64)
|
||||
{
|
||||
this.logger.LogInformation("Faulty base64 retrieved");
|
||||
logger.LogInformation("Faulty base64 retrieved");
|
||||
await Task.Delay(1000);
|
||||
continue;
|
||||
}
|
||||
|
||||
byte[] bytes;
|
||||
try
|
||||
{
|
||||
bytes = Convert.FromBase64String(potentialBase64);
|
||||
}
|
||||
catch
|
||||
{
|
||||
logger.LogError("Failed to parse base64");
|
||||
await Task.Delay(1000);
|
||||
continue;
|
||||
}
|
||||
|
||||
await SaveIconLocally(request.Skill, bytes);
|
||||
request.IconBase64 = potentialBase64;
|
||||
request.Finished = true;
|
||||
break;
|
||||
}
|
||||
|
||||
this.logger.LogError($"Failed to retrieve icon for {request.Skill.Name}");
|
||||
logger.LogError($"Failed to retrieve icon");
|
||||
request.Finished = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<string> SaveIconLocally(Skill skill, byte[] data)
|
||||
{
|
||||
var curedSkillName = skill.Name
|
||||
.Replace(" ", "_")
|
||||
.Replace("\"", "");
|
||||
await File.WriteAllBytesAsync(IconsLocation.Replace(NamePlaceholder, curedSkillName), data);
|
||||
return curedSkillName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
using Daybreak.Models.Builds;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Models;
|
||||
using Services.IconRetrieve;
|
||||
using System;
|
||||
using System.Configuration;
|
||||
using System.Core.Extensions;
|
||||
@@ -18,52 +17,27 @@ namespace Daybreak.Services.IconRetrieve
|
||||
private const string IconsDirectoryName = "Icons";
|
||||
private const string IconsLocation = $"{IconsDirectoryName}/{NamePlaceholder}.jpg";
|
||||
|
||||
private readonly IIconBrowser iconBrowser;
|
||||
private readonly ILogger<IconRetriever> logger;
|
||||
private readonly ILiveOptions<ApplicationConfiguration> liveOptions;
|
||||
|
||||
public IconRetriever(
|
||||
ILogger<IconRetriever> logger,
|
||||
IIconBrowser iconBrowser,
|
||||
ILiveOptions<ApplicationConfiguration> liveOptions)
|
||||
ILogger<IconRetriever> logger)
|
||||
{
|
||||
this.iconBrowser = iconBrowser.ThrowIfNull();
|
||||
this.logger = logger.ThrowIfNull();
|
||||
this.liveOptions = liveOptions.ThrowIfNull();
|
||||
if (Directory.Exists(IconsDirectoryName) is false)
|
||||
{
|
||||
Directory.CreateDirectory(IconsDirectoryName);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Optional<Uri>> GetIconUri(Skill skill)
|
||||
public Task<Optional<Uri>> GetIconUri(Skill skill)
|
||||
{
|
||||
var maybeIconUri = this.GetLocalIcon(skill);
|
||||
if (maybeIconUri.ExtractValue() is Uri uri)
|
||||
{
|
||||
return uri;
|
||||
return Task.FromResult(Optional.FromValue(uri));
|
||||
}
|
||||
|
||||
if (this.liveOptions.Value.ExperimentalFeatures.DownloadIcons)
|
||||
{
|
||||
this.logger.LogInformation("Application is configured to download icons");
|
||||
return await this.DownloadIcon(skill);
|
||||
}
|
||||
|
||||
return Optional.None<Uri>();
|
||||
}
|
||||
|
||||
private async Task<Optional<Uri>> DownloadIcon(Skill skill)
|
||||
{
|
||||
var maybeBase64 = await this.GetBase64ForSkill(skill);
|
||||
if (maybeBase64.ExtractValue() is not string base64)
|
||||
{
|
||||
return Optional.None<Uri>();
|
||||
}
|
||||
|
||||
var bytes = Convert.FromBase64String(base64);
|
||||
var uri = await SaveIconLocally(skill, bytes);
|
||||
return new Uri(AppDomain.CurrentDomain.BaseDirectory + "/" + IconsLocation.Replace(NamePlaceholder, uri), UriKind.Absolute);
|
||||
return Task.FromResult(Optional.None<Uri>());
|
||||
}
|
||||
|
||||
private Optional<Uri> GetLocalIcon(Skill skill)
|
||||
@@ -81,33 +55,5 @@ namespace Daybreak.Services.IconRetrieve
|
||||
this.logger.LogWarning("No local icon cache found");
|
||||
return Optional.None<Uri>();
|
||||
}
|
||||
|
||||
private async Task<Optional<string>> GetBase64ForSkill(Skill skill)
|
||||
{
|
||||
var request = new IconRequest { Skill = skill };
|
||||
this.iconBrowser.QueueIconRequest(request);
|
||||
|
||||
// Wait for the request to be served
|
||||
for (var i = 0; i < 20; i++)
|
||||
{
|
||||
if (request.Finished)
|
||||
{
|
||||
return request.IconBase64;
|
||||
}
|
||||
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
|
||||
return Optional.None<string>();
|
||||
}
|
||||
|
||||
private static async Task<string> SaveIconLocally(Skill skill, byte[] data)
|
||||
{
|
||||
var curedSkillName = skill.Name
|
||||
.Replace(" ", "_")
|
||||
.Replace("\"", "");
|
||||
await File.WriteAllBytesAsync(IconsLocation.Replace(NamePlaceholder, curedSkillName), data);
|
||||
return curedSkillName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Logging;
|
||||
|
||||
namespace Daybreak.Services.Logging
|
||||
{
|
||||
public sealed class CompositeLogsWriter : ILogsWriter
|
||||
{
|
||||
private readonly IEnumerable<ILogsWriter> logsWriters;
|
||||
|
||||
public CompositeLogsWriter(params ILogsWriter[] innerLogsWriters)
|
||||
{
|
||||
this.logsWriters = innerLogsWriters;
|
||||
}
|
||||
|
||||
public void WriteLog(Log log)
|
||||
{
|
||||
foreach (var logWriter in this.logsWriters)
|
||||
{
|
||||
logWriter.WriteLog(log);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using System.Diagnostics;
|
||||
using System.Logging;
|
||||
|
||||
namespace Daybreak.Services.Logging
|
||||
{
|
||||
public sealed class DebugLogsWriter : IDebugLogsWriter
|
||||
{
|
||||
public void WriteLog(Log log)
|
||||
{
|
||||
Debug.WriteLine($"[{log.LogTime}]\t[{log.LogLevel}]\t[{log.Category}]\n{log.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using System.Logging;
|
||||
|
||||
namespace Daybreak.Services.Logging
|
||||
{
|
||||
public interface IDebugLogsWriter : ILogsWriter
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,6 @@ using Daybreak.Services.BuildTemplates;
|
||||
using Daybreak.Services.IconRetrieve;
|
||||
using Daybreak.Services.ViewManagement;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Services.IconRetrieve;
|
||||
using System;
|
||||
using System.Configuration;
|
||||
using System.Extensions;
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
<UserControl x:Class="Daybreak.Views.IconDownloadView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Daybreak.Views"
|
||||
xmlns:controls="clr-namespace:Daybreak.Controls"
|
||||
mc:Ignorable="d"
|
||||
x:Name="_this"
|
||||
Unloaded="IconDownloadView_Unloaded"
|
||||
Loaded="IconDownloadView_Loaded"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<UserControl.Resources>
|
||||
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"></BooleanToVisibilityConverter>
|
||||
</UserControl.Resources>
|
||||
<Grid VerticalAlignment="Center" HorizontalAlignment="Center" Background="White" MinHeight="200" MinWidth="400">
|
||||
<controls:ChromiumBrowserWrapper x:Name="WebView"
|
||||
ControlsEnabled="False"
|
||||
AddressBarReadonly="True"
|
||||
CanNavigate="False"
|
||||
CanDownloadBuild="False"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center"
|
||||
Visibility="Visible"
|
||||
Width="0"
|
||||
Height="0"></controls:ChromiumBrowserWrapper>
|
||||
<StackPanel VerticalAlignment="Center">
|
||||
<TextBlock Text="{Binding ElementName=_this, Path=Description, Mode=OneWay}" Margin="10, 0, 10, 0" Foreground="Black"
|
||||
TextWrapping="Wrap" HorizontalAlignment="Center" FontSize="16"></TextBlock>
|
||||
<ProgressBar Minimum="0" Maximum="100" Value="{Binding ElementName=_this, Path=ProgressValue, Mode=OneWay}" Width="300" Height="20"></ProgressBar>
|
||||
<controls:OpaqueButton Text="Cancel" BackgroundOpacity="0.2" TransparentBackground="Gray" HorizontalAlignment="Center" Margin="10" Width="50" Height="25"
|
||||
Clicked="OpaqueButton_Clicked" Foreground="Black" FontSize="16"></controls:OpaqueButton>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,125 @@
|
||||
using Daybreak.Models.Builds;
|
||||
using Daybreak.Services.IconRetrieve;
|
||||
using Daybreak.Services.ViewManagement;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Models;
|
||||
using System.Core.Extensions;
|
||||
using System.Extensions;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Extensions;
|
||||
|
||||
namespace Daybreak.Views
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for UpdateView.xaml
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0044:Add readonly modifier", Justification = "Fields used by source generator for DependencyProperty")]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "Used by source generators")]
|
||||
public partial class IconDownloadView : UserControl
|
||||
{
|
||||
private static bool CompleteIcons = false;
|
||||
|
||||
private readonly CancellationTokenSource cancellationTokenSource = new();
|
||||
private readonly IIconRetriever iconRetriever;
|
||||
private readonly IIconBrowser iconBrowser;
|
||||
private readonly IViewManager viewManager;
|
||||
private readonly ILogger<IconDownloadView> logger;
|
||||
|
||||
[GenerateDependencyProperty]
|
||||
private string description;
|
||||
[GenerateDependencyProperty]
|
||||
private double progressValue;
|
||||
|
||||
public IconDownloadView(
|
||||
IIconRetriever iconRetriever,
|
||||
IIconBrowser iconBrowser,
|
||||
IViewManager viewManager,
|
||||
ILogger<IconDownloadView> logger)
|
||||
{
|
||||
this.iconRetriever = iconRetriever.ThrowIfNull();
|
||||
this.iconBrowser = iconBrowser.ThrowIfNull();
|
||||
this.viewManager = viewManager.ThrowIfNull();
|
||||
this.logger = logger.ThrowIfNull();
|
||||
this.InitializeComponent();
|
||||
this.Description = "Verifying icons";
|
||||
}
|
||||
|
||||
private async void IconDownloadView_Loaded(object sender, System.Windows.RoutedEventArgs e)
|
||||
{
|
||||
await this.WebView.WebBrowser.EnsureCoreWebView2Async();
|
||||
this.DownloadSkills();
|
||||
}
|
||||
|
||||
private void IconDownloadView_Unloaded(object sender, System.Windows.RoutedEventArgs e)
|
||||
{
|
||||
this.cancellationTokenSource.Cancel();
|
||||
}
|
||||
|
||||
private void OpaqueButton_Clicked(object sender, System.EventArgs e)
|
||||
{
|
||||
this.viewManager.ShowView<BuildsListView>();
|
||||
}
|
||||
|
||||
private async void DownloadSkills()
|
||||
{
|
||||
if (CompleteIcons)
|
||||
{
|
||||
this.logger.LogInformation("All icons were detected. Skipping check");
|
||||
this.viewManager.ShowView<BuildsListView>();
|
||||
return;
|
||||
}
|
||||
|
||||
this.logger.LogInformation("Beginning icon download");
|
||||
this.iconBrowser.InitializeWebView(this.WebView.WebBrowser, this.cancellationTokenSource.Token);
|
||||
var progressIncrement = 100d / Skill.Skills.Count();
|
||||
var incomplete = false;
|
||||
foreach(var skill in Skill.Skills.OrderBy(s => s.Name))
|
||||
{
|
||||
if (skill == Skill.NoSkill)
|
||||
{
|
||||
this.ProgressValue += progressIncrement;
|
||||
continue;
|
||||
}
|
||||
|
||||
var logger = this.logger.CreateScopedLogger(nameof(this.DownloadSkills), skill.Name);
|
||||
logger.LogInformation("Verifying if icon exists");
|
||||
this.Description = $"Checking [{skill.Name}] icon";
|
||||
if ((await this.iconRetriever.GetIconUri(skill)).ExtractValue() is not null)
|
||||
{
|
||||
logger.LogInformation("Icon exists");
|
||||
this.ProgressValue += progressIncrement;
|
||||
await Task.Delay(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
this.Description = $"Downloading [{skill.Name}] icon";
|
||||
logger.LogInformation("Downloading icon");
|
||||
var request = new IconRequest { Skill = skill };
|
||||
this.iconBrowser.QueueIconRequest(request);
|
||||
|
||||
while(request.Finished is false)
|
||||
{
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
|
||||
if (request.IconBase64.IsNullOrWhiteSpace())
|
||||
{
|
||||
logger.LogWarning("Failed to download icon");
|
||||
incomplete = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogInformation("Downloaded icon");
|
||||
}
|
||||
|
||||
this.ProgressValue += progressIncrement;
|
||||
}
|
||||
|
||||
CompleteIcons = !incomplete;
|
||||
this.viewManager.ShowView<BuildsListView>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,7 @@
|
||||
using Daybreak.Services.ViewManagement;
|
||||
using Daybreak.Configuration;
|
||||
using Daybreak.Services.ViewManagement;
|
||||
using System.Configuration;
|
||||
using System.Core.Extensions;
|
||||
using System.Extensions;
|
||||
using System.Windows.Controls;
|
||||
|
||||
@@ -10,11 +13,14 @@ namespace Daybreak.Views
|
||||
public partial class SettingsCategoryView : UserControl
|
||||
{
|
||||
private readonly IViewManager viewManager;
|
||||
private readonly ILiveOptions<ApplicationConfiguration> liveOptions;
|
||||
|
||||
public SettingsCategoryView(
|
||||
ILiveOptions<ApplicationConfiguration> liveOptions,
|
||||
IViewManager viewManager)
|
||||
{
|
||||
this.viewManager = viewManager.ThrowIfNull(nameof(viewManager));
|
||||
this.liveOptions = liveOptions.ThrowIfNull();
|
||||
this.viewManager = viewManager.ThrowIfNull();
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
@@ -35,7 +41,14 @@ namespace Daybreak.Views
|
||||
|
||||
private void BuildsButton_Clicked(object sender, System.EventArgs e)
|
||||
{
|
||||
this.viewManager.ShowView<BuildsListView>();
|
||||
if (this.liveOptions.Value.ExperimentalFeatures.DownloadIcons)
|
||||
{
|
||||
this.viewManager.ShowView<IconDownloadView>();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.viewManager.ShowView<BuildsListView>();
|
||||
}
|
||||
}
|
||||
|
||||
private void VersionButton_Clicked(object sender, System.EventArgs e)
|
||||
|
||||
Reference in New Issue
Block a user