Compare commits

...
8 Commits
Author SHA1 Message Date
Alexandru Macocian 98bd1b2de6 Periodically check for updates.
Reorder settings in the settings category view.
2021-04-14 15:15:56 +02:00
Alexandru Macocian c169ca1684 Menu to manage guildwars executables. 2021-04-14 15:01:43 +02:00
Alexandru Macocian 88214ea166 Darken views with text to improve readability.
Better define the reason why guildwars failed to launch.
Auto set to default when adding first account.
Auto set another default when removing the default account.
2021-04-14 14:12:38 +02:00
Alexandru Macocian 4bdcd1a811 Changed version control to check all subversions. 2021-04-14 13:50:15 +02:00
Alexandru Macocian fa4f665a3e Fixed a bug with updating account details. 2021-04-13 21:28:49 +02:00
Alexandru Macocian e59e022c0a Updated to 0.5.0 2021-04-13 21:13:38 +02:00
Alexandru Macocian d096dc696a Multi-account management.
Split settings into multiple categories.
2021-04-13 21:09:41 +02:00
Alexandru Macocian 071007c3e5 Create application manifest.
Require highest available rights.
Return dialog message when registry is failed to be set.
2021-04-12 19:35:08 +02:00
52 changed files with 1784 additions and 198 deletions
+79
View File
@@ -0,0 +1,79 @@
using System;
using System.ComponentModel;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interactivity;
using System.Windows.Media;
namespace Daybreak.Behaviors
{
public class ScaleFontWithSize : Behavior<TextBlock>
{
public static readonly DependencyProperty MaxFontSizeProperty = DependencyProperty.Register("MaxFontSize", typeof(double), typeof(ScaleFontWithSize), new PropertyMetadata(12d));
public double MaxFontSize
{
get
{
return (double)this.GetValue(MaxFontSizeProperty);
}
set
{
this.SetValue(MaxFontSizeProperty, value);
}
}
protected override void OnAttached()
{
base.OnAttached();
this.AssociatedObject.SizeChanged += (_, __) => this.CalculateFontSize();
DependencyPropertyDescriptor.FromProperty(
TextBlock.TextProperty, typeof(TextBlock)).AddValueChanged(this.AssociatedObject, (_, __) => this.CalculateFontSize());
DependencyPropertyDescriptor.FromProperty(
TextBlock.FontSizeProperty, typeof(TextBlock)).AddValueChanged(this.AssociatedObject, (_, __) => this.CalculateFontSize());
}
private void CalculateFontSize()
{
var textMeasurement = this.MeasureText(this.AssociatedObject.FontSize);
var maximumTextMeasurement = this.MeasureText(this.MaxFontSize);
var desiredWidthFontSize = this.MaxFontSize;
var desiredHeightFontSize = this.MaxFontSize;
if (Math.Round(textMeasurement.Height) != Math.Round(this.AssociatedObject.ActualHeight))
{
var scale = this.AssociatedObject.ActualHeight / maximumTextMeasurement.Height;
desiredHeightFontSize = (this.MaxFontSize * scale) - 1;
desiredHeightFontSize = desiredHeightFontSize <= this.MaxFontSize ? desiredHeightFontSize : this.MaxFontSize;
}
if (Math.Round(textMeasurement.Width) != Math.Round(this.AssociatedObject.ActualWidth))
{
var scale = this.AssociatedObject.ActualWidth / maximumTextMeasurement.Width;
desiredWidthFontSize = (this.MaxFontSize * scale) - 1;
desiredWidthFontSize = desiredWidthFontSize <= this.MaxFontSize ? desiredWidthFontSize : this.MaxFontSize;
}
var desiredFontSize = Math.Min(desiredHeightFontSize, desiredWidthFontSize);
if ((int)desiredFontSize != (int)this.AssociatedObject.FontSize && desiredFontSize > 0)
{
this.AssociatedObject.FontSize = desiredFontSize;
return;
}
}
private Size MeasureText(double fontSize)
{
var formattedText = new FormattedText(this.AssociatedObject.Text, CultureInfo.CurrentUICulture,
FlowDirection.LeftToRight,
new Typeface(this.AssociatedObject.FontFamily, this.AssociatedObject.FontStyle, this.AssociatedObject.FontWeight, this.AssociatedObject.FontStretch),
fontSize, Brushes.Black, VisualTreeHelper.GetDpi(this.AssociatedObject).PixelsPerDip);
return new Size(formattedText.Width, formattedText.Height);
}
}
}
@@ -1,23 +1,21 @@
using Newtonsoft.Json;
using Daybreak.Models;
using Newtonsoft.Json;
using System.Collections.Generic;
namespace Daybreak.Configuration
{
public sealed class ApplicationConfiguration
{
[JsonProperty("GamePath")]
public string GamePath { get; set; }
[JsonProperty("ToolboxPath")]
public string ToolboxPath { get; set; }
[JsonProperty("CharacterName")]
public string CharacterName { get; set; }
[JsonProperty("LeftBrowserDefault")]
public string LeftBrowserDefault { get; set; }
[JsonProperty("RightBrowserDefault")]
public string RightBrowserDefault { get; set; }
[JsonProperty("ProtectedUsername")]
public string ProtectedUsername { get; set; }
[JsonProperty("ProtectedPassword")]
public string ProtectedPassword { get; set; }
[JsonProperty("GuildwarsPaths")]
public List<GuildwarsPath> GuildwarsPaths { get; set; } = new();
[JsonProperty("ProtectedLoginCredentials")]
public List<ProtectedLoginCredentials> ProtectedLoginCredentials { get; set; } = new();
[JsonProperty("AddressBarReadonly")]
public bool AddressBarReadonly { get; set; } = true;
[JsonProperty("ExperimentalFeatures")]
@@ -1,4 +1,4 @@
using Daybreak.Services.ApplicationDetection;
using Daybreak.Services.ApplicationLauncher;
using Daybreak.Services.ApplicationLifetime;
using Daybreak.Services.Bloogum;
using Daybreak.Services.Configuration;
@@ -9,7 +9,6 @@ using Daybreak.Services.Screenshots;
using Daybreak.Services.Updater;
using Daybreak.Services.ViewManagement;
using Daybreak.Views;
using Microsoft.Web.WebView2.Core;
using Slim;
using System.Extensions;
@@ -27,7 +26,7 @@ namespace Daybreak.Configuration
serviceProducer.RegisterSingleton<ILogger, Logger>();
serviceProducer.RegisterSingleton<ApplicationLifetimeManager>();
serviceProducer.RegisterSingleton<ViewManager>();
serviceProducer.RegisterSingleton<IApplicationDetector, ApplicationDetector>();
serviceProducer.RegisterSingleton<IApplicationLauncher, ApplicationLauncher>();
serviceProducer.RegisterSingleton<IScreenshotProvider, ScreenshotProvider>();
serviceProducer.RegisterSingleton<IConfigurationManager, ConfigurationManager>();
serviceProducer.RegisterSingleton<IBloogumClient, BloogumClient>();
@@ -50,6 +49,10 @@ namespace Daybreak.Configuration
viewProducer.RegisterView<SettingsView>();
viewProducer.RegisterView<AskUpdateView>();
viewProducer.RegisterView<UpdateView>();
viewProducer.RegisterView<SettingsCategoryView>();
viewProducer.RegisterView<AccountsView>();
viewProducer.RegisterView<ExperimentalSettingsView>();
viewProducer.RegisterView<ExecutablesView>();
}
}
}
+49
View File
@@ -0,0 +1,49 @@
<UserControl x:Class="Daybreak.Controls.AccountTemplate"
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"
xmlns:converters="clr-namespace:Daybreak.Converters"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<ResourceDictionary>
<converters:InverseBooleanConverter x:Key="InverseBooleanConverter"></converters:InverseBooleanConverter>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid HorizontalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock FontSize="16" Text="Username:" Foreground="White" Margin="5" Grid.Row="0" HorizontalAlignment="Right"></TextBlock>
<TextBlock FontSize="16" Text="Password:" Foreground="White" Margin="5" Grid.Row="1" HorizontalAlignment="Right"></TextBlock>
<TextBlock FontSize="16" Text="Character name:" Foreground="White" Margin="5" Grid.Row="2" HorizontalAlignment="Right"></TextBlock>
<TextBox Text="{Binding ElementName=_this, Path=Username, Mode=TwoWay}" Foreground="White" Background="Transparent"
BorderThickness="1" HorizontalAlignment="Stretch" Grid.Row="0" Grid.Column="1"
FontSize="16" TextChanged="UsernameTextbox_TextChanged" Margin="5"></TextBox>
<PasswordBox x:Name="PasswordBox" Foreground="White" Background="Transparent"
BorderThickness="1" HorizontalAlignment="Stretch" Grid.Row="1" Grid.Column="1"
FontSize="16" PasswordChanged="Passwordbox_PasswordChanged" Margin="5"></PasswordBox>
<TextBox Text="{Binding ElementName=_this, Path=CharacterName, Mode=TwoWay}" Foreground="White" Background="Transparent"
BorderThickness="1" HorizontalAlignment="Stretch" Grid.Row="2" Grid.Column="1"
FontSize="16" TextChanged="CharacterNameTextbox_TextChanged" Margin="5"></TextBox>
</Grid>
<local:BinButton Grid.Column="2" Height="30" Width="30" Foreground="White" VerticalAlignment="Top" Margin="5, 15, 5, 5"
Clicked="BinButton_Clicked"></local:BinButton>
<local:StarGlyph Grid.Column="2" Height="30" Width="30" Foreground="White" VerticalAlignment="Top" Margin="5, 55, 5, 5"
Clicked="StarGlyph_Clicked" IsEnabled="{Binding ElementName=_this, Path=IsDefault, Mode=OneWay, Converter={StaticResource InverseBooleanConverter}}"></local:StarGlyph>
</Grid>
</UserControl>
+90
View File
@@ -0,0 +1,90 @@
using Daybreak.Models;
using System;
using System.Extensions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Extensions;
namespace Daybreak.Controls
{
/// <summary>
/// Interaction logic for AccountTemplate.xaml
/// </summary>
public partial class AccountTemplate : UserControl
{
public static readonly DependencyProperty UsernameProperty = DependencyPropertyExtensions.Register<AccountTemplate, string>(nameof(Username));
public static readonly DependencyProperty CharacterNameProperty = DependencyPropertyExtensions.Register<AccountTemplate, string>(nameof(CharacterName));
public static readonly DependencyProperty PasswordProperty = DependencyPropertyExtensions.Register<AccountTemplate, string>(nameof(Password));
public static readonly DependencyProperty IsDefaultProperty = DependencyPropertyExtensions.Register<AccountTemplate, bool>(nameof(IsDefault));
public event EventHandler RemoveClicked;
public event EventHandler DefaultClicked;
public string Username
{
get => this.GetTypedValue<string>(UsernameProperty);
set => this.SetValue(UsernameProperty, value);
}
public string Password
{
get => this.GetTypedValue<string>(PasswordProperty);
set => this.SetValue(PasswordProperty, value);
}
public string CharacterName
{
get => this.GetTypedValue<string>(CharacterNameProperty);
set => this.SetValue(CharacterNameProperty, value);
}
public bool IsDefault
{
get => this.GetTypedValue<bool>(IsDefaultProperty);
set => this.SetValue(IsDefaultProperty, value);
}
public AccountTemplate()
{
this.InitializeComponent();
this.DataContextChanged += AccountTemplate_DataContextChanged;
}
private void AccountTemplate_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue is LoginCredentials loginCredentials)
{
this.PasswordBox.Password = loginCredentials.Password;
this.Username = loginCredentials.Username;
this.CharacterName = loginCredentials.CharacterName;
this.IsDefault = loginCredentials.Default;
}
}
private void BinButton_Clicked(object sender, EventArgs e)
{
this.RemoveClicked?.Invoke(this, e);
}
private void UsernameTextbox_TextChanged(object sender, EventArgs e)
{
this.Username = sender.As<TextBox>()?.Text;
this.DataContext.As<LoginCredentials>().Username = this.Username;
}
private void CharacterNameTextbox_TextChanged(object sender, EventArgs e)
{
this.CharacterName = sender.As<TextBox>()?.Text;
this.DataContext.As<LoginCredentials>().CharacterName = this.CharacterName;
}
private void Passwordbox_PasswordChanged(object sender, EventArgs e)
{
this.Password = sender.As<PasswordBox>()?.Password;
this.DataContext.As<LoginCredentials>().Password = this.Password;
}
private void StarGlyph_Clicked(object sender, EventArgs e)
{
this.DefaultClicked?.Invoke(this, e);
}
}
}
+22
View File
@@ -0,0 +1,22 @@
<UserControl x:Class="Daybreak.Controls.AddButton"
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"
mc:Ignorable="d"
x:Name="_this"
d:DesignHeight="450" d:DesignWidth="800">
<Viewbox>
<Grid>
<Ellipse x:Name="BackgroundEllipse" Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" Visibility="Visible" Opacity="0.1" />
<Path Data="m13,26a13,13 0 1 1 13,-13a13,13 0 0 1 -13,13zm0,-24a11,11 0 1 0 11,11a11,11 0 0 0 -11,-11z"
Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"></Path>
<Path Data="m13,20a1,1 0 0 1 -1,-1l0,-12a1,1 0 0 1 2,0l0,12a1,1 0 0 1 -1,1z"
Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"></Path>
<Path Data="m19,14l-12,0a1,1 0 0 1 0,-2l12,0a1,1 0 0 1 0,2z"
Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"></Path>
<Ellipse Fill="Transparent" MouseEnter="Ellipse_MouseEnter" MouseLeave="Ellipse_MouseLeave" MouseLeftButtonDown="Ellipse_MouseLeftButtonDown"></Ellipse>
</Grid>
</Viewbox>
</UserControl>
+37
View File
@@ -0,0 +1,37 @@
using System;
using System.Windows.Controls;
using System.Windows.Input;
namespace Daybreak.Controls
{
/// <summary>
/// Interaction logic for AddButton.xaml
/// </summary>
public partial class AddButton : UserControl
{
public event EventHandler Clicked;
public AddButton()
{
InitializeComponent();
}
private void Ellipse_MouseEnter(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Opacity = 0.6;
}
private void Ellipse_MouseLeave(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Opacity = 0;
}
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
Clicked?.Invoke(this, e);
}
}
}
}
+18
View File
@@ -0,0 +1,18 @@
<UserControl x:Class="Daybreak.Controls.AvatarGlyph"
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"
mc:Ignorable="d"
x:Name="_this"
d:DesignHeight="450" d:DesignWidth="800">
<Viewbox>
<Grid>
<Path Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
Data="m5.7,104.4c10.6,-10.6 24.6,-16.4 39.6,-16.4s29,5.8 39.6,16.4l5.7,-5.7c-12.1,-12 -28.2,-18.7 -45.3,-18.7s-33.2,6.7 -45.3,18.7l5.7,5.7z"></Path>
<Path Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
Data="m11.3,34c0,18.7 15.3,34 34,34s34,-15.3 34,-34s-15.3,-34 -34,-34s-34,15.3 -34,34zm60,0c0,14.3 -11.7,26 -26,26s-26,-11.7 -26,-26s11.7,-26 26,-26s26,11.7 26,26z"></Path>
</Grid>
</Viewbox>
</UserControl>
+28
View File
@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Daybreak.Controls
{
/// <summary>
/// Interaction logic for AvatarGlyph.xaml
/// </summary>
public partial class AvatarGlyph : UserControl
{
public AvatarGlyph()
{
InitializeComponent();
}
}
}
+30
View File
@@ -0,0 +1,30 @@
<UserControl x:Class="Daybreak.Controls.BinButton"
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"
mc:Ignorable="d"
x:Name="_this"
d:DesignHeight="450" d:DesignWidth="800">
<Viewbox>
<Grid>
<Ellipse x:Name="BackgroundEllipse" Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" Width="80" Height="80" Opacity="0.6"
Visibility="Hidden"></Ellipse>
<Path Data="m40,7l-2,0l0,-5l-18,0l0,5l-2,0l0,-6a1,1 0 0 1 1,-1l20,0a1,1 0 0 1 1,1l0,6z"
Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" Margin="11"></Path>
<Path Data="m58,14l-2,0l0,-3l-54,0l0,3l-2,0l0,-4a1,1 0 0 1 1,-1l56,0a1,1 0 0 1 1,1l0,4z"
Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" Margin="11"></Path>
<Path Data="m51,64l-44,0a1,1 0 0 1 -1,-1l0,-48l2,0l0,47l42,0l0,-47l2,0l0,48a1,1 0 0 1 -1,1z"
Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" Margin="11"></Path>
<Rectangle Margin="38, 32, 0, 0" Width="2" Height="32" Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
VerticalAlignment="Top" HorizontalAlignment="Left"></Rectangle>
<Rectangle Margin="26, 35, 0, 0" Width="2" Height="32" Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
VerticalAlignment="Top" HorizontalAlignment="Left"></Rectangle>
<Rectangle Margin="50, 35, 0, 0" Width="2" Height="32" Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
VerticalAlignment="Top" HorizontalAlignment="Left"></Rectangle>
<Ellipse Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" StrokeThickness="3" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Fill="Transparent"
MouseLeftButtonDown="Ellipse_MouseLeftButtonDown" MouseEnter="Ellipse_MouseEnter" MouseLeave="Ellipse_MouseLeave"></Ellipse>
</Grid>
</Viewbox>
</UserControl>
+36
View File
@@ -0,0 +1,36 @@
using System;
using System.Windows.Controls;
using System.Windows.Input;
namespace Daybreak.Controls
{
/// <summary>
/// Interaction logic for BinButton.xaml
/// </summary>
public partial class BinButton : UserControl
{
public event EventHandler Clicked;
public BinButton()
{
InitializeComponent();
}
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
this.Clicked?.Invoke(this, e);
}
}
private void Ellipse_MouseEnter(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Visibility = System.Windows.Visibility.Visible;
}
private void Ellipse_MouseLeave(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Visibility = System.Windows.Visibility.Hidden;
}
}
}
+14
View File
@@ -0,0 +1,14 @@
<UserControl x:Class="Daybreak.Controls.ExperimentGlyph"
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"
mc:Ignorable="d"
x:Name="_this"
d:DesignHeight="450" d:DesignWidth="800">
<Viewbox>
<Path Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
Data="m23.8,22.5l-7.8,-12.6l0,-7.9l1,0c0.6,0 1,-0.4 1,-1s-0.4,-1 -1,-1l-3,0l0,9.9l3.5,6.1l-11,0l3.5,-6.1l0,-9.9l-3,0c-0.6,0 -1,0.4 -1,1s0.4,1 1,1l1,0l0,7.9l-7.8,12.7c-0.5,0.7 0,1.4 0.8,1.4l22,0c0.8,0 1.3,-0.5 0.8,-1.5zm-20.8,-0.5l2.9,-5l12.2,0l2.9,5l-18,0z"></Path>
</Viewbox>
</UserControl>
+28
View File
@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Daybreak.Controls
{
/// <summary>
/// Interaction logic for ExperimentGlyph.xaml
/// </summary>
public partial class ExperimentGlyph : UserControl
{
public ExperimentGlyph()
{
InitializeComponent();
}
}
}
+14
View File
@@ -0,0 +1,14 @@
<UserControl x:Class="Daybreak.Controls.FileGlyph"
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"
mc:Ignorable="d"
x:Name="_this"
d:DesignHeight="450" d:DesignWidth="800">
<Viewbox>
<Path Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
Data="m52,0l-40,0c-6.627,0 -12,5.373 -12,12l0,72c0,6.627 5.373,12 12,12l55.875,0c6.627,0 12.125,-5.373 12.125,-12l0,-56c-4,-4 -22,-22 -28,-28zm0,11.178l16.709,16.822l-16.709,0l0,-16.822zm15.875,76.822l-55.875,0c-2.206,0 -4,-1.794 -4,-4l0,-72c0,-2.206 1.794,-4 4,-4l32,0l0,20l0,8l8,0l20,0l0,48c0,2.168 -1.889,4 -4.125,4z"></Path>
</Viewbox>
</UserControl>
+15
View File
@@ -0,0 +1,15 @@
using System.Windows.Controls;
namespace Daybreak.Controls
{
/// <summary>
/// Interaction logic for FileGlyph.xaml
/// </summary>
public partial class FileGlyph : UserControl
{
public FileGlyph()
{
InitializeComponent();
}
}
}
+11 -8
View File
@@ -8,14 +8,17 @@
x:Name="_this"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<Rectangle x:Name="BackgroundEllipse" Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" Visibility="Visible" Opacity="0.1" />
<Viewbox>
<StackPanel Orientation="Horizontal">
<Ellipse Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" Height="1" Width="1"></Ellipse>
<Ellipse Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" Height="1" Width="1"></Ellipse>
<Ellipse Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" Height="1" Width="1"></Ellipse>
</StackPanel>
<Ellipse x:Name="BackgroundEllipse" Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" Visibility="Visible" Opacity="0.1" />
<Viewbox Stretch="Fill">
<Grid>
<Ellipse Height="4" Width="4" StrokeThickness="0.2" Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"></Ellipse>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Ellipse Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" Height="1" Width="1"></Ellipse>
<Ellipse Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" Height="1" Width="1"></Ellipse>
<Ellipse Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" Height="1" Width="1"></Ellipse>
</StackPanel>
</Grid>
</Viewbox>
<Rectangle Fill="Transparent" MouseEnter="Ellipse_MouseEnter" MouseLeave="Ellipse_MouseLeave" MouseLeftButtonDown="Ellipse_MouseLeftButtonDown"></Rectangle>
<Ellipse Fill="Transparent" MouseEnter="Ellipse_MouseEnter" MouseLeave="Ellipse_MouseLeave" MouseLeftButtonDown="Ellipse_MouseLeftButtonDown"></Ellipse>
</Grid>
</UserControl>
+19
View File
@@ -0,0 +1,19 @@
<UserControl x:Class="Daybreak.Controls.GoldenArrowGlyph"
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"
mc:Ignorable="d"
x:Name="_this"
d:DesignHeight="450" d:DesignWidth="800">
<Viewbox>
<Grid>
<Grid.RenderTransform>
<RotateTransform Angle="180" CenterX="900" CenterY="595"></RotateTransform>
</Grid.RenderTransform>
<Path Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
Data="m771.53119,1071.05017c-81,-64 -151,-120 -154,-126c-4,-5 -15,-7 -25,-3c-11,4 -77,12 -149,16c-146,10 -203,26 -326,92c-63,35 -82,41 -96,32c-22,-13 -28,-55 -14,-95c7,-20 7,-39 -1,-60c-8,-25 -7,-38 5,-65c9,-19 21,-34 27,-34c5,0 10,-15 10,-34c0,-49 32,-75 83,-67c4,0 7,-10 7,-24c0,-31 41,-75 70,-75c11,0 20,-6 20,-14c0,-41 73,-60 136,-36c23,9 30,7 50,-15c13,-14 27,-25 32,-25c5,0 14,-11 20,-25c6,-14 17,-25 23,-25c7,0 22,-10 34,-22c12,-13 38,-36 58,-53c34,-28 37,-34 38,-90l1,-60l149,-133c82,-74 154,-132 160,-130c6,2 73,62 149,133l138,130l1,60c1,56 4,62 38,90c20,17 46,40 58,53c12,12 27,22 34,22c6,0 17,11 23,25c6,14 15,25 20,25c5,0 19,11 32,25c20,22 27,24 50,15c63,-24 136,-5 136,36c0,8 8,14 19,14c32,0 71,39 71,71c0,16 3,28 8,28c50,-8 82,18 82,67c0,19 4,34 9,34c5,0 16,16 26,36c13,27 14,42 6,65c-7,20 -7,38 0,58c14,40 8,82 -14,95c-14,9 -33,3 -96,-32c-123,-66 -180,-82 -326,-92c-71,-4 -138,-11 -148,-15c-11,-5 -22,-2 -30,7c-7,9 -76,65 -154,126l-141,111l-149,-116zm277,-45c99,-78 119,-97 119,-120c1,-32 1,-32 78,-14c32,8 114,19 183,25c134,11 208,31 297,81c61,35 63,35 63,15c0,-8 -12,-22 -26,-31l-25,-17l25,-24c14,-13 26,-30 26,-38c0,-19 -27,-44 -56,-51c-24,-6 -24,-7 -9,-31c27,-40 13,-55 -44,-47l-50,6l11,-35c23,-76 -11,-87 -77,-26c-25,23 -48,39 -51,36c-3,-3 6,-27 20,-53c14,-27 26,-57 26,-68c0,-16 -6,-18 -41,-13c-22,3 -58,17 -80,31c-21,14 -41,26 -44,26c-3,0 -5,-20 -5,-45c0,-42 -2,-45 -19,-35c-32,16 -41,12 -41,-20c0,-36 -13,-38 -34,-8c-15,22 -16,21 -16,-27c0,-47 -1,-48 -17,-32c-17,17 -18,16 -28,-24c-6,-24 -17,-45 -24,-47c-11,-4 -12,5 -5,44c15,83 11,140 -11,164c-13,14 -18,33 -16,55c8,101 -156,220 -241,174c-14,-8 -23,-8 -31,0c-15,15 -61,14 -101,-3c-74,-31 -155,-132 -142,-179c3,-13 -2,-29 -13,-42c-26,-28 -32,-84 -17,-150c13,-52 8,-74 -13,-61c-5,4 -12,24 -16,47c-7,39 -8,40 -26,23c-18,-17 -19,-16 -19,32c0,47 -1,48 -16,26c-21,-30 -34,-28 -34,8c0,32 -9,36 -41,20c-17,-10 -19,-7 -19,35c0,25 -2,45 -5,45c-3,0 -23,-12 -44,-26c-22,-14 -58,-28 -80,-31c-35,-5 -41,-3 -41,13c0,11 12,41 26,68c14,26 23,50 20,53c-3,3 -26,-13 -51,-36c-66,-61 -100,-50 -77,26l11,35l-43,-6c-23,-4 -50,-4 -60,0c-15,6 -15,9 3,39l19,33l-26,7c-59,15 -69,55 -25,91c27,21 27,23 8,30c-24,9 -35,23 -35,46c0,14 10,11 57,-17c92,-53 173,-76 313,-87c69,-5 150,-15 181,-23c72,-19 69,-20 69,13c1,23 20,42 118,119c64,50 123,92 130,92c7,1 66,-41 132,-91zm-149,-229c7,-21 15,-39 19,-39c4,0 14,18 23,40c13,34 20,40 45,40c37,0 108,-52 135,-98l19,-32l-31,-31c-17,-17 -31,-32 -31,-34c0,-1 17,-6 37,-10c45,-8 53,-18 53,-66c0,-68 -45,-159 -78,-159c-9,1 -32,14 -51,30c-19,16 -36,28 -37,27c-2,-2 4,-27 13,-56c13,-47 13,-55 0,-68c-22,-23 -91,-34 -139,-24c-59,14 -69,31 -52,86c15,51 7,56 -33,25c-14,-11 -31,-20 -38,-20c-20,0 -52,43 -69,93c-29,88 -18,121 45,131l42,7l-34,35l-33,34l19,36c20,37 84,88 120,96c32,7 44,-2 56,-43zm-154,-439c11,0 23,-11 29,-28c32,-85 252,-85 292,1c7,15 21,27 31,27c10,0 30,9 45,21l26,20l0,-55l0,-56l-106,-102c-58,-57 -114,-108 -124,-115c-14,-10 -34,3 -143,100l-127,112l0,67l0,66l29,-29c16,-16 38,-29 48,-29z" />
</Grid>
</Viewbox>
</UserControl>
@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Daybreak.Controls
{
/// <summary>
/// Interaction logic for GoldenArrowGlyph.xaml
/// </summary>
public partial class GoldenArrowGlyph : UserControl
{
public GoldenArrowGlyph()
{
InitializeComponent();
}
}
}
@@ -0,0 +1,43 @@
<UserControl x:Class="Daybreak.Controls.GuildwarsPathTemplate"
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:converters="clr-namespace:Daybreak.Converters"
xmlns:local="clr-namespace:Daybreak.Controls"
mc:Ignorable="d"
x:Name="_this"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<ResourceDictionary>
<converters:InverseBooleanConverter x:Key="InverseBooleanConverter"></converters:InverseBooleanConverter>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid HorizontalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="auto"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock FontSize="22" Text="Path:" Foreground="White" Margin="5" Grid.Row="0" HorizontalAlignment="Right"></TextBlock>
<TextBox Foreground="White" Background="Transparent" Text="{Binding ElementName=_this, Path=Path, Mode=TwoWay}"
BorderThickness="1" HorizontalAlignment="Stretch" Grid.Row="0" Grid.Column="1"
FontSize="22" TextChanged="TextBox_TextChanged" Margin="5"></TextBox>
</Grid>
<WrapPanel Grid.Column="1">
<local:FilePickerGlyph Width="30" Height="30" Foreground="White" VerticalAlignment="Top" Margin="5"
Clicked="FilePickerGlyph_Clicked"></local:FilePickerGlyph>
<local:BinButton Grid.Column="2" Height="30" Width="30" Foreground="White" VerticalAlignment="Top" Margin="5"
Clicked="BinButton_Clicked"></local:BinButton>
<local:StarGlyph Grid.Column="2" Height="30" Width="30" Foreground="White" VerticalAlignment="Top" Margin="5"
Clicked="StarGlyph_Clicked" IsEnabled="{Binding ElementName=_this, Path=IsDefault, Mode=OneWay, Converter={StaticResource InverseBooleanConverter}}"></local:StarGlyph>
</WrapPanel>
</Grid>
</UserControl>
@@ -0,0 +1,80 @@
using Daybreak.Models;
using Microsoft.Win32;
using System;
using System.Extensions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Extensions;
namespace Daybreak.Controls
{
/// <summary>
/// Interaction logic for GuildwarsPathTemplate.xaml
/// </summary>
public partial class GuildwarsPathTemplate : UserControl
{
public static readonly DependencyProperty PathProperty = DependencyPropertyExtensions.Register<GuildwarsPathTemplate, string>(nameof(Path));
public static readonly DependencyProperty IsDefaultProperty = DependencyPropertyExtensions.Register<GuildwarsPathTemplate, bool>(nameof(IsDefault));
public event EventHandler RemoveClicked;
public event EventHandler DefaultClicked;
public string Path
{
get => this.GetTypedValue<string>(PathProperty);
set => this.SetValue(PathProperty, value);
}
public bool IsDefault
{
get => this.GetTypedValue<bool>(IsDefaultProperty);
set => this.SetValue(IsDefaultProperty, value);
}
public GuildwarsPathTemplate()
{
this.InitializeComponent();
this.DataContextChanged += GuildwarsPathTemplate_DataContextChanged;
}
private void GuildwarsPathTemplate_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue is GuildwarsPath guildwarsPath)
{
this.IsDefault = guildwarsPath.Default;
this.Path = guildwarsPath.Path;
}
}
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
this.Path = sender.As<TextBox>()?.Text;
this.DataContext.As<GuildwarsPath>().Path = this.Path;
}
private void StarGlyph_Clicked(object sender, EventArgs e)
{
this.DefaultClicked?.Invoke(this, e);
}
private void BinButton_Clicked(object sender, EventArgs e)
{
this.RemoveClicked?.Invoke(this, e);
}
private void FilePickerGlyph_Clicked(object sender, EventArgs e)
{
var filePicker = new OpenFileDialog()
{
CheckFileExists = true,
CheckPathExists = true,
DefaultExt = "exe",
Multiselect = false
};
if (filePicker.ShowDialog() is true)
{
this.Path = filePicker.FileName;
this.DataContext.As<GuildwarsPath>().Path = filePicker.FileName;
}
}
}
}
+1 -1
View File
@@ -21,7 +21,7 @@
VerticalAlignment="Top" HorizontalAlignment="Left" StrokeThickness="3" Width="47.25" Height="3" />
<Rectangle Stroke="{Binding ElementName=_this, Path=Foreground}" Margin="39.375, 85.625, 0, 0"
VerticalAlignment="Top" HorizontalAlignment="Left" StrokeThickness="3" Width="47.25" Height="3" />
<Ellipse Stroke="{Binding ElementName=_this, Path=Foreground}" Width="128" Height="128" StrokeThickness="5" Fill="Transparent"
<Ellipse Stroke="{Binding ElementName=_this, Path=Foreground}" Width="128" Height="128" StrokeThickness="8" Fill="Transparent"
MouseEnter="Ellipse_MouseEnter" MouseLeave="Ellipse_MouseLeave" MouseLeftButtonDown="Ellipse_MouseLeftButtonDown"></Ellipse>
</Grid>
</Viewbox>
+45
View File
@@ -0,0 +1,45 @@
<UserControl x:Class="Daybreak.Controls.TileButton"
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"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:behaviors="clr-namespace:Daybreak.Behaviors"
xmlns:converters="clr-namespace:Daybreak.Converters"
x:Name="_this"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<converters:TileButtonHighlightConverter x:Key="HighlightConverter"></converters:TileButtonHighlightConverter>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
</Grid.RowDefinitions>
<ContentPresenter x:Name="Content" Margin="5"
Content="{Binding ElementName=_this, Path=InnerContent}"></ContentPresenter>
<Border BorderBrush="{Binding ElementName=_this, Path=BorderBrush}"
BorderThickness="{Binding ElementName=_this, Path=BorderThickness}"
Opacity="{Binding ElementName=_this, Path=Highlighted, Converter={StaticResource HighlightConverter}}"
Grid.RowSpan="2">
</Border>
<TextBlock Grid.Row="1" Text="{Binding ElementName=_this, Path=Title}"
FontSize="{Binding ElementName=_this, Path=FontSize}"
FontFamily="{Binding ElementName=_this, Path=FontFamily}"
Foreground="{Binding ElementName=_this, Path=Foreground}"
VerticalAlignment="Center" HorizontalAlignment="Stretch" TextWrapping="Wrap"
TextAlignment="Center">
<i:Interaction.Behaviors>
<behaviors:ScaleFontWithSize MaxFontSize="22"></behaviors:ScaleFontWithSize>
</i:Interaction.Behaviors>
</TextBlock>
<Rectangle Fill="Transparent"
MouseEnter="Grid_MouseEnter"
MouseLeave="Grid_MouseLeave"
MouseLeftButtonDown="Rectangle_MouseLeftButtonDown"
Grid.RowSpan="2">
</Rectangle>
</Grid>
</UserControl>
+68
View File
@@ -0,0 +1,68 @@
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace Daybreak.Controls
{
/// <summary>
/// Interaction logic for TileButton.xaml
/// </summary>
public partial class TileButton : UserControl
{
public event EventHandler Clicked;
public static readonly DependencyProperty HighlightedProperty =
DependencyProperty.Register("Highlighted", typeof(bool), typeof(TileButton), null);
public static readonly DependencyProperty HighlightColorProperty =
DependencyProperty.Register("HighlightColor", typeof(Brush), typeof(TileButton), null);
public static readonly DependencyProperty InnerContentProperty =
DependencyProperty.Register("InnerContent", typeof(FrameworkElement), typeof(TileButton), null);
public static readonly DependencyProperty TitleProperty =
DependencyProperty.Register("Title", typeof(string), typeof(TileButton), null);
public TileButton()
{
this.InitializeComponent();
}
public bool Highlighted
{
get => (bool)this.GetValue(HighlightedProperty);
set => this.SetValue(HighlightedProperty, value);
}
public string Title
{
get => this.GetValue(TitleProperty) as string;
set => this.SetValue(TitleProperty, value);
}
public FrameworkElement InnerContent
{
get => this.GetValue(InnerContentProperty) as FrameworkElement;
set => this.SetValue(InnerContentProperty, value);
}
public Brush HighlightColor
{
get => this.GetValue(HighlightColorProperty) as Brush;
set => this.SetValue(HighlightColorProperty, value);
}
private void Grid_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
{
this.Highlighted = true;
}
private void Grid_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
{
this.Highlighted = false;
}
private void Rectangle_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
Clicked?.Invoke(this, e);
}
}
}
@@ -0,0 +1,25 @@
using System;
using System.Windows.Data;
namespace Daybreak.Converters
{
public class InverseBooleanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
if (targetType != typeof(bool))
{
throw new InvalidOperationException("The target must be a boolean");
}
return !(bool)value;
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}
}
}
@@ -0,0 +1,35 @@
using System;
using System.Globalization;
using System.Windows.Data;
namespace Daybreak.Converters
{
public class TileButtonHighlightConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (targetType == typeof(double) &&
value is bool boolean)
{
return boolean ? 1 : 0.4;
}
else
{
throw new NotImplementedException();
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (targetType == typeof(bool) &&
value is double doubleValue)
{
return doubleValue == 1;
}
else
{
throw new NotImplementedException();
}
}
}
}
-6
View File
@@ -1,6 +0,0 @@
{
"GamePath": "",
"CharacterName": "",
"LeftBrowserDefault": "https://gwpvx.fandom.com/wiki/Special:RecentChanges?hidebots=1&hidecategorization=1&limit=50&days=7&enhanced=1&urlversion=2",
"RightBrowserDefault": "https://wiki.guildwars.com/wiki/Quick_access_links"
}
+3 -7
View File
@@ -9,13 +9,15 @@
<CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>
<LangVersion>preview</LangVersion>
<ApplicationIcon>Daybreak.ico</ApplicationIcon>
<Version>0.4.0</Version>
<Version>0.6.1</Version>
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.774.44" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Slim" Version="1.2.1" />
<PackageReference Include="System.Windows.Interactivity.WPF" Version="2.0.20525" />
<PackageReference Include="SystemExtensions.NetStandard" Version="1.1.3" />
<PackageReference Include="WCL" Version="1.0.2" />
<PackageReference Include="WpfExtended" Version="0.1.1" />
@@ -30,12 +32,6 @@
</Compile>
</ItemGroup>
<ItemGroup>
<None Update="Daybreak.config.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<Page Update="Controls\MaximizeButton.xaml">
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
@@ -0,0 +1,24 @@
using System;
using System.Runtime.Serialization;
namespace Daybreak.Exceptions
{
public sealed class CredentialsNotFoundException : Exception
{
public CredentialsNotFoundException()
{
}
public CredentialsNotFoundException(string message) : base(message)
{
}
public CredentialsNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
public CredentialsNotFoundException(string message, Exception innerException) : base(message, innerException)
{
}
}
}
@@ -0,0 +1,24 @@
using System;
using System.Runtime.Serialization;
namespace Daybreak.Exceptions
{
public sealed class ExecutableNotFoundException : Exception
{
public ExecutableNotFoundException()
{
}
public ExecutableNotFoundException(string message) : base(message)
{
}
public ExecutableNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
public ExecutableNotFoundException(string message, Exception innerException) : base(message, innerException)
{
}
}
}
+13 -1
View File
@@ -120,7 +120,7 @@ namespace Daybreak.Launch
private void SettingsButton_Clicked(object sender, EventArgs e)
{
this.viewManager.ShowView<SettingsView>();
this.viewManager.ShowView<SettingsCategoryView>();
}
private void CreditTextBox_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
@@ -159,9 +159,21 @@ namespace Daybreak.Launch
else
{
this.viewManager.ShowView<MainView>();
this.PeriodicallyCheckForUpdates();
}
}
private void PeriodicallyCheckForUpdates()
{
TaskExtensions.RunPeriodicAsync(async () =>
{
if (await this.applicationUpdater.UpdateAvailable())
{
this.Dispatcher.Invoke(() => this.viewManager.ShowView<AskUpdateView>());
}
}, TimeSpan.FromMinutes(15), TimeSpan.FromMinutes(15), CancellationToken.None);
}
private static Color GetAverageColor(BitmapSource bitmap)
{
var format = bitmap.Format;
+12
View File
@@ -0,0 +1,12 @@
using Newtonsoft.Json;
namespace Daybreak.Models
{
public sealed class GuildwarsPath
{
[JsonProperty("path")]
public string Path { get; set; }
[JsonProperty("default")]
public bool Default { get; set; }
}
}
+3 -1
View File
@@ -3,6 +3,8 @@
public sealed class LoginCredentials
{
public string Username { get; set; }
public SecureString Password { get; set; }
public string Password { get; set; }
public string CharacterName { get; set; }
public bool Default { get; set; }
}
}
@@ -0,0 +1,16 @@
using Newtonsoft.Json;
namespace Daybreak.Models
{
public sealed class ProtectedLoginCredentials
{
[JsonProperty("ProtectedUsername")]
public string ProtectedUsername { get; set; }
[JsonProperty("ProtectedPassword")]
public string ProtectedPassword { get; set; }
[JsonProperty("CharacterName")]
public string CharacterName { get; set; }
[JsonProperty("Default")]
public bool Default { get; set; }
}
}
@@ -1,10 +0,0 @@
namespace Daybreak.Services.ApplicationDetection
{
public interface IApplicationDetector
{
bool IsGuildwarsRunning { get; }
bool IsToolboxRunning { get; }
void LaunchGuildwars();
void LaunchGuildwarsToolbox();
}
}
@@ -1,20 +1,22 @@
using Daybreak.Models;
using Daybreak.Exceptions;
using Daybreak.Services.Configuration;
using Daybreak.Services.Credentials;
using Daybreak.Services.Logging;
using Daybreak.Services.Mutex;
using Daybreak.Utils;
using Microsoft.Win32;
using Pepa.Wpf.Utilities;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Extensions;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security;
using System.Threading.Tasks;
namespace Daybreak.Services.ApplicationDetection
namespace Daybreak.Services.ApplicationLauncher
{
public class ApplicationDetector : IApplicationDetector
public class ApplicationLauncher : IApplicationLauncher
{
private const string ToolboxProcessName = "GWToolbox";
private const string ProcessName = "gw";
@@ -23,29 +25,27 @@ namespace Daybreak.Services.ApplicationDetection
private readonly IConfigurationManager configurationManager;
private readonly ICredentialManager credentialManager;
private readonly IMutexHandler mutexHandler;
private readonly ILogger logger;
public bool IsGuildwarsRunning => this.GuildwarsProcessDetected();
public bool IsToolboxRunning => GuildwarsToolboxProcessDetected();
public ApplicationDetector(
public ApplicationLauncher(
IConfigurationManager configurationManager,
ICredentialManager credentialManager,
IMutexHandler mutexHandler)
IMutexHandler mutexHandler,
ILogger logger)
{
this.logger = logger.ThrowIfNull(nameof(logger));
this.mutexHandler = mutexHandler.ThrowIfNull(nameof(mutexHandler));
this.credentialManager = credentialManager.ThrowIfNull(nameof(credentialManager));
this.configurationManager = configurationManager.ThrowIfNull(nameof(configurationManager));
}
public void LaunchGuildwars()
public async Task LaunchGuildwars()
{
var configuration = this.configurationManager.GetConfiguration();
if (string.IsNullOrEmpty(configuration.CharacterName))
{
throw new InvalidOperationException($"No character name set");
}
var auth = this.credentialManager.GetCredentials();
var auth = await this.credentialManager.GetDefaultCredentials().ConfigureAwait(false);
auth.Do(
onSome: (credentials) =>
{
@@ -54,38 +54,59 @@ namespace Daybreak.Services.ApplicationDetection
ClearGwLocks();
}
LaunchGuildwarsProcess(credentials.Username, credentials.Password, configuration.CharacterName);
LaunchGuildwarsProcess(credentials.Username, credentials.Password, credentials.CharacterName);
},
onNone: () =>
{
throw new InvalidOperationException($"No credentials available");
throw new CredentialsNotFoundException($"No credentials available");
});
}
public void LaunchGuildwarsToolbox()
public Task LaunchGuildwarsToolbox()
{
var configuration = this.configurationManager.GetConfiguration();
var executable = configuration.ToolboxPath;
if (File.Exists(executable) is false)
return Task.Run(() =>
{
throw new InvalidOperationException($"Guildwars executable doesn't exist at {executable}");
}
var configuration = this.configurationManager.GetConfiguration();
var executable = configuration.ToolboxPath;
if (File.Exists(executable) is false)
{
throw new ExecutableNotFoundException($"Guildwars executable doesn't exist at {executable}");
}
if (Process.Start(executable) is null)
{
throw new InvalidOperationException($"Unable to launch {executable}");
}
if (Process.Start(executable) is null)
{
throw new InvalidOperationException($"Unable to launch {executable}");
}
});
}
private void LaunchGuildwarsProcess(string email, SecureString password, string character)
private void LaunchGuildwarsProcess(string email, Models.SecureString password, string character)
{
var executable = this.configurationManager.GetConfiguration().GamePath;
if (File.Exists(executable) is false)
var executable = this.configurationManager.GetConfiguration().GuildwarsPaths.Where(path => path.Default).FirstOrDefault();
if (executable is null)
{
throw new InvalidOperationException($"Guildwars executable doesn't exist at {executable}");
throw new ExecutableNotFoundException($"No executable selected");
}
if (Process.Start(executable, new List<string> { "-email", email, "-password", password, "-character", character }) is null)
if (File.Exists(executable.Path) is false)
{
throw new ExecutableNotFoundException($"Guildwars executable doesn't exist at {executable}");
}
var args = new List<string>()
{
"-email",
email,
"-password",
password
};
if (!string.IsNullOrWhiteSpace(character))
{
args.Add("-character");
args.Add(character);
}
if (Process.Start(executable.Path, args) is null)
{
throw new InvalidOperationException($"Unable to launch {executable}");
}
@@ -97,7 +118,13 @@ namespace Daybreak.Services.ApplicationDetection
{
try
{
using var stream = File.OpenWrite(this.configurationManager.GetConfiguration().GamePath);
var path = this.configurationManager.GetConfiguration().GuildwarsPaths.Where(path => path.Default).FirstOrDefault();
if (path is null)
{
return false;
}
using var stream = File.OpenWrite(path.Path);
return false;
}
catch
@@ -120,14 +147,27 @@ namespace Daybreak.Services.ApplicationDetection
private void SetRegistryGuildwarsPath()
{
var gamePath = this.configurationManager.GetConfiguration().GamePath;
var registryKey = GetGuildwarsRegistryKey(true);
registryKey.SetValue("Path", gamePath);
registryKey.SetValue("Src", gamePath);
registryKey.Close();
var path = this.configurationManager.GetConfiguration().GuildwarsPaths.Where(path => path.Default).FirstOrDefault();
if (path is null)
{
throw new ExecutableNotFoundException("No executable currently selected");
}
var gamePath = path.Path;
try
{
var registryKey = GetGuildwarsRegistryKey(true);
registryKey.SetValue("Path", gamePath);
registryKey.SetValue("Src", gamePath);
registryKey.Close();
}
catch (SecurityException ex)
{
this.logger.LogCritical($"Multi-launch requires administrator rights. Details: {ex}");
}
}
private RegistryKey GetGuildwarsRegistryKey(bool write)
private static RegistryKey GetGuildwarsRegistryKey(bool write)
{
var gwKey = Registry.CurrentUser.OpenSubKey("SOFTWARE")?.OpenSubKey("ArenaNet")?.OpenSubKey("Guild Wars", write);
if (gwKey is not null)
@@ -0,0 +1,12 @@
using System.Threading.Tasks;
namespace Daybreak.Services.ApplicationLauncher
{
public interface IApplicationLauncher
{
bool IsGuildwarsRunning { get; }
bool IsToolboxRunning { get; }
Task LaunchGuildwars();
Task LaunchGuildwarsToolbox();
}
}
@@ -3,9 +3,12 @@ using Daybreak.Services.Configuration;
using Daybreak.Services.Logging;
using Daybreak.Utils;
using System;
using System.Collections.Generic;
using System.Extensions;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace Daybreak.Services.Credentials
{
@@ -23,43 +26,123 @@ namespace Daybreak.Services.Credentials
this.logger = logger.ThrowIfNull(nameof(logger));
}
public Optional<LoginCredentials> GetCredentials()
public Task<Optional<LoginCredentials>> GetDefaultCredentials()
{
this.logger.LogInformation("Retrieving credentials");
var config = this.configurationManager.GetConfiguration();
if (string.IsNullOrEmpty(config.ProtectedUsername) ||
string.IsNullOrEmpty(config.ProtectedPassword))
return Task.Run(async () =>
{
this.logger.LogInformation("No credentials found");
return Optional.None<LoginCredentials>();
}
this.logger.LogInformation("Retrieving default credentials");
var defaultCredentials = (await this.GetCredentialList())
.Where(creds => creds.Default)
.ToList();
if (defaultCredentials.Count == 0)
{
this.logger.LogWarning("No default credentials");
return Optional.None<LoginCredentials>();
}
if (defaultCredentials.Count > 1)
{
this.logger.LogError("Multiple credentials set as default");
return Optional.None<LoginCredentials>();
}
return defaultCredentials.FirstOrDefault();
});
}
public Task<List<LoginCredentials>> GetCredentialList()
{
return Task.Run(() =>
{
this.logger.LogInformation("Retrieving credentials");
var config = this.configurationManager.GetConfiguration();
if (config.ProtectedLoginCredentials is null || config.ProtectedLoginCredentials.Count == 0)
{
this.logger.LogInformation("No credentials found");
return new List<LoginCredentials>();
}
return config
.ProtectedLoginCredentials
.Select(UnprotectCredentials)
.Where(CredentialsUnprotected)
.Select(ExtractCredentials)
.ToList();
});
}
public Task StoreCredentials(List<LoginCredentials> loginCredentials)
{
return Task.Run(() =>
{
this.logger.LogInformation("Storing credentials");
var config = this.configurationManager.GetConfiguration();
config.ProtectedLoginCredentials = loginCredentials
.Select(ProtectCredentials)
.Where(CredentialsProtected)
.Select(ExtractProtectedCredentials)
.ToList();
this.configurationManager.SaveConfiguration(config);
});
}
private Optional<LoginCredentials> UnprotectCredentials(ProtectedLoginCredentials protectedLoginCredentials)
{
try
{
var usrbytes = Convert.FromBase64String(config.ProtectedUsername);
var psdBytes = Convert.FromBase64String(config.ProtectedPassword);
var usrbytes = Convert.FromBase64String(protectedLoginCredentials.ProtectedUsername);
var psdBytes = Convert.FromBase64String(protectedLoginCredentials.ProtectedPassword);
return new LoginCredentials
{
Username = Encoding.UTF8.GetString(ProtectedData.Unprotect(usrbytes, Entropy, DataProtectionScope.LocalMachine)),
Password = Encoding.UTF8.GetString(ProtectedData.Unprotect(psdBytes, Entropy, DataProtectionScope.LocalMachine))
Password = Encoding.UTF8.GetString(ProtectedData.Unprotect(psdBytes, Entropy, DataProtectionScope.LocalMachine)),
CharacterName = protectedLoginCredentials.CharacterName,
Default = protectedLoginCredentials.Default
};
}
catch(Exception e)
catch (Exception e)
{
this.logger.LogError($"Unable to retrieve credentials. Details: {e}");
return Optional.None<LoginCredentials>();
}
}
public void StoreCredentials(LoginCredentials loginCredentials)
private Optional<ProtectedLoginCredentials> ProtectCredentials(LoginCredentials loginCredentials)
{
this.logger.LogInformation("Storing credentials");
var usrBytes = Encoding.UTF8.GetBytes(loginCredentials.Username);
var psdBytes = Encoding.UTF8.GetBytes(loginCredentials.Password);
var config = this.configurationManager.GetConfiguration();
config.ProtectedUsername = Convert.ToBase64String(ProtectedData.Protect(usrBytes, Entropy, DataProtectionScope.LocalMachine));
config.ProtectedPassword = Convert.ToBase64String(ProtectedData.Protect(psdBytes, Entropy, DataProtectionScope.LocalMachine));
this.configurationManager.SaveConfiguration(config);
try
{
var usrBytes = Encoding.UTF8.GetBytes(loginCredentials.Username);
var psdBytes = Encoding.UTF8.GetBytes(loginCredentials.Password);
return new ProtectedLoginCredentials
{
ProtectedUsername = Convert.ToBase64String(ProtectedData.Protect(usrBytes, Entropy, DataProtectionScope.LocalMachine)),
ProtectedPassword = Convert.ToBase64String(ProtectedData.Protect(psdBytes, Entropy, DataProtectionScope.LocalMachine)),
CharacterName = loginCredentials.CharacterName,
Default = loginCredentials.Default
};
}
catch
{
return Optional.None<ProtectedLoginCredentials>();
}
}
private bool CredentialsUnprotected(Optional<LoginCredentials> optional)
{
return optional
.Switch(onSome: _ => true, onNone: () => false)
.ExtractValue();
}
private bool CredentialsProtected(Optional<ProtectedLoginCredentials> optional)
{
return optional
.Switch(onSome: _ => true, onNone: () => false)
.ExtractValue();
}
private ProtectedLoginCredentials ExtractProtectedCredentials(Optional<ProtectedLoginCredentials> optional)
{
return optional.ExtractValue();
}
private LoginCredentials ExtractCredentials(Optional<LoginCredentials> optional)
{
return optional.ExtractValue();
}
}
}
@@ -1,11 +1,14 @@
using Daybreak.Models;
using System.Collections.Generic;
using System.Extensions;
using System.Threading.Tasks;
namespace Daybreak.Services.Credentials
{
public interface ICredentialManager
{
void StoreCredentials(LoginCredentials loginCredentials);
Optional<LoginCredentials> GetCredentials();
Task StoreCredentials(List<LoginCredentials> loginCredentials);
Task<List<LoginCredentials>> GetCredentialList();
Task<Optional<LoginCredentials>> GetDefaultCredentials();
}
}
@@ -93,7 +93,7 @@ namespace Daybreak.Services.Updater
public async Task<bool> UpdateAvailable()
{
var version = string.Join('.', this.CurrentVersion.Split('.').Take(3));
var version = string.Join('.', this.CurrentVersion.Split('.'));
var maybeLatestVersion = await this.GetLatestVersion();
return maybeLatestVersion.Switch(
onSome: latestVersion => string.Compare(version, latestVersion, true) < 0,
+37
View File
@@ -0,0 +1,37 @@
<UserControl x:Class="Daybreak.Views.AccountsView"
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"
mc:Ignorable="d"
xmlns:controls="clr-namespace:Daybreak.Controls"
x:Name="_this"
d:DesignHeight="450" d:DesignWidth="800">
<Grid Background="#A0202020">
<TextBlock HorizontalAlignment="Center" Text="Accounts settings" FontSize="22" Foreground="White"></TextBlock>
<controls:BackButton Foreground="White" Height="30" Width="30" Grid.Column="0" HorizontalAlignment="Left" Margin="5"
Clicked="BackButton_Clicked" VerticalAlignment="Top"></controls:BackButton>
<controls:AddButton Foreground="White" Height="30" Width="30" Grid.Column="0" HorizontalAlignment="Right" Margin="5, 5, 45, 5"
Clicked="AddButton_Clicked" VerticalAlignment="Top"></controls:AddButton>
<controls:SaveButton Foreground="White" Height="30" Width="30" Grid.Column="0" HorizontalAlignment="Right" Margin="5"
Clicked="SaveButton_Clicked" VerticalAlignment="Top"></controls:SaveButton>
<ListView ItemsSource="{Binding ElementName=_this, Path=Accounts, Mode=OneWay}" Background="Transparent" Margin="0, 40, 0, 0">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<controls:AccountTemplate Username="{Binding Username, Mode=TwoWay}"
Password="{Binding Password, Mode=TwoWay}"
CharacterName="{Binding CharacterName, Mode=TwoWay}"
RemoveClicked="AccountTemplate_RemoveClicked"
IsDefault="{Binding Default, Mode=TwoWay}"
DefaultClicked="AccountTemplate_DefaultClicked"></controls:AccountTemplate>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</UserControl>
+88
View File
@@ -0,0 +1,88 @@
using Daybreak.Controls;
using Daybreak.Models;
using Daybreak.Services.Credentials;
using Daybreak.Services.ViewManagement;
using System;
using System.Collections.ObjectModel;
using System.Extensions;
using System.Linq;
using System.Windows.Controls;
using System.Windows.Data;
namespace Daybreak.Views
{
/// <summary>
/// Interaction logic for AccountsView.xaml
/// </summary>
public partial class AccountsView : UserControl
{
private readonly ICredentialManager credentialManager;
private readonly IViewManager viewManager;
public ObservableCollection<LoginCredentials> Accounts { get; } = new();
public AccountsView(
ICredentialManager credentialManager,
IViewManager viewManager)
{
this.credentialManager = credentialManager.ThrowIfNull(nameof(credentialManager));
this.viewManager = viewManager.ThrowIfNull(nameof(viewManager));
this.InitializeComponent();
this.GetCredentials();
}
private async void GetCredentials()
{
var creds = await this.credentialManager.GetCredentialList().ConfigureAwait(true);
this.Accounts.AddRange(creds);
}
private void BackButton_Clicked(object sender, EventArgs e)
{
this.viewManager.ShowView<SettingsCategoryView>();
}
private void AddButton_Clicked(object sender, EventArgs e)
{
var newCredentials = new LoginCredentials();
this.Accounts.Add(newCredentials);
if (this.Accounts.Count == 1)
{
this.SetAccountAsDefault(newCredentials);
}
}
private async void SaveButton_Clicked(object sender, EventArgs e)
{
await this.credentialManager.StoreCredentials(this.Accounts.ToList()).ConfigureAwait(true);
this.viewManager.ShowView<SettingsCategoryView>();
}
private void AccountTemplate_RemoveClicked(object sender, EventArgs e)
{
var creds = sender.As<AccountTemplate>()?.DataContext?.As<LoginCredentials>();
this.Accounts.Remove(creds);
if (this.Accounts.Count > 0 && creds.Default is true)
{
this.SetAccountAsDefault(this.Accounts.First());
}
}
private void AccountTemplate_DefaultClicked(object sender, EventArgs e)
{
var creds = sender.As<AccountTemplate>()?.DataContext?.As<LoginCredentials>();
this.SetAccountAsDefault(creds);
}
private void SetAccountAsDefault(LoginCredentials loginCredentials)
{
foreach (var cred in this.Accounts)
{
cred.Default = false;
}
loginCredentials.Default = true;
var view = CollectionViewSource.GetDefaultView(this.Accounts);
view.Refresh();
}
}
}
-3
View File
@@ -12,16 +12,13 @@ namespace Daybreak.Views
/// </summary>
public partial class AskUpdateView : UserControl
{
private readonly IApplicationUpdater applicationUpdater;
private readonly ILogger logger;
private readonly IViewManager viewManager;
public AskUpdateView(
IApplicationUpdater applicationUpdater,
ILogger logger,
IViewManager viewManager)
{
this.applicationUpdater = applicationUpdater.ThrowIfNull(nameof(applicationUpdater));
this.logger = logger.ThrowIfNull(nameof(logger));
this.viewManager = viewManager.ThrowIfNull(nameof(viewManager));
this.InitializeComponent();
+36
View File
@@ -0,0 +1,36 @@
<UserControl x:Class="Daybreak.Views.ExecutablesView"
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"
mc:Ignorable="d"
xmlns:controls="clr-namespace:Daybreak.Controls"
x:Name="_this"
d:DesignHeight="450" d:DesignWidth="800">
<Grid Background="#A0202020">
<TextBlock HorizontalAlignment="Center" Text="Executables settings" FontSize="22" Foreground="White"></TextBlock>
<controls:BackButton Foreground="White" Height="30" Width="30" Grid.Column="0" HorizontalAlignment="Left" Margin="5"
Clicked="BackButton_Clicked" VerticalAlignment="Top"></controls:BackButton>
<controls:AddButton Foreground="White" Height="30" Width="30" Grid.Column="0" HorizontalAlignment="Right" Margin="5, 5, 45, 5"
Clicked="AddButton_Clicked" VerticalAlignment="Top"></controls:AddButton>
<controls:SaveButton Foreground="White" Height="30" Width="30" Grid.Column="0" HorizontalAlignment="Right" Margin="5"
Clicked="SaveButton_Clicked" VerticalAlignment="Top"></controls:SaveButton>
<ListView ItemsSource="{Binding ElementName=_this, Path=Paths, Mode=OneWay}" Background="Transparent" Margin="0, 40, 0, 0">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<controls:GuildwarsPathTemplate
Path="{Binding Path, Mode=TwoWay}"
IsDefault="{Binding Default, Mode=TwoWay}"
DefaultClicked="GuildwarsPathTemplate_DefaultClicked"
RemoveClicked="GuildwarsPathTemplate_RemoveClicked"></controls:GuildwarsPathTemplate>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</UserControl>
+89
View File
@@ -0,0 +1,89 @@
using Daybreak.Controls;
using Daybreak.Models;
using Daybreak.Services.Configuration;
using Daybreak.Services.ViewManagement;
using Microsoft.Win32;
using System;
using System.Collections.ObjectModel;
using System.Extensions;
using System.Linq;
using System.Windows.Controls;
using System.Windows.Data;
namespace Daybreak.Views
{
/// <summary>
/// Interaction logic for ExecutablesView.xaml
/// </summary>
public partial class ExecutablesView : UserControl
{
private readonly IConfigurationManager configurationManager;
private readonly IViewManager viewManager;
public ObservableCollection<GuildwarsPath> Paths { get; } = new();
public ExecutablesView(
IConfigurationManager configurationManager,
IViewManager viewManager)
{
this.configurationManager = configurationManager.ThrowIfNull(nameof(configurationManager));
this.viewManager = viewManager.ThrowIfNull(nameof(viewManager));
this.InitializeComponent();
this.GetPaths();
}
private void GetPaths()
{
this.Paths.AddRange(this.configurationManager.GetConfiguration().GuildwarsPaths);
}
private void BackButton_Clicked(object sender, EventArgs e)
{
this.viewManager.ShowView<SettingsCategoryView>();
}
private void AddButton_Clicked(object sender, EventArgs e)
{
var newPath = new GuildwarsPath();
this.Paths.Add(newPath);
if (this.Paths.Count == 1)
{
this.SetPathAsDefault(newPath);
}
}
private void SaveButton_Clicked(object sender, EventArgs e)
{
var config = this.configurationManager.GetConfiguration();
config.GuildwarsPaths = this.Paths.ToList();
this.configurationManager.SaveConfiguration(config);
this.viewManager.ShowView<SettingsCategoryView>();
}
private void GuildwarsPathTemplate_DefaultClicked(object sender, EventArgs e)
{
var path = sender.As<GuildwarsPathTemplate>()?.DataContext?.As<GuildwarsPath>();
this.SetPathAsDefault(path);
}
private void GuildwarsPathTemplate_RemoveClicked(object sender, EventArgs e)
{
var path = sender.As<GuildwarsPathTemplate>()?.DataContext?.As<GuildwarsPath>();
this.Paths.Remove(path);
if (this.Paths.Count > 0 && path.Default is true)
{
this.SetPathAsDefault(this.Paths.First());
}
}
private void SetPathAsDefault(GuildwarsPath gwPath)
{
foreach (var path in this.Paths)
{
path.Default = false;
}
gwPath.Default = true;
var view = CollectionViewSource.GetDefaultView(this.Paths);
view.Refresh();
}
}
}
@@ -0,0 +1,94 @@
<UserControl x:Class="Daybreak.Views.ExperimentalSettingsView"
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"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<ResourceDictionary>
<Style x:Key="AnimatedSwitch" TargetType="{x:Type ToggleButton}">
<Setter Property="Foreground" Value="Black" />
<Setter Property="Background" Value="#FAFAFB" />
<Setter Property="BorderBrush" Value="#EAEAEB" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Viewbox Stretch="Uniform">
<Canvas Name="Layer_1" Width="35" Height="20" Canvas.Left="10" Canvas.Top="0">
<Ellipse Canvas.Left="0" Width="20" Height="20" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding BorderBrush}" StrokeThickness="0.5"/>
<Ellipse Canvas.Left="15" Width="20" Height="20" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding BorderBrush}" StrokeThickness="0.5"/>
<Border Canvas.Left="10" Width="15" Height="20" Name="rect416927" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="0,0.5,0,0.5"/>
<Ellipse x:Name="ellipse" Canvas.Left="0" Width="20" Height="20" Fill="White" Stroke="{TemplateBinding BorderBrush}" StrokeThickness="0.3">
<Ellipse.RenderTransform>
<TranslateTransform X="0" Y="0" />
</Ellipse.RenderTransform>
<Ellipse.BitmapEffect>
<DropShadowBitmapEffect Softness="0.1" ShadowDepth="0.7" Direction="270" Color="#BBBBBB"/>
</Ellipse.BitmapEffect>
</Ellipse>
</Canvas>
</Viewbox>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True" >
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="Background.Color" To="DodgerBlue" Duration="0:0:0.2" />
<ColorAnimation Storyboard.TargetProperty="BorderBrush.Color" To="#41C955" Duration="0:0:0.2" />
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(Ellipse.RenderTransform).(TranslateTransform.X)" Storyboard.TargetName="ellipse">
<SplineDoubleKeyFrame KeyTime="0" Value="0"/>
<SplineDoubleKeyFrame KeyTime="0:0:0.4" Value="15" KeySpline="0, 1, 0.6, 1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="Background.Color" To="#FAFAFB" Duration="0:0:0.2" />
<ColorAnimation Storyboard.TargetProperty="BorderBrush.Color" To="#EAEAEB" Duration="0:0:0.2" />
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(Ellipse.RenderTransform).(TranslateTransform.X)" Storyboard.TargetName="ellipse">
<SplineDoubleKeyFrame KeyTime="0" Value="15"/>
<SplineDoubleKeyFrame KeyTime="0:0:0.3" Value="0" KeySpline="0, 0.5, 0.5, 1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
</UserControl.Resources>
<Grid Background="#A0202020">
<Grid.RowDefinitions>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<controls:BackButton Foreground="White" Height="30" Width="30" Grid.Column="0" Margin="5"
Clicked="BackButton_Clicked" VerticalAlignment="Top" HorizontalAlignment="Left"></controls:BackButton>
<controls:SaveButton Foreground="White" Height="30" Width="30" Grid.Column="0" Margin="5"
Clicked="SaveButton_Clicked" VerticalAlignment="Top" HorizontalAlignment="Right"></controls:SaveButton>
<StackPanel Margin="50, 0, 50, 0" HorizontalAlignment="Center">
<TextBlock FontSize="22" Foreground="White" TextWrapping="Wrap"
Text="Experimental settings" HorizontalAlignment="Center"></TextBlock>
<TextBlock FontSize="16" Foreground="White" TextWrapping="Wrap"
Text="Warning! Functionality under development! These settings might have unintended consequences, including breaking the GuildWars TOS."></TextBlock>
</StackPanel>
<Rectangle Fill="White" Height="1" VerticalAlignment="Bottom"></Rectangle>
<Grid Grid.Row="1" HorizontalAlignment="Center" Margin="0, 15, 0, 0">
<WrapPanel>
<TextBlock Text="Multi-launch support" Foreground="White" FontSize="22" VerticalAlignment="Center" Margin="0, 0, 15, 0"></TextBlock>
<ToggleButton IsChecked="{Binding ElementName=_this, Path=MultiLaunch, Mode=TwoWay}" Style="{StaticResource AnimatedSwitch}"
Height="30" Width="60"></ToggleButton>
</WrapPanel>
</Grid>
</Grid>
</UserControl>
@@ -0,0 +1,61 @@
using Daybreak.Services.Configuration;
using Daybreak.Services.ViewManagement;
using System;
using System.Extensions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Extensions;
namespace Daybreak.Views
{
/// <summary>
/// Interaction logic for ExperimentalSettingsView.xaml
/// </summary>
public partial class ExperimentalSettingsView : UserControl
{
public static readonly DependencyProperty MultiLaunchProperty = DependencyPropertyExtensions.Register<ExperimentalSettingsView, bool>(nameof(MultiLaunch));
private readonly IViewManager viewManager;
private readonly IConfigurationManager configurationManager;
public bool MultiLaunch
{
get => this.GetTypedValue<bool>(MultiLaunchProperty);
set => this.SetValue(MultiLaunchProperty, value);
}
public ExperimentalSettingsView(
IViewManager viewManager,
IConfigurationManager configurationManager)
{
this.viewManager = viewManager.ThrowIfNull(nameof(viewManager));
this.configurationManager = configurationManager.ThrowIfNull(nameof(configurationManager));
this.InitializeComponent();
this.LoadExperimentalSettings();
}
private void LoadExperimentalSettings()
{
var config = this.configurationManager.GetConfiguration();
this.MultiLaunch = config.ExperimentalFeatures.MultiLaunchSupport;
}
private void SaveExperimentalSettings()
{
var config = this.configurationManager.GetConfiguration();
config.ExperimentalFeatures.MultiLaunchSupport = this.MultiLaunch;
this.configurationManager.SaveConfiguration(config);
}
private void SaveButton_Clicked(object sender, EventArgs e)
{
this.SaveExperimentalSettings();
this.viewManager.ShowView<SettingsCategoryView>();
}
private void BackButton_Clicked(object sender, EventArgs e)
{
this.viewManager.ShowView<SettingsCategoryView>();
}
}
}
+12 -7
View File
@@ -1,5 +1,6 @@
using Daybreak.Controls;
using Daybreak.Services.ApplicationDetection;
using Daybreak.Exceptions;
using Daybreak.Services.ApplicationLauncher;
using Daybreak.Services.Configuration;
using Daybreak.Services.ViewManagement;
using System;
@@ -29,7 +30,7 @@ namespace Daybreak.Views
public static readonly DependencyProperty LeftBrowserFavoriteAddressProperty =
DependencyPropertyExtensions.Register<MainView, string>(nameof(LeftBrowserFavoriteAddress));
private readonly IApplicationDetector applicationDetector;
private readonly IApplicationLauncher applicationDetector;
private readonly IViewManager viewManager;
private readonly IConfigurationManager configurationManager;
private readonly CancellationTokenSource cancellationTokenSource = new();
@@ -69,7 +70,7 @@ namespace Daybreak.Views
}
public MainView(
IApplicationDetector applicationDetector,
IApplicationLauncher applicationDetector,
IViewManager viewManager,
IConfigurationManager configurationManager)
{
@@ -110,15 +111,19 @@ namespace Daybreak.Views
this.cancellationTokenSource.Cancel();
}
private void LaunchButton_Clicked(object sender, EventArgs e)
private async void LaunchButton_Clicked(object sender, EventArgs e)
{
try
{
this.applicationDetector.LaunchGuildwars();
await this.applicationDetector.LaunchGuildwars();
}
catch
catch (CredentialsNotFoundException)
{
this.viewManager.ShowView<SettingsView>();
this.viewManager.ShowView<AccountsView>();
}
catch (ExecutableNotFoundException)
{
this.viewManager.ShowView<ExecutablesView>();
}
}
+42
View File
@@ -0,0 +1,42 @@
<UserControl x:Class="Daybreak.Views.SettingsCategoryView"
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"
d:DesignHeight="450" d:DesignWidth="800">
<Grid Background="#A0202020">
<controls:BackButton Foreground="White" Height="30" Width="30" Grid.Column="0" Margin="5"
Clicked="BackButton_Clicked" VerticalAlignment="Top" HorizontalAlignment="Left"></controls:BackButton>
<WrapPanel Orientation="Vertical" VerticalAlignment="Bottom">
<WrapPanel Orientation="Horizontal">
<controls:TileButton Title="Account settings" Foreground="White" BorderBrush="White" BorderThickness="2"
HighlightColor="White" Clicked="AccountButton_Clicked" Width="150" Height="150">
<controls:TileButton.InnerContent>
<controls:AvatarGlyph></controls:AvatarGlyph>
</controls:TileButton.InnerContent>
</controls:TileButton>
<controls:TileButton Title="Guildwars settings" Foreground="White" BorderBrush="White" BorderThickness="2"
HighlightColor="White" Clicked="FileButton_Clicked" Height="150" Width="150">
<controls:TileButton.InnerContent>
<controls:FileGlyph></controls:FileGlyph>
</controls:TileButton.InnerContent>
</controls:TileButton>
<controls:TileButton Title="Launcher settings" Foreground="White" BorderBrush="White" BorderThickness="2"
HighlightColor="White" Clicked="LauncherButton_Clicked" Width="150" Height="150">
<controls:TileButton.InnerContent>
<controls:GoldenArrowGlyph></controls:GoldenArrowGlyph>
</controls:TileButton.InnerContent>
</controls:TileButton>
<controls:TileButton Title="Experimental settings" Foreground="White" BorderBrush="White" BorderThickness="2"
HighlightColor="White" Clicked="ExperimentalButton_Clicked" Height="150" Width="150">
<controls:TileButton.InnerContent>
<controls:ExperimentGlyph></controls:ExperimentGlyph>
</controls:TileButton.InnerContent>
</controls:TileButton>
</WrapPanel>
</WrapPanel>
</Grid>
</UserControl>
@@ -0,0 +1,46 @@
using Daybreak.Services.ViewManagement;
using System.Extensions;
using System.Windows.Controls;
namespace Daybreak.Views
{
/// <summary>
/// Interaction logic for SettingsCategoryView.xaml
/// </summary>
public partial class SettingsCategoryView : UserControl
{
private readonly IViewManager viewManager;
public SettingsCategoryView(
IViewManager viewManager)
{
this.viewManager = viewManager.ThrowIfNull(nameof(viewManager));
InitializeComponent();
}
private void AccountButton_Clicked(object sender, System.EventArgs e)
{
this.viewManager.ShowView<AccountsView>();
}
private void LauncherButton_Clicked(object sender, System.EventArgs e)
{
this.viewManager.ShowView<SettingsView>();
}
private void ExperimentalButton_Clicked(object sender, System.EventArgs e)
{
this.viewManager.ShowView<ExperimentalSettingsView>();
}
private void FileButton_Clicked(object sender, System.EventArgs e)
{
this.viewManager.ShowView<ExecutablesView>();
}
private void BackButton_Clicked(object sender, System.EventArgs e)
{
this.viewManager.ShowView<MainView>();
}
}
}
+79 -29
View File
@@ -8,7 +8,65 @@
mc:Ignorable="d"
x:Name="_this"
d:DesignHeight="450" d:DesignWidth="800">
<Grid Background="#80202020">
<UserControl.Resources>
<ResourceDictionary>
<Style x:Key="AnimatedSwitch" TargetType="{x:Type ToggleButton}">
<Setter Property="Foreground" Value="Black" />
<Setter Property="Background" Value="#FAFAFB" />
<Setter Property="BorderBrush" Value="#EAEAEB" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Viewbox Stretch="Uniform">
<Canvas Name="Layer_1" Width="35" Height="20" Canvas.Left="10" Canvas.Top="0">
<Ellipse Canvas.Left="0" Width="20" Height="20" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding BorderBrush}" StrokeThickness="0.5"/>
<Ellipse Canvas.Left="15" Width="20" Height="20" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding BorderBrush}" StrokeThickness="0.5"/>
<Border Canvas.Left="10" Width="15" Height="20" Name="rect416927" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="0,0.5,0,0.5"/>
<Ellipse x:Name="ellipse" Canvas.Left="0" Width="20" Height="20" Fill="White" Stroke="{TemplateBinding BorderBrush}" StrokeThickness="0.3">
<Ellipse.RenderTransform>
<TranslateTransform X="0" Y="0" />
</Ellipse.RenderTransform>
<Ellipse.BitmapEffect>
<DropShadowBitmapEffect Softness="0.1" ShadowDepth="0.7" Direction="270" Color="#BBBBBB"/>
</Ellipse.BitmapEffect>
</Ellipse>
</Canvas>
</Viewbox>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True" >
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="Background.Color" To="DodgerBlue" Duration="0:0:0.2" />
<ColorAnimation Storyboard.TargetProperty="BorderBrush.Color" To="#41C955" Duration="0:0:0.2" />
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(Ellipse.RenderTransform).(TranslateTransform.X)" Storyboard.TargetName="ellipse">
<SplineDoubleKeyFrame KeyTime="0" Value="0"/>
<SplineDoubleKeyFrame KeyTime="0:0:0.4" Value="15" KeySpline="0, 1, 0.6, 1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="Background.Color" To="#FAFAFB" Duration="0:0:0.2" />
<ColorAnimation Storyboard.TargetProperty="BorderBrush.Color" To="#EAEAEB" Duration="0:0:0.2" />
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(Ellipse.RenderTransform).(TranslateTransform.X)" Storyboard.TargetName="ellipse">
<SplineDoubleKeyFrame KeyTime="0" Value="15"/>
<SplineDoubleKeyFrame KeyTime="0:0:0.3" Value="0" KeySpline="0, 0.5, 0.5, 1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
</UserControl.Resources>
<Grid Background="#A0202020">
<Grid.RowDefinitions>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
@@ -18,43 +76,35 @@
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Text="Launcher settings" FontSize="22" Foreground="White" HorizontalAlignment="Center" Grid.ColumnSpan="2"></TextBlock>
<controls:BackButton Foreground="White" Height="30" Width="30" Grid.Column="0" HorizontalAlignment="Left" Margin="5"
Clicked="BackButton_Clicked"></controls:BackButton>
<controls:SaveButton Foreground="White" Height="30" Width="30" Grid.Column="1" HorizontalAlignment="Right" Margin="5"
Clicked="SaveButton_Clicked"></controls:SaveButton>
<TextBlock Text="Username: " FontSize="22" Foreground="White" Grid.Row="1"></TextBlock>
<TextBox x:Name="UsernameTextbox" Grid.Column="1" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" Grid.Row="1" FontSize="22"
Background="Transparent" Foreground="White"></TextBox>
<TextBlock Text="Password: " FontSize="22" Foreground="White" Grid.Row="2"></TextBlock>
<PasswordBox x:Name="PasswordBox" Grid.Column="1" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" Grid.Row="2"
FontSize="22" Foreground="White" Background="Transparent"></PasswordBox>
<TextBlock Text="Character name: " FontSize="22" Foreground="White" Grid.Row="3"></TextBlock>
<TextBox Grid.Column="1" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" Grid.Row="3"
x:Name="CharacterTextbox" FontSize="22" Background="Transparent" Foreground="White"></TextBox>
<TextBlock Text="Game path: " FontSize="22" Foreground="White" Grid.Row="4"></TextBlock>
<TextBox Grid.Column="1" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" Grid.Row="4"
x:Name="GamePathTextbox" FontSize="22" Margin="0, 0, 30, 0" Background="Transparent" Foreground="White"></TextBox>
<controls:FilePickerGlyph Grid.Row="4" Grid.Column="1" Height="30" Width="30" HorizontalAlignment="Right"
Foreground="White" BorderBrush="Gray" BorderThickness="1"
Clicked="GameFilePickerGlyph_Clicked"></controls:FilePickerGlyph>
<TextBlock Text="Toolbox path: " FontSize="22" Foreground="White" Grid.Row="5"></TextBlock>
<TextBox Grid.Column="1" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" Grid.Row="5"
x:Name="ToolboxPathTextbox" FontSize="22" Margin="0, 0, 30, 0" Background="Transparent" Foreground="White"></TextBox>
<controls:FilePickerGlyph Grid.Row="5" Grid.Column="1" Height="30" Width="30" HorizontalAlignment="Right"
Foreground="White" BorderBrush="Gray" BorderThickness="1"
<TextBlock Text="Toolbox path: " FontSize="22" Foreground="White" Grid.Row="2"></TextBlock>
<TextBox Grid.Column="1" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" Grid.Row="2"
FontSize="22" Margin="0, 0, 30, 0" Background="Transparent" Foreground="White"
Text="{Binding ElementName=_this, Path=ToolboxPath, Mode=TwoWay}"></TextBox>
<controls:FilePickerGlyph Grid.Row="2" Grid.Column="1" Height="30" Width="30" HorizontalAlignment="Right"
Foreground="White" BorderBrush="Gray" BorderThickness="0"
Clicked="ToolboxFilePickerGlyph_Clicked"></controls:FilePickerGlyph>
<TextBlock Text="Address bar readonly: " FontSize="22" Foreground="White" Grid.Row="6"/>
<TextBox Grid.Column="1" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" Grid.Row="6"
x:Name="AddressBarReadonlyTextbox" FontSize="22" Background="Transparent" Foreground="White"></TextBox>
<TextBlock Text="Experimental" FontSize="26" Foreground="White" Grid.Row="7" Grid.ColumnSpan="2" HorizontalAlignment="Center"/>
<TextBlock Text="Multi-launch support: " FontSize="22" Foreground="White" Grid.Row="8"/>
<TextBox Grid.Column="1" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" Grid.Row="8"
x:Name="MultiLaunchSupportTextbox" FontSize="22" Background="Transparent" Foreground="White"></TextBox>
<TextBlock Text="Address bar readonly: " FontSize="22" Foreground="White" Grid.Row="3"/>
<ToggleButton Grid.Column="1" HorizontalAlignment="Center" HorizontalContentAlignment="Stretch" Grid.Row="3" Style="{StaticResource AnimatedSwitch}" Height="30" Width="40"
FontSize="22" Background="Transparent" Foreground="White" IsChecked="{Binding ElementName=_this, Path=AddressBarReadonly, Mode=TwoWay}"></ToggleButton>
<TextBlock Text="Left browser homepage: " FontSize="22" Foreground="White" Grid.Row="4"></TextBlock>
<TextBox Grid.Column="1" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" Grid.Row="4"
FontSize="22" Background="Transparent" Foreground="White"
Text="{Binding ElementName=_this, Path=LeftBrowserUrl, Mode=TwoWay}"
TextChanged="LeftBrowserUrl_TextChanged"></TextBox>
<TextBlock Text="Right browser homepage: " FontSize="22" Foreground="White" Grid.Row="5"></TextBlock>
<TextBox Grid.Column="1" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" Grid.Row="5"
FontSize="22" Background="Transparent" Foreground="White"
Text="{Binding ElementName=_this, Path=RightBrowserUrl, Mode=TwoWay}"
TextChanged="RightBrowserUrl_TextChanged"></TextBox>
</Grid>
</UserControl>
+55 -51
View File
@@ -1,10 +1,11 @@
using Daybreak.Models;
using Daybreak.Services.Configuration;
using Daybreak.Services.Credentials;
using Daybreak.Services.Configuration;
using Daybreak.Services.ViewManagement;
using Microsoft.Win32;
using System;
using System.Extensions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Extensions;
namespace Daybreak.Views
{
@@ -13,17 +14,44 @@ namespace Daybreak.Views
/// </summary>
public partial class SettingsView : UserControl
{
public static readonly DependencyProperty ToolboxPathProperty =
DependencyPropertyExtensions.Register<SettingsView, string>(nameof(ToolboxPath));
public static readonly DependencyProperty AddressBarReadonlyProperty =
DependencyPropertyExtensions.Register<SettingsView, bool>(nameof(AddressBarReadonly));
public static readonly DependencyProperty LeftBrowserUrlProperty =
DependencyPropertyExtensions.Register<SettingsView, string>(nameof(LeftBrowserUrl));
public static readonly DependencyProperty RightBrowserUrlProperty =
DependencyPropertyExtensions.Register<SettingsView, string>(nameof(RightBrowserUrl));
private readonly IConfigurationManager configurationManager;
private readonly ICredentialManager credentialManager;
private readonly IViewManager viewManager;
public string ToolboxPath
{
get => this.GetTypedValue<string>(ToolboxPathProperty);
set => this.SetValue(ToolboxPathProperty, value);
}
public bool AddressBarReadonly
{
get => this.GetTypedValue<bool>(AddressBarReadonlyProperty);
set => this.SetValue(AddressBarReadonlyProperty, value);
}
public string LeftBrowserUrl
{
get => this.GetTypedValue<string>(LeftBrowserUrlProperty);
set => this.SetValue(LeftBrowserUrlProperty, value);
}
public string RightBrowserUrl
{
get => this.GetTypedValue<string>(RightBrowserUrlProperty);
set => this.SetValue(RightBrowserUrlProperty, value);
}
public SettingsView(
IConfigurationManager configurationManager,
ICredentialManager credentialManager,
IViewManager viewManager)
{
this.configurationManager = configurationManager.ThrowIfNull(nameof(configurationManager));
this.credentialManager = credentialManager.ThrowIfNull(nameof(credentialManager));
this.viewManager = viewManager.ThrowIfNull(nameof(viewManager));
this.InitializeComponent();
this.LoadSettings();
@@ -32,43 +60,24 @@ namespace Daybreak.Views
private void LoadSettings()
{
var config = this.configurationManager.GetConfiguration();
var creds = this.credentialManager.GetCredentials();
creds.DoAny(
onSome: (credentials) =>
{
this.UsernameTextbox.Text = credentials.Username;
this.PasswordBox.Password = credentials.Password;
});
this.AddressBarReadonlyTextbox.Text = config.AddressBarReadonly.ToString();
this.CharacterTextbox.Text = config.CharacterName;
this.GamePathTextbox.Text = config.GamePath;
this.ToolboxPathTextbox.Text = config.ToolboxPath;
this.MultiLaunchSupportTextbox.Text = config.ExperimentalFeatures.MultiLaunchSupport.ToString();
this.AddressBarReadonly = config.AddressBarReadonly;
this.ToolboxPath = config.ToolboxPath;
this.LeftBrowserUrl = config.LeftBrowserDefault;
this.RightBrowserUrl = config.RightBrowserDefault;
}
private void SaveButton_Clicked(object sender, System.EventArgs e)
private void SaveButton_Clicked(object sender, EventArgs e)
{
var currentConfig = this.configurationManager.GetConfiguration();
currentConfig.CharacterName = this.CharacterTextbox.Text;
currentConfig.GamePath = this.GamePathTextbox.Text;
currentConfig.ToolboxPath = this.ToolboxPathTextbox.Text;
if (bool.TryParse(this.AddressBarReadonlyTextbox.Text, out var addressBarReadonly))
{
currentConfig.AddressBarReadonly = addressBarReadonly;
}
if (bool.TryParse(this.MultiLaunchSupportTextbox.Text, out var multiLaunchSupport))
{
currentConfig.ExperimentalFeatures.MultiLaunchSupport = multiLaunchSupport;
}
currentConfig.ToolboxPath = this.ToolboxPath;
currentConfig.AddressBarReadonly = this.AddressBarReadonly;
currentConfig.LeftBrowserDefault = this.LeftBrowserUrl;
currentConfig.RightBrowserDefault = this.RightBrowserUrl;
this.configurationManager.SaveConfiguration(currentConfig);
this.credentialManager.StoreCredentials(new LoginCredentials { Username = this.UsernameTextbox.Text, Password = this.PasswordBox.Password });
this.viewManager.ShowView<MainView>();
this.viewManager.ShowView<SettingsCategoryView>();
}
private void GameFilePickerGlyph_Clicked(object sender, System.EventArgs e)
private void ToolboxFilePickerGlyph_Clicked(object sender, EventArgs e)
{
var filePicker = new OpenFileDialog()
{
@@ -79,28 +88,23 @@ namespace Daybreak.Views
};
if (filePicker.ShowDialog() is true)
{
this.GamePathTextbox.Text = filePicker.FileName;
this.ToolboxPath = filePicker.FileName;
}
}
private void ToolboxFilePickerGlyph_Clicked(object sender, System.EventArgs e)
private void BackButton_Clicked(object sender, EventArgs e)
{
var filePicker = new OpenFileDialog()
{
CheckFileExists = true,
CheckPathExists = true,
DefaultExt = "exe",
Multiselect = false
};
if (filePicker.ShowDialog() is true)
{
this.ToolboxPathTextbox.Text = filePicker.FileName;
}
this.viewManager.ShowView<SettingsCategoryView>();
}
private void BackButton_Clicked(object sender, System.EventArgs e)
private void LeftBrowserUrl_TextChanged(object sender, TextChangedEventArgs e)
{
this.viewManager.ShowView<MainView>();
this.LeftBrowserUrl = sender.As<TextBox>().Text;
}
private void RightBrowserUrl_TextChanged(object sender, TextChangedEventArgs e)
{
this.RightBrowserUrl = sender.As<TextBox>().Text;
}
}
}
+22
View File
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
</windowsSettings>
</application>
</assembly>