Compare commits

...
1 Commits
Author SHA1 Message Date
amacocianandGitHub b01c09491f Download and check icons at startup (#41) 2022-08-12 23:41:22 +02:00
14 changed files with 296 additions and 89 deletions
+14 -2
View File
@@ -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;
+8 -1
View File
@@ -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'">
+6 -5
View File
@@ -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
{
+43 -17
View File
@@ -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
{
}
}
-1
View File
@@ -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;
+35
View File
@@ -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>
+125
View File
@@ -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>();
}
}
}
+16 -3
View File
@@ -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)