Compare commits

...
4 Commits
Author SHA1 Message Date
amacocianandGitHub 15a67ea28c Minor fixes
Stop showing browser when browser is disabled
Prevent setting address of browser when browser is disabled (should prevent browser from instantiating when disabled)
Ignore errors from browser caused by switching view before the browser could be initialized
Provide expression to filter logs
Button to export logs to json file
2021-06-07 14:33:54 +02:00
amacocianandGitHub c6b62fd5fd Logging improvements
Log uncaught exceptions
Logview expander
2021-06-07 00:34:43 +02:00
amacocianandGitHub 3c0877c1a0 Ability to keep a local cache of icons (#16) 2021-06-03 21:12:31 +02:00
967b57b9a8 Fix build code encoding/decoding view (#15)
Co-authored-by: Alexandru Macocian <almacoci@microsoft.com>
2021-06-03 20:40:56 +02:00
20 changed files with 339 additions and 37 deletions
@@ -3,7 +3,9 @@ using FluentAssertions;
using LiteDB;
using Microsoft.Extensions.Logging;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.IO;
using System.Linq;
using WpfExtended.Logging;
namespace Daybreak.Tests.Services
@@ -37,6 +39,18 @@ namespace Daybreak.Tests.Services
logger.Should().NotBeNull();
}
[TestMethod]
public void LoggerLogsAndReaderReadsFiltered()
{
var logger = this.loggerProvider.CreateLogger("SomeCategory");
logger.LogTrace("Logging some trace");
logger.LogInformation("Logging some stuff");
logger.LogError("Logging some error");
this.logsManager.GetLogs(l => l.LogLevel < LogLevel.Information).Should().HaveCount(1);
var log = this.logsManager.GetLogs(l => l.LogLevel < LogLevel.Information).First();
log.LogLevel.Should().Be(LogLevel.Error);
}
[TestMethod]
public void LoggerLogsAndReaderReads()
{
var logger = this.loggerProvider.CreateLogger("SomeCategory");
@@ -37,5 +37,7 @@ namespace Daybreak.Configuration
public bool PlaceShortcut { get; set; }
[JsonProperty("AutoCheckUpdate")]
public bool AutoCheckUpdate { get; set; } = true;
[JsonProperty("KeepLocalIconCache")]
public bool KeepLocalIconCache { get; set; } = true;
}
}
@@ -22,6 +22,9 @@ namespace Daybreak.Controls
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "Used by source generators")]
public partial class ChromiumBrowserWrapper : UserControl
{
public static readonly DependencyProperty AddressProperty =
DependencyPropertyExtensions.Register<ChromiumBrowserWrapper, string>(nameof(Address));
private const string BrowserDownloadLink = "https://developer.microsoft.com/en-us/microsoft-edge/webview2/";
public event EventHandler<string> FavoriteUriChanged;
@@ -49,8 +52,17 @@ namespace Daybreak.Controls
private bool navigating;
[GenerateDependencyProperty]
private string favoriteAddress;
[GenerateDependencyProperty]
private string address;
public string Address
{
get => this.GetTypedValue<string>(AddressProperty);
set
{
if (this.BrowserSupported is true)
{
this.SetValue(AddressProperty, value);
}
}
}
public ChromiumBrowserWrapper()
{
@@ -15,6 +15,7 @@ namespace Daybreak.Controls
public partial class AttributeTemplate : UserControl
{
public event EventHandler<AttributeEntry> HelpClicked;
public event EventHandler<AttributeEntry> AttributeChanged;
[GenerateDependencyProperty(InitialValue = false)]
private bool canAdd;
@@ -50,6 +51,7 @@ namespace Daybreak.Controls
this.DataContext.As<AttributeEntry>().Points--;
this.CanSubtract = this.DataContext.As<AttributeEntry>().Points > 0;
this.CanAdd = true;
this.AttributeChanged?.Invoke(this, this.DataContext.As<AttributeEntry>());
}
}
@@ -60,6 +62,7 @@ namespace Daybreak.Controls
this.DataContext.As<AttributeEntry>().Points++;
this.CanAdd = this.DataContext.As<AttributeEntry>().Points < 12;
this.CanSubtract = true;
this.AttributeChanged?.Invoke(this, this.DataContext.As<AttributeEntry>());
}
}
@@ -75,7 +75,7 @@
HorizontalContentAlignment="Stretch" BorderThickness="0">
<ListBox.ItemTemplate>
<DataTemplate>
<local:AttributeTemplate HelpClicked="AttributeTemplate_HelpClicked"></local:AttributeTemplate>
<local:AttributeTemplate HelpClicked="AttributeTemplate_HelpClicked" AttributeChanged="AttributeTemplate_AttributeChanged"></local:AttributeTemplate>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
@@ -3,6 +3,7 @@ using Daybreak.Services.BuildTemplates;
using Daybreak.Services.Configuration;
using Daybreak.Services.IconRetrieve;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Extensions;
@@ -23,10 +24,13 @@ namespace Daybreak.Controls
private const string InfoNamePlaceholder = "[NAME]";
private const string BaseAddress = $"https://wiki.guildwars.com/wiki/{InfoNamePlaceholder}";
private bool suppressBuildChanged = false;
private bool loadedProperties = false;
private BuildEntry loadedBuild;
private SkillTemplate selectingSkillTemplate;
public event EventHandler BuildChanged;
[GenerateDependencyProperty]
private Profession primaryProfession;
[GenerateDependencyProperty]
@@ -95,6 +99,33 @@ namespace Daybreak.Controls
}
this.LoadSkills();
this.LoadAttributes();
if (this.suppressBuildChanged is false)
{
this.BuildChanged?.Invoke(this, new EventArgs());
}
}
if (e.Property == Skill0Property ||
e.Property == Skill1Property ||
e.Property == Skill2Property ||
e.Property == Skill3Property ||
e.Property == Skill4Property ||
e.Property == Skill5Property ||
e.Property == Skill6Property ||
e.Property == Skill7Property)
{
if (this.suppressBuildChanged is false)
{
this.loadedBuild.Build.Skills[0] = this.Skill0;
this.loadedBuild.Build.Skills[1] = this.Skill1;
this.loadedBuild.Build.Skills[2] = this.Skill2;
this.loadedBuild.Build.Skills[3] = this.Skill3;
this.loadedBuild.Build.Skills[4] = this.Skill4;
this.loadedBuild.Build.Skills[5] = this.Skill5;
this.loadedBuild.Build.Skills[6] = this.Skill6;
this.loadedBuild.Build.Skills[7] = this.Skill7;
this.BuildChanged?.Invoke(this, new EventArgs());
}
}
}
@@ -218,6 +249,7 @@ namespace Daybreak.Controls
private void LoadBuild()
{
this.suppressBuildChanged = true;
var build = this.DataContext.As<BuildEntry>();
this.loadedBuild = build;
this.PrimaryProfession = build.Build.Primary;
@@ -230,6 +262,7 @@ namespace Daybreak.Controls
this.Skill5 = build.Build.Skills[5];
this.Skill6 = build.Build.Skills[6];
this.Skill7 = build.Build.Skills[7];
this.suppressBuildChanged = false;
}
private void BrowseToInfo(string infoName)
@@ -241,13 +274,19 @@ namespace Daybreak.Controls
private void ShowInfoBrowser()
{
this.SkillBrowser.Width = 400;
this.SkillsListView.Width = 0;
if (this.SkillBrowser.BrowserSupported is true)
{
this.SkillBrowser.Width = 400;
this.SkillsListView.Width = 0;
}
}
private void HideInfoBrowser()
{
this.SkillBrowser.Width = 0;
if (this.SkillBrowser.BrowserSupported is true)
{
this.SkillBrowser.Width = 0;
}
}
private void ShowSkillListView()
@@ -294,6 +333,11 @@ namespace Daybreak.Controls
this.BrowseToInfo(e.Attribute.Name);
}
private void AttributeTemplate_AttributeChanged(object sender, AttributeEntry e)
{
this.BuildChanged?.Invoke(this, new EventArgs());
}
private void SkillTemplate_Clicked(object sender, RoutedEventArgs e)
{
var skill = sender.As<SkillTemplate>().DataContext.As<Skill>();
@@ -0,0 +1,18 @@
<UserControl x:Class="Daybreak.Controls.LogMessageTemplate"
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.Controls"
x:Name="_this"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVisibilityConverter"></BooleanToVisibilityConverter>
</UserControl.Resources>
<Grid HorizontalAlignment="Stretch">
<TextBlock Text="{Binding ElementName=_this, Path=Message, Mode=OneWay}" Background="Transparent"
Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
MouseLeftButtonDown="TextBox_MouseLeftButtonDown" MaxHeight="18" TextWrapping="Wrap"></TextBlock>
</Grid>
</UserControl>
@@ -0,0 +1,36 @@
using System.Windows.Extensions;
using System.Windows.Controls;
using System.Windows.Input;
using System.Extensions;
namespace Daybreak.Controls
{
/// <summary>
/// Interaction logic for LogTemplate.xaml
/// </summary>
public partial class LogMessageTemplate : UserControl
{
private bool expanded;
[GenerateDependencyProperty]
private string message;
public LogMessageTemplate()
{
this.InitializeComponent();
}
private void TextBox_MouseLeftButtonDown(object sender, MouseButtonEventArgs eventArgs)
{
this.expanded = !this.expanded;
if (this.expanded)
{
sender.As<TextBlock>().MaxHeight = double.MaxValue;
}
else
{
sender.As<TextBlock>().MaxHeight = 18;
}
}
}
}
+2 -2
View File
@@ -10,7 +10,7 @@
<LangVersion>preview</LangVersion>
<ApplicationIcon>Daybreak.ico</ApplicationIcon>
<IncludePackageReferencesDuringMarkupCompilation>true</IncludePackageReferencesDuringMarkupCompilation>
<Version>0.9.1</Version>
<Version>0.9.2.2</Version>
</PropertyGroup>
<ItemGroup>
@@ -27,7 +27,7 @@
<PackageReference Include="System.Windows.Interactivity.WPF" Version="2.0.20525" />
<PackageReference Include="SystemExtensions.NetStandard" Version="1.3.0" />
<PackageReference Include="WCL" Version="1.0.2" />
<PackageReference Include="WpfExtended" Version="0.4.1" />
<PackageReference Include="WpfExtended" Version="0.4.2" />
<PackageReference Include="WpfExtended.SourceGeneration" Version="0.1.1" />
<PackageReference Include="WpfScreenHelper" Version="1.0.0" />
</ItemGroup>
+16 -6
View File
@@ -16,7 +16,7 @@ namespace Daybreak.Launch
{
public sealed class Launcher : ExtendedApplication<MainWindow>
{
public static IServiceManager ApplicationServiceManager { get; private set; }
private ILogger logger;
private readonly static Launcher launcher = new();
[STAThread]
@@ -27,7 +27,6 @@ namespace Daybreak.Launch
protected override void SetupServiceManager(IServiceManager serviceManager)
{
ApplicationServiceManager = this.ServiceManager;
ProjectConfiguration.RegisterResolvers(serviceManager);
}
protected override void RegisterServices(IServiceProducer serviceProducer)
@@ -44,17 +43,16 @@ namespace Daybreak.Launch
return false;
}
this.ServiceManager.GetService<ILogger>().LogCritical(e, $"Unhandled exception");
if (e is FatalException fatalException)
{
this.ServiceManager.GetService<ILogger>().LogCritical(e, $"{nameof(FatalException)} encountered. Closing application.");
this.logger.LogCritical(e, $"{nameof(FatalException)} encountered. Closing application");
MessageBox.Show(fatalException.ToString());
File.WriteAllText("crash.log", e.ToString());
return false;
}
else if (e is TargetInvocationException targetInvocationException && e.InnerException is FatalException innerFatalException)
{
this.ServiceManager.GetService<ILogger>().LogCritical(e, $"{nameof(FatalException)} encountered. Closing application.");
this.logger.LogCritical(e, $"{nameof(FatalException)} encountered. Closing application");
MessageBox.Show(innerFatalException.ToString());
File.WriteAllText("crash.log", e.ToString());
return false;
@@ -66,18 +64,30 @@ namespace Daybreak.Launch
{
/*
* Ignore exception caused by browser failing to initialize due to missing window.
* Likely caused by switching windows before browser was initialized.
* Likely caused by switching views before browser was initialized.
*/
this.logger.LogError(e, "Failed to initialize browser");
return true;
}
}
else if (e.Message.Contains("Invalid window handle.") && e.StackTrace.Contains("CoreWebView2Environment.CreateCoreWebView2ControllerAsync"))
{
/*
* Ignore exception caused by browser failing to initialize due to missing window.
* Likely caused by switching views before the browser was initialized.
*/
this.logger.LogError(e, "Failed to initialize browser");
return true;
}
this.logger.LogError(e, $"Unhandled exception caught {e.GetType()}");
MessageBox.Show(e.ToString());
return true;
}
protected override void ApplicationStarting()
{
this.ServiceManager.GetService<IApplicationLifetimeManager>().OnStartup();
this.logger = this.ServiceManager.GetService<ILogger<Launcher>>();
this.RegisterViewContainer();
}
protected override void ApplicationClosing()
+15
View File
@@ -0,0 +1,15 @@
using Microsoft.Extensions.Logging;
using System;
namespace Daybreak.Models
{
public sealed class Log
{
public string Message { get; set; }
public string Category { get; set; }
public LogLevel LogLevel { get; set; }
public string CorrelationVector { get; set; }
public string EventId { get; set; }
public DateTime LogTime { get; set; }
}
}
@@ -1,4 +1,5 @@
using Daybreak.Models.Builds;
using Daybreak.Services.Configuration;
using HtmlAgilityPack;
using Microsoft.Extensions.Logging;
using System;
@@ -15,20 +16,48 @@ namespace Daybreak.Services.IconRetrieve
private const string NamePlaceholder = "[SKILLNAME]";
private const string BaseUrl = "https://wiki.guildwars.com";
private const string QueryUrl = $"wiki/File:{NamePlaceholder}.jpg";
private const string IconsDirectoryName = "Icons";
private const string IconsLocation = $"{IconsDirectoryName}/{NamePlaceholder}.jpg";
private readonly IHttpClient<IconRetriever> httpClient;
private readonly ILogger<IconRetriever> logger;
private readonly IConfigurationManager configurationManager;
public IconRetriever(
ILogger<IconRetriever> logger,
IHttpClient<IconRetriever> httpClient)
IHttpClient<IconRetriever> httpClient,
IConfigurationManager configurationManager)
{
this.logger = logger.ThrowIfNull(nameof(logger));
this.httpClient = httpClient.ThrowIfNull(nameof(httpClient));
this.configurationManager = configurationManager.ThrowIfNull(nameof(configurationManager));
this.httpClient.BaseAddress = new Uri(BaseUrl);
if (Directory.Exists(IconsDirectoryName) is false)
{
Directory.CreateDirectory(IconsDirectoryName);
}
}
public async Task<Optional<Stream>> GetIcon(Skill skill)
{
if (this.configurationManager.GetConfiguration().KeepLocalIconCache)
{
this.logger.LogInformation($"{nameof(IconRetriever)} configured to look first in cache before downloading icons");
var maybeIcon = await this.GetLocalIcon(skill);
if (maybeIcon.ExtractValue() is Stream stream)
{
return stream;
}
}
else
{
this.logger.LogInformation($"{nameof(IconRetriever)} configured to skip local cache. Downloading icon");
}
return await this.DownloadIcon(skill);
}
private async Task<Optional<Stream>> DownloadIcon(Skill skill)
{
var curedSkillName = skill.Name
.Replace(" ", "_");
@@ -56,13 +85,42 @@ namespace Daybreak.Services.IconRetrieve
if (response.IsSuccessStatusCode)
{
this.logger.LogInformation("Retrieved latest icon stream");
return new MemoryStream(await iconResponse.Content.ReadAsByteArrayAsync());
var iconData = await iconResponse.Content.ReadAsByteArrayAsync();
if (this.configurationManager.GetConfiguration().KeepLocalIconCache)
{
await this.SaveIconLocally(skill, iconData);
}
return new MemoryStream(iconData);
}
this.logger.LogError($"Failed to retrieve icon from {BaseUrl + "/" + url}");
return Optional.None<Stream>();
}
private async Task<Optional<Stream>> GetLocalIcon(Skill skill)
{
var curedSkillName = skill.Name
.Replace(" ", "_")
.Replace("\"", "");
this.logger.LogInformation("Checking local icon cache");
if (File.Exists(IconsLocation.Replace(NamePlaceholder, curedSkillName)))
{
this.logger.LogInformation("Local icon cache found. Retrieving icon");
return new MemoryStream(await File.ReadAllBytesAsync(IconsLocation.Replace(NamePlaceholder, curedSkillName)));
}
this.logger.LogWarning("No local icon cache found");
return Optional.None<Stream>();
}
private async Task SaveIconLocally(Skill skill, byte[] data)
{
var curedSkillName = skill.Name
.Replace(" ", "_")
.Replace("\"", "");
await File.WriteAllBytesAsync(IconsLocation.Replace(NamePlaceholder, curedSkillName), data);
}
private static string GetHref(HtmlDocument doc)
{
foreach (var child in doc.DocumentNode.Descendants("a"))
+5 -2
View File
@@ -1,11 +1,14 @@
using System.Collections.Generic;
using Daybreak.Models;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using WpfExtended.Logging;
using WpfExtended.Models;
namespace Daybreak.Services.Logging
{
public interface ILogsManager : ILogsWriter
{
IEnumerable<Log> GetLogs(Expression<Func<Log, bool>> filter);
IEnumerable<Log> GetLogs();
int DeleteLogs();
}
+20 -4
View File
@@ -1,6 +1,8 @@
using LiteDB;
using System;
using System.Collections.Generic;
using System.Extensions;
using System.Linq.Expressions;
using WpfExtended.Models;
namespace Daybreak.Services.Logging
@@ -14,17 +16,31 @@ namespace Daybreak.Services.Logging
this.liteDatabase = liteDatabase.ThrowIfNull(nameof(liteDatabase));
}
public IEnumerable<Log> GetLogs()
public IEnumerable<Models.Log> GetLogs(Expression<Func<Models.Log, bool>> filter)
{
return this.liteDatabase.GetCollection<Log>().FindAll();
return this.liteDatabase.GetCollection<Models.Log>().Find(filter);
}
public IEnumerable<Models.Log> GetLogs()
{
return this.liteDatabase.GetCollection<Models.Log>().FindAll();
}
public void WriteLog(Log log)
{
this.liteDatabase.GetCollection<Log>().Insert(log);
var dbLog = new Models.Log
{
EventId = log.EventId,
Message = log.Exception is null ? log.Message : $"{log.Message}{Environment.NewLine}{log.Exception}",
Category = log.Category,
LogLevel = log.LogLevel,
LogTime = log.LogTime,
CorrelationVector = log.CorrelationVector
};
this.liteDatabase.GetCollection<Models.Log>().Insert(dbLog);
}
public int DeleteLogs()
{
return this.liteDatabase.GetCollection<Log>().DeleteAll();
return this.liteDatabase.GetCollection<Models.Log>().DeleteAll();
}
}
}
+3 -3
View File
@@ -43,10 +43,10 @@
</Grid.ColumnDefinitions>
<TextBlock Text="Code: " Foreground="White" Background="Transparent" FontSize="16"></TextBlock>
<TextBox Grid.Column="1" Foreground="White" Background="Transparent" FontSize="16"
Text="{Binding ElementName=_this, Path=CurrentBuildCode, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
KeyDown="BuildCodeTextBox_KeyDown"></TextBox>
Text="{Binding ElementName=_this, Path=CurrentBuildCode, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></TextBox>
</Grid>
<controls:BuildTemplate x:Name="BuildTemplate" Grid.Row="2" DataContext="{Binding ElementName=_this, Path=CurrentBuild, Mode=OneWay}">
<controls:BuildTemplate x:Name="BuildTemplate" Grid.Row="2" DataContext="{Binding ElementName=_this, Path=CurrentBuild, Mode=OneWay}"
BuildChanged="BuildTemplate_BuildChanged">
</controls:BuildTemplate>
</Grid>
</UserControl>
+29 -7
View File
@@ -22,6 +22,8 @@ namespace Daybreak.Views
{
private const string DisallowedChars = "\r\n\\/.";
private bool supressDecode = false;
private readonly IViewManager viewManager;
private readonly IBuildTemplateManager buildTemplateManager;
private readonly ILogger<BuildTemplateView> logger;
@@ -57,28 +59,48 @@ namespace Daybreak.Views
};
}
private void BuildCodeTextBox_KeyDown(object sender, KeyEventArgs e)
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
if (e.Key == Key.Enter)
base.OnPropertyChanged(e);
if (e.Property == CurrentBuildCodeProperty && this.supressDecode is false)
{
this.logger.LogInformation($"Attempting to decode provided template {sender.As<TextBox>().Text}");
this.logger.LogInformation($"Attempting to decode provided template {this.CurrentBuildCode}");
try
{
this.CurrentBuild = new BuildEntry
{
Name = this.CurrentBuild.Name,
PreviousName = this.CurrentBuild.PreviousName,
Build = this.buildTemplateManager.DecodeTemplate(sender.As<TextBox>().Text)
Build = this.buildTemplateManager.DecodeTemplate(this.CurrentBuildCode)
};
this.logger.LogInformation($"Template {sender.As<TextBox>().Text} decoded");
this.logger.LogInformation($"Template {CurrentBuildCode} decoded");
}
catch (Exception ex)
catch
{
throw new InvalidOperationException($"Failed to decode template {sender.As<TextBox>().Text}", ex);
this.logger.LogWarning($"Failed to decode {this.CurrentBuildCode}. Reverting to default build");
this.CurrentBuild = new BuildEntry
{
Name = this.CurrentBuild.Name,
PreviousName = this.CurrentBuild.PreviousName,
Build = new Build()
};
}
}
}
private void BuildTemplate_BuildChanged(object sender, EventArgs e)
{
try
{
this.supressDecode = true;
this.CurrentBuildCode = this.buildTemplateManager.EncodeTemplate(this.CurrentBuild.Build);
}
finally
{
this.supressDecode = false;
}
}
private void BackButton_Clicked(object sender, EventArgs e)
{
this.viewManager.ShowView<BuildsListView>();
+13 -1
View File
@@ -24,6 +24,12 @@
Clicked="BinButton_Clicked"></controls:BinButton>
<controls:RefreshGlyph Foreground="White" Height="30" Width="30" HorizontalAlignment="Right" Margin="0, 5, 45, 5"
Clicked="RefreshGlyph_Clicked"></controls:RefreshGlyph>
<controls:BackButton Foreground="White" Height="30" Width="30" HorizontalAlignment="Right" Margin="0, 5, 85, 5"
Clicked="ExportButton_Clicked">
<controls:BackButton.RenderTransform>
<RotateTransform Angle="270" CenterX="15" CenterY="15"></RotateTransform>
</controls:BackButton.RenderTransform>
</controls:BackButton>
<DataGrid IsReadOnly="True" Background="Transparent" Foreground="White" Grid.Row="1"
ItemsSource="{Binding ElementName=_this, Path=Logs, Mode=OneWay}" HorizontalScrollBarVisibility="Disabled"
AutoGenerateColumns="False" HeadersVisibility="Column" EnableColumnVirtualization="True"
@@ -54,7 +60,13 @@
<DataGridTextColumn IsReadOnly="True" Header="Category" Binding="{Binding Category}" ElementStyle="{StaticResource WrapText}" Width="auto"/>
<DataGridTextColumn IsReadOnly="True" Header="LogLevel" Binding="{Binding LogLevel}" ElementStyle="{StaticResource WrapText}" Width="auto"/>
<DataGridTextColumn IsReadOnly="True" Header="EventId" Binding="{Binding EventId}" ElementStyle="{StaticResource WrapText}" Width="auto"/>
<DataGridTextColumn IsReadOnly="True" Header="Message" Binding="{Binding Message}" ElementStyle="{StaticResource WrapText}" Width="*"/>
<DataGridTemplateColumn IsReadOnly="True" Header="Message" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<controls:LogMessageTemplate Message="{Binding Message}" Foreground="White"></controls:LogMessageTemplate>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
+34 -4
View File
@@ -1,10 +1,15 @@
using Daybreak.Services.Logging;
using Daybreak.Models;
using Daybreak.Services.Logging;
using Daybreak.Services.ViewManagement;
using Daybreak.Utils;
using Microsoft.Extensions.Logging;
using Microsoft.Win32;
using System;
using System.Collections.ObjectModel;
using System.Extensions;
using System.IO;
using System.Linq;
using System.Windows.Controls;
using WpfExtended.Models;
namespace Daybreak.Views
{
@@ -15,22 +20,47 @@ namespace Daybreak.Views
{
private readonly IViewManager viewManager;
private readonly ILogsManager logManager;
private readonly ILogger<LogsView> logger;
public ObservableCollection<Log> Logs { get; } = new ObservableCollection<Log>();
public LogsView(
IViewManager viewManager,
ILogsManager logManager)
ILogsManager logManager,
ILogger<LogsView> logger)
{
this.logManager = logManager.ThrowIfNull(nameof(logManager));
this.viewManager = viewManager.ThrowIfNull(nameof(viewManager));
this.logger = logger.ThrowIfNull(nameof(logger));
this.InitializeComponent();
this.UpdateLogs();
}
private void UpdateLogs()
{
this.Logs.ClearAnd().AddRange(this.logManager.GetLogs());
this.Logs.ClearAnd().AddRange(this.logManager.GetLogs(l => l.LogLevel < Microsoft.Extensions.Logging.LogLevel.Trace));
}
private async void ExportButton_Clicked(object sender, EventArgs e)
{
this.logger.LogInformation("Exporting logs");
var saveFileDialog = new SaveFileDialog
{
DefaultExt = "json",
Filter = "Json files (*.json)|*.json",
Title = "Export logs",
ValidateNames = true,
CreatePrompt = true
};
if (saveFileDialog.ShowDialog() is true)
{
var fileName = saveFileDialog.FileName;
this.logger.LogInformation($"Exporting to {fileName}");
await File.WriteAllTextAsync(fileName, this.logManager.GetLogs().ToList().Serialize());
}
else
{
this.logger.LogInformation("Exporting canceled");
}
}
private void BackButton_Clicked(object sender, EventArgs e)
{
+3
View File
@@ -94,6 +94,7 @@
<TextBlock Text="Desired screen id: " FontSize="22" Foreground="White" Height="30"></TextBlock>
<TextBlock Text="Place Shortcut: " FontSize="22" Foreground="White" Height="30"></TextBlock>
<TextBlock Text="Shortcut folder: " FontSize="22" Foreground="White" Height="30"></TextBlock>
<TextBlock Text="Keep local cache of icons: " FontSize="22" Foreground="White" Height="30"></TextBlock>
</StackPanel>
<StackPanel Orientation="Vertical" Grid.Row="1" Grid.Column="1">
<ToggleButton HorizontalAlignment="Center" HorizontalContentAlignment="Stretch" Style="{StaticResource AnimatedSwitch}" Height="30" Width="40"
@@ -148,6 +149,8 @@
Foreground="White" BorderBrush="Gray" BorderThickness="0"
Clicked="ShortcutFolderPickerGlyph_Clicked"></controls:FilePickerGlyph>
</Grid>
<ToggleButton HorizontalAlignment="Center" HorizontalContentAlignment="Stretch" Style="{StaticResource AnimatedSwitch}" Height="30" Width="40"
FontSize="22" Foreground="White" IsChecked="{Binding ElementName=_this, Path=KeepLocalIconCache, Mode=TwoWay}"></ToggleButton>
</StackPanel>
</Grid>
</ScrollViewer>
+4
View File
@@ -45,6 +45,8 @@ namespace Daybreak.Views
private bool shortcutPlaced;
[GenerateDependencyProperty]
private bool autoCheckUpdate;
[GenerateDependencyProperty]
private bool keepLocalIconCache;
public SettingsView(
IConfigurationManager configurationManager,
@@ -71,6 +73,7 @@ namespace Daybreak.Views
this.ShortcutFolder = config.ShortcutLocation;
this.ShortcutPlaced = config.PlaceShortcut;
this.AutoCheckUpdate = config.AutoCheckUpdate;
this.KeepLocalIconCache = config.KeepLocalIconCache;
}
private void SaveButton_Clicked(object sender, EventArgs e)
@@ -88,6 +91,7 @@ namespace Daybreak.Views
currentConfig.ShortcutLocation = this.ShortcutFolder;
currentConfig.PlaceShortcut = this.ShortcutPlaced;
currentConfig.AutoCheckUpdate = this.AutoCheckUpdate;
currentConfig.KeepLocalIconCache = this.KeepLocalIconCache;
this.configurationManager.SaveConfiguration(currentConfig);
this.viewManager.ShowView<SettingsCategoryView>();
}