mirror of
https://github.com/gwdevhub/Daybreak.git
synced 2026-09-16 05:19:23 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d2bada4159 | ||
|
|
b27998d7f2 | ||
|
|
98d3e21db9 | ||
|
|
0683504330 | ||
|
|
98bd1b2de6 | ||
|
|
c169ca1684 | ||
|
|
88214ea166 | ||
|
|
4bdcd1a811 | ||
|
|
fa4f665a3e | ||
|
|
e59e022c0a | ||
|
|
d096dc696a | ||
|
|
071007c3e5 | ||
|
|
57192d5043 | ||
|
|
6af72683a8 | ||
|
|
3af9567506 | ||
|
|
1d7adf3944 | ||
|
|
fb7399adf8 | ||
|
|
6ebbffdda1 | ||
|
|
2c35333cac |
@@ -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,24 +1,30 @@
|
||||
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("BrowsersEnabled")]
|
||||
public bool BrowsersEnabled { get; set; } = true;
|
||||
[JsonProperty("ToolboxPath")]
|
||||
public string ToolboxPath { get; set; }
|
||||
[JsonProperty("CharacterName")]
|
||||
public string CharacterName { get; set; }
|
||||
[JsonProperty("TexmodPath")]
|
||||
public string TexmodPath { get; set; }
|
||||
[JsonProperty("ToolboxAutoLaunch")]
|
||||
public bool ToolboxAutoLaunch { get; set; }
|
||||
[JsonProperty("LeftBrowserDefault")]
|
||||
public string LeftBrowserDefault { get; set; }
|
||||
public string LeftBrowserDefault { get; set; } = "https://gwpvx.fandom.com/wiki/PvX_wiki";
|
||||
[JsonProperty("RightBrowserDefault")]
|
||||
public string RightBrowserDefault { get; set; }
|
||||
[JsonProperty("ProtectedUsername")]
|
||||
public string ProtectedUsername { get; set; }
|
||||
[JsonProperty("ProtectedPassword")]
|
||||
public string ProtectedPassword { get; set; }
|
||||
public string RightBrowserDefault { get; set; } = "https://wiki.guildwars.com/wiki/Quick_access_links";
|
||||
[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")]
|
||||
public ExperimentalFeatures ExperimentalFeatures { get; set; } = new();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Daybreak.Configuration
|
||||
{
|
||||
public sealed class ExperimentalFeatures
|
||||
{
|
||||
[JsonProperty("MultiLaunchSupport")]
|
||||
public bool MultiLaunchSupport { get; set; }
|
||||
[JsonProperty("ToolboxAutoLaunchDelay")]
|
||||
public int ToolboxAutoLaunchDelay { get; set; } = 5000;
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
using Daybreak.Services.ApplicationDetection;
|
||||
using Daybreak.Services.ApplicationLauncher;
|
||||
using Daybreak.Services.ApplicationLifetime;
|
||||
using Daybreak.Services.Bloogum;
|
||||
using Daybreak.Services.Configuration;
|
||||
using Daybreak.Services.Credentials;
|
||||
using Daybreak.Services.Logging;
|
||||
using Daybreak.Services.Mutex;
|
||||
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;
|
||||
|
||||
@@ -26,12 +26,12 @@ 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>();
|
||||
serviceProducer.RegisterSingleton<IApplicationUpdater, ApplicationUpdater>();
|
||||
serviceProducer.RegisterSingleton<CoreWebView2Environment, CoreWebView2Environment>((sp) => TaskExtensions.RunSync(() => CoreWebView2Environment.CreateAsync(null, "BrowserData", null)));
|
||||
serviceProducer.RegisterSingleton<IMutexHandler, MutexHandler>();
|
||||
}
|
||||
public static void RegisterLifetimeServices(IApplicationLifetimeProducer applicationLifetimeProducer)
|
||||
{
|
||||
@@ -49,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>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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, UpdateSourceTrigger=PropertyChanged}" 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, UpdateSourceTrigger=PropertyChanged}" 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>
|
||||
@@ -0,0 +1,88 @@
|
||||
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.DataContext.As<LoginCredentials>().Username = this.Username;
|
||||
}
|
||||
|
||||
private void CharacterNameTextbox_TextChanged(object sender, EventArgs e)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,8 +19,9 @@
|
||||
<RowDefinition Height="*"></RowDefinition>
|
||||
<RowDefinition Height="auto"></RowDefinition>
|
||||
</Grid.RowDefinitions>
|
||||
<wv2:WebView2 x:Name="WebBrowser" Source="{Binding ElementName=_this, Path=Address, Mode=TwoWay}"></wv2:WebView2>
|
||||
<Grid Grid.Row="1" Background="#80808080">
|
||||
<wv2:WebView2 x:Name="WebBrowser" Source="{Binding ElementName=_this, Path=Address, Mode=TwoWay}"
|
||||
IsEnabled="{Binding ElementName=_this, Path=BrowserSupported, Mode=OneWay}"></wv2:WebView2>
|
||||
<Grid Grid.Row="1" Background="#80808080" IsEnabled="{Binding ElementName=_this, Path=BrowserSupported, Mode=OneWay}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"></ColumnDefinition>
|
||||
<ColumnDefinition Width="*"></ColumnDefinition>
|
||||
@@ -51,15 +52,32 @@
|
||||
Grid.Column="1" IsReadOnly="{Binding ElementName=_this, Path=AddressBarReadonly, Mode=OneWay}" Background="Transparent"
|
||||
BorderThickness="1" VerticalAlignment="Center" VerticalContentAlignment="Center"
|
||||
BorderBrush="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
|
||||
PreviewKeyDown="TextBox_PreviewKeyDown"></TextBox>
|
||||
PreviewKeyDown="TextBox_PreviewKeyDown"
|
||||
IsEnabled="{Binding ElementName=_this, Path=BrowserSupported, Mode=OneWay}"></TextBox>
|
||||
<StackPanel Grid.Column="2" Orientation="Horizontal">
|
||||
<local:StarGlyph Height="30" Width="30" Margin="5"
|
||||
Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
|
||||
IsEnabled="{Binding ElementName=_this, Path=BrowserSupported, Mode=OneWay}"
|
||||
Clicked="StarGlyph_Clicked" x:Name="FavoriteButton"></local:StarGlyph>
|
||||
<local:MaximizeButton Height="30" Width="30" Margin="5"
|
||||
Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
|
||||
IsEnabled="{Binding ElementName=_this, Path=BrowserSupported, Mode=OneWay}"
|
||||
Clicked="MaximizeButton_Clicked"></local:MaximizeButton>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<Grid Grid.RowSpan="2" Background="Gray"
|
||||
Visibility="{Binding ElementName=_this, Path=BrowserSupported, Mode=OneWay,Converter={StaticResource BooleanToVisibilityConverter}}">
|
||||
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
|
||||
<TextBlock Foreground="White" Text="Browser not supported." FontSize="26" TextWrapping="Wrap"></TextBlock>
|
||||
<TextBlock Foreground="White" Text="Download the Evergreen Bootstrapper from here:" FontSize="26" TextWrapping="Wrap" />
|
||||
<TextBox Background="Transparent" BorderBrush="Transparent" BorderThickness="0"
|
||||
Text="https://go.microsoft.com/fwlink/p/?LinkId=2124703"
|
||||
IsReadOnly="True" Margin="0, 0, 0, 30" FontSize="22" Foreground="Blue"
|
||||
PreviewMouseLeftButtonDown="Hyperlink_PreviewMouseLeftButtonDown" Cursor="Hand"
|
||||
TextWrapping="Wrap"></TextBox>
|
||||
<TextBlock Foreground="White" Text="Restart after the installation." FontSize="26" TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
using Daybreak.Launch;
|
||||
using Daybreak.Services.Configuration;
|
||||
using Daybreak.Services.Logging;
|
||||
using Daybreak.Utils;
|
||||
using Microsoft.Web.WebView2.Core;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Extensions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Extensions;
|
||||
@@ -14,16 +18,21 @@ namespace Daybreak.Controls
|
||||
/// </summary>
|
||||
public partial class ChromiumBrowserWrapper : UserControl
|
||||
{
|
||||
private const string BrowserDownloadLink = "https://developer.microsoft.com/en-us/microsoft-edge/webview2/";
|
||||
|
||||
public readonly static DependencyProperty AddressProperty = DependencyPropertyExtensions.Register<ChromiumBrowserWrapper, string>(nameof(Address));
|
||||
public readonly static DependencyProperty FavoriteAddressProperty = DependencyPropertyExtensions.Register<ChromiumBrowserWrapper, string>(nameof(FavoriteAddress));
|
||||
public readonly static DependencyProperty NavigatingProperty = DependencyPropertyExtensions.Register<ChromiumBrowserWrapper, bool>(nameof(Navigating));
|
||||
public readonly static DependencyProperty BrowserEnabledProperty = DependencyPropertyExtensions.Register<ChromiumBrowserWrapper, bool>(nameof(BrowserEnabled));
|
||||
public readonly static DependencyProperty AddressBarReadonlyProperty = DependencyPropertyExtensions.Register<ChromiumBrowserWrapper, bool>(nameof(AddressBarReadonly));
|
||||
public readonly static DependencyProperty BrowserSupportedProperty = DependencyPropertyExtensions.Register<ChromiumBrowserWrapper, bool>(nameof(BrowserSupported), new PropertyMetadata(true));
|
||||
|
||||
public event EventHandler<string> FavoriteUriChanged;
|
||||
public event EventHandler MaximizeClicked;
|
||||
|
||||
private readonly CoreWebView2Environment coreWebView2Environment;
|
||||
private readonly IConfigurationManager configurationManager;
|
||||
private readonly ILogger logger;
|
||||
private CoreWebView2Environment coreWebView2Environment;
|
||||
|
||||
public string Address
|
||||
{
|
||||
@@ -45,12 +54,23 @@ namespace Daybreak.Controls
|
||||
get => this.GetTypedValue<bool>(AddressBarReadonlyProperty);
|
||||
private set => this.SetTypedValue<bool>(AddressBarReadonlyProperty, value);
|
||||
}
|
||||
public bool BrowserEnabled
|
||||
{
|
||||
get => this.GetTypedValue<bool>(BrowserEnabledProperty);
|
||||
private set => this.SetTypedValue<bool>(BrowserEnabledProperty, value);
|
||||
}
|
||||
public bool BrowserSupported
|
||||
{
|
||||
get => this.GetTypedValue<bool>(BrowserSupportedProperty);
|
||||
private set => this.SetTypedValue<bool>(BrowserSupportedProperty, value);
|
||||
}
|
||||
|
||||
public ChromiumBrowserWrapper()
|
||||
{
|
||||
this.coreWebView2Environment = Launcher.ApplicationServiceManager.GetService<CoreWebView2Environment>();
|
||||
this.configurationManager = Launcher.ApplicationServiceManager.GetService<IConfigurationManager>();
|
||||
this.logger = Launcher.ApplicationServiceManager.GetService<ILogger>();
|
||||
this.InitializeComponent();
|
||||
this.InitializeEnvironment();
|
||||
this.InitializeBrowser();
|
||||
}
|
||||
|
||||
@@ -63,18 +83,62 @@ namespace Daybreak.Controls
|
||||
}
|
||||
}
|
||||
|
||||
public void ReinitializeBrowser()
|
||||
public async void ReinitializeBrowser()
|
||||
{
|
||||
this.InitializeBrowser();
|
||||
await this.InitializeBrowser();
|
||||
}
|
||||
|
||||
private async void InitializeBrowser()
|
||||
private void InitializeEnvironment()
|
||||
{
|
||||
await this.WebBrowser.EnsureCoreWebView2Async(this.coreWebView2Environment);
|
||||
this.AddressBarReadonly = this.configurationManager.GetConfiguration().AddressBarReadonly;
|
||||
this.WebBrowser.CoreWebView2.NewWindowRequested += (browser, args) => args.Handled = true;
|
||||
this.WebBrowser.NavigationStarting += (browser, args) => this.Navigating = true;
|
||||
this.WebBrowser.NavigationCompleted += (browser, args) => this.Navigating = false;
|
||||
if (this.configurationManager.GetConfiguration().BrowsersEnabled is false)
|
||||
{
|
||||
this.BrowserSupported = false;
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
this.coreWebView2Environment = System.Extensions.TaskExtensions.RunSync(() => CoreWebView2Environment.CreateAsync(null, "BrowserData", null));
|
||||
this.BrowserSupported = true;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
this.logger.LogWarning($"Browser initialization failed. Details: {e}");
|
||||
this.BrowserSupported = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task InitializeBrowser()
|
||||
{
|
||||
if (this.BrowserSupported is true)
|
||||
{
|
||||
await this.WebBrowser.EnsureCoreWebView2Async(this.coreWebView2Environment);
|
||||
this.AddressBarReadonly = this.configurationManager.GetConfiguration().AddressBarReadonly;
|
||||
this.WebBrowser.CoreWebView2.NewWindowRequested += (browser, args) => args.Handled = true;
|
||||
this.WebBrowser.NavigationStarting += (browser, args) => this.Navigating = true;
|
||||
this.WebBrowser.NavigationCompleted += (browser, args) => this.Navigating = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async void RetryInitializeButton_Clicked(object sender, EventArgs e)
|
||||
{
|
||||
this.InitializeEnvironment();
|
||||
try
|
||||
{
|
||||
await this.InitializeBrowser();
|
||||
}
|
||||
catch
|
||||
{
|
||||
this.BrowserSupported = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void Hyperlink_PreviewMouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
|
||||
{
|
||||
if (Uri.TryCreate(BrowserDownloadLink, UriKind.Absolute, out var uri))
|
||||
{
|
||||
Process.Start("explorer.exe", uri.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private void TextBox_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
|
||||
|
||||
@@ -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>
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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, UpdateSourceTrigger=PropertyChanged}"
|
||||
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,79 @@
|
||||
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.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
@@ -9,13 +9,15 @@
|
||||
<CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<ApplicationIcon>Daybreak.ico</ApplicationIcon>
|
||||
<Version>0.2.2</Version>
|
||||
<Version>0.6.4</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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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,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,85 +0,0 @@
|
||||
using Daybreak.Services.Configuration;
|
||||
using Daybreak.Services.Credentials;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Extensions;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Daybreak.Services.ApplicationDetection
|
||||
{
|
||||
public class ApplicationDetector : IApplicationDetector
|
||||
{
|
||||
private const string ToolboxProcessName = "GWToolbox";
|
||||
private const string ProcessName = "gw";
|
||||
|
||||
private readonly IConfigurationManager configurationManager;
|
||||
private readonly ICredentialManager credentialManager;
|
||||
|
||||
public bool IsGuildwarsRunning => GuildwarsProcessDetected();
|
||||
public bool IsToolboxRunning => GuildwarsToolboxProcessDetected();
|
||||
|
||||
public ApplicationDetector(
|
||||
IConfigurationManager configurationManager,
|
||||
ICredentialManager credentialManager)
|
||||
{
|
||||
this.credentialManager = credentialManager.ThrowIfNull(nameof(credentialManager));
|
||||
this.configurationManager = configurationManager.ThrowIfNull(nameof(configurationManager));
|
||||
}
|
||||
|
||||
public void LaunchGuildwars()
|
||||
{
|
||||
var configuration = this.configurationManager.GetConfiguration();
|
||||
var executable = configuration.GamePath;
|
||||
if (File.Exists(executable) is false)
|
||||
{
|
||||
throw new InvalidOperationException($"Guildwars executable doesn't exist at {executable}");
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(configuration.CharacterName))
|
||||
{
|
||||
throw new InvalidOperationException($"No character name set");
|
||||
}
|
||||
|
||||
var auth = this.credentialManager.GetCredentials();
|
||||
auth.Do(
|
||||
onSome: (credentials) =>
|
||||
{
|
||||
if (Process.Start(executable, new List<string> { "-email", credentials.Username, "-password", credentials.Password, "-character", configuration.CharacterName }) is null)
|
||||
{
|
||||
throw new InvalidOperationException($"Unable to launch {executable}");
|
||||
}
|
||||
},
|
||||
onNone: () =>
|
||||
{
|
||||
throw new InvalidOperationException($"No credentials available");
|
||||
});
|
||||
}
|
||||
|
||||
public void LaunchGuildwarsToolbox()
|
||||
{
|
||||
var configuration = this.configurationManager.GetConfiguration();
|
||||
var executable = configuration.ToolboxPath;
|
||||
if (File.Exists(executable) is false)
|
||||
{
|
||||
throw new InvalidOperationException($"Guildwars executable doesn't exist at {executable}");
|
||||
}
|
||||
|
||||
if (Process.Start(executable) is null)
|
||||
{
|
||||
throw new InvalidOperationException($"Unable to launch {executable}");
|
||||
}
|
||||
}
|
||||
|
||||
private static bool GuildwarsProcessDetected()
|
||||
{
|
||||
return Process.GetProcessesByName(ProcessName).FirstOrDefault() is not null;
|
||||
}
|
||||
|
||||
private static bool GuildwarsToolboxProcessDetected()
|
||||
{
|
||||
return Process.GetProcessesByName(ToolboxProcessName).FirstOrDefault() is not null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
namespace Daybreak.Services.ApplicationDetection
|
||||
{
|
||||
public interface IApplicationDetector
|
||||
{
|
||||
bool IsGuildwarsRunning { get; }
|
||||
bool IsToolboxRunning { get; }
|
||||
void LaunchGuildwars();
|
||||
void LaunchGuildwarsToolbox();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
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.Security;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Daybreak.Services.ApplicationLauncher
|
||||
{
|
||||
public class ApplicationLauncher : IApplicationLauncher
|
||||
{
|
||||
private const string TexModProcessName = "TexMod";
|
||||
private const string UModProcessName = "uMod";
|
||||
private const string ToolboxProcessName = "GWToolbox";
|
||||
private const string ProcessName = "gw";
|
||||
private const string ArenaNetMutex = "AN-Mute";
|
||||
|
||||
private readonly IConfigurationManager configurationManager;
|
||||
private readonly ICredentialManager credentialManager;
|
||||
private readonly IMutexHandler mutexHandler;
|
||||
private readonly ILogger logger;
|
||||
|
||||
public bool IsTexmodRunning => TexModProcessDetected();
|
||||
public bool IsGuildwarsRunning => this.GuildwarsProcessDetected();
|
||||
public bool IsToolboxRunning => GuildwarsToolboxProcessDetected();
|
||||
|
||||
public ApplicationLauncher(
|
||||
IConfigurationManager configurationManager,
|
||||
ICredentialManager credentialManager,
|
||||
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 async Task LaunchGuildwars()
|
||||
{
|
||||
var configuration = this.configurationManager.GetConfiguration();
|
||||
var auth = await this.credentialManager.GetDefaultCredentials().ConfigureAwait(false);
|
||||
auth.Do(
|
||||
onSome: (credentials) =>
|
||||
{
|
||||
if (configuration.ExperimentalFeatures.MultiLaunchSupport is true)
|
||||
{
|
||||
ClearGwLocks();
|
||||
}
|
||||
|
||||
LaunchGuildwarsProcess(credentials.Username, credentials.Password, credentials.CharacterName);
|
||||
},
|
||||
onNone: () =>
|
||||
{
|
||||
throw new CredentialsNotFoundException($"No credentials available");
|
||||
});
|
||||
}
|
||||
|
||||
public Task LaunchGuildwarsToolbox()
|
||||
{
|
||||
return Task.Run(() =>
|
||||
{
|
||||
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}");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public Task LaunchTexmod()
|
||||
{
|
||||
return Task.Run(() =>
|
||||
{
|
||||
var configuration = this.configurationManager.GetConfiguration();
|
||||
var executable = configuration.TexmodPath;
|
||||
if (File.Exists(executable) is false)
|
||||
{
|
||||
throw new ExecutableNotFoundException($"Texmod executable doesn't exist at {executable}");
|
||||
}
|
||||
|
||||
if (Process.Start(executable) is null)
|
||||
{
|
||||
throw new InvalidOperationException($"Unable to launch {executable}");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void LaunchGuildwarsProcess(string email, Models.SecureString password, string character)
|
||||
{
|
||||
var executable = this.configurationManager.GetConfiguration().GuildwarsPaths.Where(path => path.Default).FirstOrDefault();
|
||||
if (executable is null)
|
||||
{
|
||||
throw new ExecutableNotFoundException($"No executable selected");
|
||||
}
|
||||
|
||||
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}");
|
||||
}
|
||||
}
|
||||
|
||||
private bool GuildwarsProcessDetected()
|
||||
{
|
||||
if (this.configurationManager.GetConfiguration().ExperimentalFeatures.MultiLaunchSupport is true)
|
||||
{
|
||||
try
|
||||
{
|
||||
var path = this.configurationManager.GetConfiguration().GuildwarsPaths.Where(path => path.Default).FirstOrDefault();
|
||||
if (path is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return Process.GetProcessesByName(ProcessName).Where(process => string.Equals(path.Path, process.MainModule.FileName, StringComparison.Ordinal)).Any();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return Process.GetProcessesByName(ProcessName).Any();
|
||||
}
|
||||
|
||||
private void ClearGwLocks()
|
||||
{
|
||||
this.SetRegistryGuildwarsPath();
|
||||
foreach (var process in Process.GetProcessesByName(ProcessName))
|
||||
{
|
||||
this.mutexHandler.CloseMutex(process, ArenaNetMutex);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetRegistryGuildwarsPath()
|
||||
{
|
||||
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 static RegistryKey GetGuildwarsRegistryKey(bool write)
|
||||
{
|
||||
var gwKey = Registry.CurrentUser.OpenSubKey("SOFTWARE")?.OpenSubKey("ArenaNet")?.OpenSubKey("Guild Wars", write);
|
||||
if (gwKey is not null)
|
||||
{
|
||||
return gwKey;
|
||||
}
|
||||
|
||||
gwKey = Registry.CurrentUser.OpenSubKey("SOFTWARE")?.OpenSubKey("WOW6432Node")?.OpenSubKey("ArenaNet")?.OpenSubKey("Guild Wars", write);
|
||||
if (gwKey is not null)
|
||||
{
|
||||
return gwKey;
|
||||
}
|
||||
|
||||
gwKey = Registry.LocalMachine.OpenSubKey("SOFTWARE")?.OpenSubKey("ArenaNet")?.OpenSubKey("Guild Wars", write);
|
||||
if (gwKey is not null)
|
||||
{
|
||||
return gwKey;
|
||||
}
|
||||
|
||||
gwKey = Registry.LocalMachine.OpenSubKey("SOFTWARE")?.OpenSubKey("WOW6432Node")?.OpenSubKey("ArenaNet")?.OpenSubKey("Guild Wars", write);
|
||||
if (gwKey is not null)
|
||||
{
|
||||
return gwKey;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("Could not find registry key for guildwars.");
|
||||
}
|
||||
|
||||
private static bool GuildwarsToolboxProcessDetected()
|
||||
{
|
||||
return Process.GetProcessesByName(ToolboxProcessName).Any();
|
||||
}
|
||||
|
||||
private static bool TexModProcessDetected()
|
||||
{
|
||||
return Process.GetProcesses()
|
||||
.Where(process => string.Equals(process.ProcessName, UModProcessName, StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(process.ProcessName, TexModProcessName, StringComparison.OrdinalIgnoreCase)).Any();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Daybreak.Services.ApplicationLauncher
|
||||
{
|
||||
public interface IApplicationLauncher
|
||||
{
|
||||
bool IsGuildwarsRunning { get; }
|
||||
bool IsToolboxRunning { get; }
|
||||
bool IsTexmodRunning { get; }
|
||||
Task LaunchGuildwars();
|
||||
Task LaunchGuildwarsToolbox();
|
||||
Task LaunchTexmod();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Daybreak.Services.Mutex
|
||||
{
|
||||
public interface IMutexHandler
|
||||
{
|
||||
void CloseMutex(Process process, string mutexName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
using Pepa.Wpf.Utilities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Daybreak.Services.Mutex
|
||||
{
|
||||
public sealed class MutexHandler : IMutexHandler
|
||||
{
|
||||
public void CloseMutex(Process process, string mutexName)
|
||||
{
|
||||
CloseHandle(process, mutexName);
|
||||
}
|
||||
|
||||
private static List<NativeMethods.SystemHandleInformation> GetHandles(Process targetProcess, IntPtr systemHandle)
|
||||
{
|
||||
var processHandles = new List<NativeMethods.SystemHandleInformation>();
|
||||
var basePointer = systemHandle.ToInt64();
|
||||
NativeMethods.SystemHandleInformation currentHandleInfo;
|
||||
for (int i = 0; i < Marshal.ReadInt32(systemHandle); i++)
|
||||
{
|
||||
var currentOffset = IntPtr.Size + i * Marshal.SizeOf(typeof(NativeMethods.SystemHandleInformation));
|
||||
currentHandleInfo = (NativeMethods.SystemHandleInformation)Marshal.PtrToStructure(new IntPtr(basePointer + currentOffset), typeof(NativeMethods.SystemHandleInformation));
|
||||
if (currentHandleInfo.OwnerPID == (uint)targetProcess.Id)
|
||||
{
|
||||
processHandles.Add(currentHandleInfo);
|
||||
}
|
||||
}
|
||||
|
||||
return processHandles;
|
||||
}
|
||||
|
||||
private static void CloseHandle(Process targetProcess, string handleName)
|
||||
{
|
||||
var systemHandles = GetAllHandles();
|
||||
if (systemHandles == IntPtr.Zero)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
List<NativeMethods.SystemHandleInformation> processHandles = GetHandles(targetProcess, systemHandles);
|
||||
Marshal.FreeHGlobal(systemHandles);
|
||||
var processHandle = NativeMethods.OpenProcess(NativeMethods.ProcessAccessFlags.DupHandle, false, (uint)targetProcess.Id);
|
||||
foreach (var handleInfo in processHandles)
|
||||
{
|
||||
if (GetHandleName(handleInfo, processHandle).Contains(handleName))
|
||||
{
|
||||
if (CloseOwnedHandle(handleInfo.OwnerPID, new IntPtr(handleInfo.HandleValue)))
|
||||
{
|
||||
NativeMethods.CloseHandle(processHandle);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NativeMethods.CloseHandle(processHandle);
|
||||
return;
|
||||
}
|
||||
|
||||
private static string GetHandleName(NativeMethods.SystemHandleInformation targetHandleInfo, IntPtr processHandle)
|
||||
{
|
||||
if (targetHandleInfo.AccessMask.ToInt64() == 0x0012019F)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var thisProcess = Process.GetCurrentProcess().Handle;
|
||||
NativeMethods.DuplicateHandle(processHandle, new IntPtr(targetHandleInfo.HandleValue), thisProcess, out var handle, 0, false, NativeMethods.DuplicateOptions.DUPLICATE_SAME_ACCESS);
|
||||
var bufferSize = GetHandleNameLength(handle);
|
||||
var stringBuffer = Marshal.AllocHGlobal(bufferSize);
|
||||
NativeMethods.NtQueryObject(handle, NativeMethods.ObjectInformationClass.ObjectNameInformation, stringBuffer, bufferSize, out _);
|
||||
NativeMethods.CloseHandle(handle);
|
||||
var handleName = ConvertToString(stringBuffer);
|
||||
Marshal.FreeHGlobal(stringBuffer);
|
||||
return handleName;
|
||||
}
|
||||
|
||||
private static IntPtr GetAllHandles()
|
||||
{
|
||||
int bufferSize = 0x10000;
|
||||
var pSysInfoBuffer = Marshal.AllocHGlobal(bufferSize);
|
||||
var queryResult = NativeMethods.NtQuerySystemInformation(NativeMethods.SystemInformationClass.SystemHandleInformation,
|
||||
pSysInfoBuffer, bufferSize, out _);
|
||||
|
||||
while (queryResult == NativeMethods.NtStatus.STATUS_INFO_LENGTH_MISMATCH)
|
||||
{
|
||||
Marshal.FreeHGlobal(pSysInfoBuffer);
|
||||
bufferSize *= 2;
|
||||
pSysInfoBuffer = Marshal.AllocHGlobal(bufferSize);
|
||||
queryResult = NativeMethods.NtQuerySystemInformation(NativeMethods.SystemInformationClass.SystemHandleInformation,
|
||||
pSysInfoBuffer, bufferSize, out _);
|
||||
}
|
||||
|
||||
if (queryResult == NativeMethods.NtStatus.STATUS_SUCCESS)
|
||||
{
|
||||
return pSysInfoBuffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
Marshal.FreeHGlobal(pSysInfoBuffer);
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
private static int GetHandleNameLength(IntPtr handle)
|
||||
{
|
||||
var infoBufferSize = Marshal.SizeOf(typeof(NativeMethods.ObjectBasicInformation));
|
||||
var pInfoBuffer = Marshal.AllocHGlobal(infoBufferSize);
|
||||
NativeMethods.NtQueryObject(handle, NativeMethods.ObjectInformationClass.ObjectBasicInformation, pInfoBuffer, infoBufferSize, out _);
|
||||
NativeMethods.ObjectBasicInformation objInfo = (NativeMethods.ObjectBasicInformation)Marshal.PtrToStructure(pInfoBuffer, typeof(NativeMethods.ObjectBasicInformation));
|
||||
Marshal.FreeHGlobal(pInfoBuffer);
|
||||
if (objInfo.NameInformationLength == 0)
|
||||
{
|
||||
return 0x100;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (int)objInfo.NameInformationLength;
|
||||
}
|
||||
}
|
||||
|
||||
private static string ConvertToString(IntPtr stringBuffer)
|
||||
{
|
||||
var baseAddress = stringBuffer.ToInt64();
|
||||
var offset = IntPtr.Size * 2;
|
||||
var handleName = Marshal.PtrToStringUni(new IntPtr(baseAddress + offset));
|
||||
return handleName;
|
||||
}
|
||||
|
||||
private static bool CloseOwnedHandle(uint processId, IntPtr handleToClose)
|
||||
{
|
||||
var processHandle = NativeMethods.OpenProcess(NativeMethods.ProcessAccessFlags.All, false, processId);
|
||||
var success = NativeMethods.DuplicateHandle(processHandle, handleToClose, IntPtr.Zero, out _, 0, false, NativeMethods.DuplicateOptions.DUPLICATE_CLOSE_SOURCE);
|
||||
NativeMethods.CloseHandle(processHandle);
|
||||
return success;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -1,13 +1,109 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.ComTypes;
|
||||
using System.Text;
|
||||
|
||||
namespace Pepa.Wpf.Utilities
|
||||
{
|
||||
static class NativeMethods
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct SystemHandleInformation
|
||||
{
|
||||
public uint OwnerPID;
|
||||
public byte ObjectType;
|
||||
public byte HandleFlags;
|
||||
public ushort HandleValue;
|
||||
public UIntPtr ObjectPointer;
|
||||
public IntPtr AccessMask;
|
||||
}
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct ObjectBasicInformation
|
||||
{
|
||||
public uint Attributes;
|
||||
public uint GrantedAccess;
|
||||
public uint HandleCount;
|
||||
public uint PointerCount;
|
||||
public uint PagedPoolUsage;
|
||||
public uint NonPagedPoolUsage;
|
||||
public uint Reserved1;
|
||||
public uint Reserved2;
|
||||
public uint Reserved3;
|
||||
public uint NameInformationLength;
|
||||
public uint TypeInformationLength;
|
||||
public uint SecurityDescriptorLength;
|
||||
public FILETIME CreateTime;
|
||||
}
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct IoStatusBlock
|
||||
{
|
||||
public uint Status;
|
||||
public ulong Information;
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum DuplicateOptions : uint
|
||||
{
|
||||
DUPLICATE_CLOSE_SOURCE = 0x00000001,
|
||||
DUPLICATE_SAME_ACCESS = 0x00000002
|
||||
}
|
||||
[Flags]
|
||||
public enum ProcessAccessFlags : uint
|
||||
{
|
||||
All = 0x001F0FFF,
|
||||
Terminate = 0x00000001,
|
||||
CreateThread = 0x00000002,
|
||||
VMOperation = 0x00000008,
|
||||
VMRead = 0x00000010,
|
||||
VMWrite = 0x00000020,
|
||||
DupHandle = 0x00000040,
|
||||
SetInformation = 0x00000200,
|
||||
QueryInformation = 0x00000400,
|
||||
Synchronize = 0x00100000
|
||||
}
|
||||
[Flags]
|
||||
public enum NtStatus : uint
|
||||
{
|
||||
STATUS_SUCCESS = 0x00000000,
|
||||
STATUS_INFO_LENGTH_MISMATCH = 0xC0000004
|
||||
}
|
||||
[Flags]
|
||||
public enum ObjectInformationClass : uint
|
||||
{
|
||||
ObjectBasicInformation = 0,
|
||||
ObjectNameInformation = 1,
|
||||
ObjectTypeInformation = 2,
|
||||
ObjectAllTypesInformation = 3,
|
||||
ObjectHandleInformation = 4
|
||||
}
|
||||
[Flags]
|
||||
public enum SystemInformationClass : uint
|
||||
{
|
||||
SystemHandleInformation = 16
|
||||
}
|
||||
[Flags]
|
||||
public enum FileInformationClass
|
||||
{
|
||||
FileNameInformation = 9
|
||||
}
|
||||
|
||||
public const int WM_SYSCOMMAND = 0x112;
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto)]
|
||||
public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern bool CloseHandle(IntPtr hObject);
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern bool DuplicateHandle(IntPtr hSourceProcessHandle, IntPtr hSourceHandle, IntPtr hTargetProcessHandle, out IntPtr lpTargetHandle, uint dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, DuplicateOptions dwOptions);
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, bool bInheritHandle, uint dwProcessID);
|
||||
[DllImport("ntdll.dll", SetLastError = true)]
|
||||
public static extern NtStatus NtQueryInformationFile(IntPtr FileHandle, ref IoStatusBlock IoStatusBlock, IntPtr FileInformation, int FileInformationLength, FileInformationClass FileInformationClass);
|
||||
[DllImport("ntdll.dll")]
|
||||
public static extern NtStatus NtQueryObject(IntPtr ObjectHandle, ObjectInformationClass ObjectInformationClass, IntPtr ObjectInformation, int ObjectInformationLength, out int ReturnLength);
|
||||
[DllImport("ntdll.dll")]
|
||||
public static extern NtStatus NtQuerySystemInformation(SystemInformationClass SystemInformationClass, IntPtr SystemInformation, int SystemInformationLength, out int ReturnLength);
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern bool QueryFullProcessImageName(IntPtr hProcess, uint dwFlags, StringBuilder lpExeName, ref uint lpdwSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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>
|
||||
@@ -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,103 @@
|
||||
<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="Stretch" Margin="0, 15, 0, 0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"></ColumnDefinition>
|
||||
<ColumnDefinition Width="*"></ColumnDefinition>
|
||||
</Grid.ColumnDefinitions>
|
||||
<StackPanel>
|
||||
<TextBlock Text="Multi-launch support" Foreground="White" FontSize="22" VerticalAlignment="Center" Margin="0, 0, 15, 0" Height="30"></TextBlock>
|
||||
<TextBlock Text="GWToolbox startup delay (in ms)" Foreground="White" FontSize="22" VerticalAlignment="Center" Margin="0, 0, 15, 0" Height="30"></TextBlock>
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="1">
|
||||
<ToggleButton IsChecked="{Binding ElementName=_this, Path=MultiLaunch, Mode=TwoWay}" Style="{StaticResource AnimatedSwitch}"
|
||||
Height="30" Width="60"></ToggleButton>
|
||||
<TextBox Background="Transparent" Foreground="White" FontSize="16" Height="30"
|
||||
PreviewTextInput="TextBox_AllowNumbersOnly" Text="{Binding ElementName=_this, Path=GWToolboxLaunchDelay, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
CommandManager.PreviewCanExecute="TextBox_DisallowPaste"></TextBox>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,91 @@
|
||||
using Daybreak.Services.Configuration;
|
||||
using Daybreak.Services.ViewManagement;
|
||||
using System;
|
||||
using System.Extensions;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Extensions;
|
||||
using System.Windows.Input;
|
||||
|
||||
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));
|
||||
public static readonly DependencyProperty GWToolboxLaunchDelayProperty =
|
||||
DependencyPropertyExtensions.Register<ExperimentalSettingsView, string>(nameof(GWToolboxLaunchDelay));
|
||||
|
||||
private readonly IViewManager viewManager;
|
||||
private readonly IConfigurationManager configurationManager;
|
||||
|
||||
public bool MultiLaunch
|
||||
{
|
||||
get => this.GetTypedValue<bool>(MultiLaunchProperty);
|
||||
set => this.SetValue(MultiLaunchProperty, value);
|
||||
}
|
||||
public string GWToolboxLaunchDelay
|
||||
{
|
||||
get => this.GetTypedValue<string>(GWToolboxLaunchDelayProperty);
|
||||
set => this.SetValue(GWToolboxLaunchDelayProperty, 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;
|
||||
this.GWToolboxLaunchDelay = config.ExperimentalFeatures.ToolboxAutoLaunchDelay.ToString();
|
||||
}
|
||||
|
||||
private void SaveExperimentalSettings()
|
||||
{
|
||||
var config = this.configurationManager.GetConfiguration();
|
||||
config.ExperimentalFeatures.MultiLaunchSupport = this.MultiLaunch;
|
||||
if (int.TryParse(this.GWToolboxLaunchDelay, out var gwToolboxLaunchDelay))
|
||||
{
|
||||
config.ExperimentalFeatures.ToolboxAutoLaunchDelay = gwToolboxLaunchDelay;
|
||||
}
|
||||
|
||||
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>();
|
||||
}
|
||||
|
||||
private void TextBox_AllowNumbersOnly(object sender, TextCompositionEventArgs e)
|
||||
{
|
||||
e.Handled = e.Text.Select(c => char.IsDigit(c)).All(result => result is true) is false;
|
||||
}
|
||||
|
||||
private void TextBox_DisallowPaste(object sender, CanExecuteRoutedEventArgs e)
|
||||
{
|
||||
if (e.Command == ApplicationCommands.ContextMenu || e.Command == ApplicationCommands.Paste)
|
||||
{
|
||||
e.CanExecute = false;
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,14 +31,18 @@
|
||||
<controls:OpaqueButton Text="Launch toolbox" Highlight="White" TransparentBackground="Black" HighlightOpacity="0.3" BackgroundOpacity="0.2"
|
||||
Foreground="White" FontSize="24" Width="200" Height="40" Margin="0, 10, 0, 10"
|
||||
IsEnabled="{Binding ElementName=_this, Path=LaunchToolboxButtonEnabled, Mode=OneWay}"
|
||||
Clicked="LaunchToolboxButton_Clicked" Grid.Row="1" Grid.ColumnSpan="3"></controls:OpaqueButton>
|
||||
<Grid x:Name="RightContainer" Grid.Column="2" Margin="10">
|
||||
Clicked="LaunchToolboxButton_Clicked" Grid.Row="1" Grid.ColumnSpan="2"></controls:OpaqueButton>
|
||||
<controls:OpaqueButton Text="Launch texmod" Highlight="White" TransparentBackground="Black" HighlightOpacity="0.3" BackgroundOpacity="0.2"
|
||||
Foreground="White" FontSize="24" Width="200" Height="40" Margin="0, 10, 0, 10"
|
||||
IsEnabled="{Binding ElementName=_this, Path=LaunchTexmodButtonEnabled, Mode=OneWay}"
|
||||
Clicked="LaunchTexmodButton_Clicked" Grid.Row="1" Grid.ColumnSpan="2" Grid.Column="1"></controls:OpaqueButton>
|
||||
<Grid Grid.Column="2" Margin="10" Visibility="{Binding ElementName=_this, Path=BrowsersEnabled, Mode=OneWay, Converter={StaticResource BooleanToVisibility}}">
|
||||
<controls:ChromiumBrowserWrapper Address="{Binding ElementName=_this, Path=RightBrowserAddress, Mode=OneWay}"
|
||||
Foreground="White" FavoriteUriChanged="RightBrowser_FavoriteUriChanged"
|
||||
FavoriteAddress="{Binding ElementName=_this, Path=RightBrowserFavoriteAddress, Mode=OneWay}"
|
||||
MaximizeClicked="RightChromiumBrowserWrapper_MaximizeClicked"/>
|
||||
</Grid>
|
||||
<Grid x:Name="LeftContainer" Grid.Column="0" Margin="10">
|
||||
<Grid Grid.Column="0" Margin="10" Visibility="{Binding ElementName=_this, Path=BrowsersEnabled, Mode=OneWay, Converter={StaticResource BooleanToVisibility}}">
|
||||
<controls:ChromiumBrowserWrapper Address="{Binding ElementName=_this, Path=LeftBrowserAddress, Mode=OneWay}"
|
||||
Foreground="White" FavoriteUriChanged="LeftBrowser_FavoriteUriChanged"
|
||||
FavoriteAddress="{Binding ElementName=_this, Path=LeftBrowserFavoriteAddress, Mode=OneWay}"
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
using Daybreak.Controls;
|
||||
using Daybreak.Services.ApplicationDetection;
|
||||
using Daybreak.Exceptions;
|
||||
using Daybreak.Services.ApplicationLauncher;
|
||||
using Daybreak.Services.Configuration;
|
||||
using Daybreak.Services.ViewManagement;
|
||||
using System;
|
||||
using System.Extensions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Extensions;
|
||||
@@ -20,6 +22,10 @@ namespace Daybreak.Views
|
||||
DependencyPropertyExtensions.Register<MainView, bool>(nameof(LaunchButtonEnabled));
|
||||
public static readonly DependencyProperty LaunchToolboxButtonEnabledProperty =
|
||||
DependencyPropertyExtensions.Register<MainView, bool>(nameof(LaunchToolboxButtonEnabled));
|
||||
public static readonly DependencyProperty LaunchTexmodButtonEnabledProperty =
|
||||
DependencyPropertyExtensions.Register<MainView, bool>(nameof(LaunchTexmodButtonEnabled));
|
||||
public static readonly DependencyProperty BrowsersEnabledProperty =
|
||||
DependencyPropertyExtensions.Register<MainView, bool>(nameof(BrowsersEnabled), new PropertyMetadata(true));
|
||||
public static readonly DependencyProperty RightBrowserAddressProperty =
|
||||
DependencyPropertyExtensions.Register<MainView, string>(nameof(RightBrowserAddress));
|
||||
public static readonly DependencyProperty LeftBrowserAddressProperty =
|
||||
@@ -29,7 +35,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();
|
||||
@@ -67,9 +73,19 @@ namespace Daybreak.Views
|
||||
get => this.GetTypedValue<bool>(LaunchToolboxButtonEnabledProperty);
|
||||
set => this.SetTypedValue(LaunchToolboxButtonEnabledProperty, value);
|
||||
}
|
||||
public bool LaunchTexmodButtonEnabled
|
||||
{
|
||||
get => this.GetTypedValue<bool>(LaunchTexmodButtonEnabledProperty);
|
||||
set => this.SetTypedValue(LaunchTexmodButtonEnabledProperty, value);
|
||||
}
|
||||
public bool BrowsersEnabled
|
||||
{
|
||||
get => this.GetTypedValue<bool>(BrowsersEnabledProperty);
|
||||
set => this.SetTypedValue(BrowsersEnabledProperty, value);
|
||||
}
|
||||
|
||||
public MainView(
|
||||
IApplicationDetector applicationDetector,
|
||||
IApplicationLauncher applicationDetector,
|
||||
IViewManager viewManager,
|
||||
IConfigurationManager configurationManager)
|
||||
{
|
||||
@@ -84,10 +100,17 @@ namespace Daybreak.Views
|
||||
private void NavigateToDefaults()
|
||||
{
|
||||
var applicationConfiguration = this.configurationManager.GetConfiguration();
|
||||
this.LeftBrowserFavoriteAddress = applicationConfiguration.LeftBrowserDefault;
|
||||
this.RightBrowserFavoriteAddress = applicationConfiguration.RightBrowserDefault;
|
||||
this.LeftBrowserAddress = applicationConfiguration.LeftBrowserDefault;
|
||||
this.RightBrowserAddress = applicationConfiguration.RightBrowserDefault;
|
||||
if (applicationConfiguration.BrowsersEnabled)
|
||||
{
|
||||
this.LeftBrowserFavoriteAddress = applicationConfiguration.LeftBrowserDefault;
|
||||
this.RightBrowserFavoriteAddress = applicationConfiguration.RightBrowserDefault;
|
||||
this.LeftBrowserAddress = applicationConfiguration.LeftBrowserDefault;
|
||||
this.RightBrowserAddress = applicationConfiguration.RightBrowserDefault;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.BrowsersEnabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void PeriodicallyCheckGameState()
|
||||
@@ -97,8 +120,9 @@ namespace Daybreak.Views
|
||||
|
||||
private void CheckGameState()
|
||||
{
|
||||
this.LaunchButtonEnabled = applicationDetector.IsGuildwarsRunning is false;
|
||||
this.LaunchToolboxButtonEnabled = applicationDetector.IsToolboxRunning is false;
|
||||
this.LaunchButtonEnabled = this.applicationDetector.IsGuildwarsRunning is false;
|
||||
this.LaunchToolboxButtonEnabled = this.applicationDetector.IsToolboxRunning is false;
|
||||
this.LaunchTexmodButtonEnabled = this.applicationDetector.IsTexmodRunning is false;
|
||||
}
|
||||
|
||||
private void StartupView_Loaded(object sender, RoutedEventArgs e)
|
||||
@@ -110,15 +134,25 @@ 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();
|
||||
if (this.configurationManager.GetConfiguration().ToolboxAutoLaunch is true)
|
||||
{
|
||||
var delay = this.configurationManager.GetConfiguration().ExperimentalFeatures.ToolboxAutoLaunchDelay;
|
||||
await Task.Delay(delay);
|
||||
await this.applicationDetector.LaunchGuildwarsToolbox();
|
||||
}
|
||||
}
|
||||
catch
|
||||
catch (CredentialsNotFoundException)
|
||||
{
|
||||
this.viewManager.ShowView<SettingsView>();
|
||||
this.viewManager.ShowView<AccountsView>();
|
||||
}
|
||||
catch (ExecutableNotFoundException)
|
||||
{
|
||||
this.viewManager.ShowView<ExecutablesView>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,6 +168,18 @@ namespace Daybreak.Views
|
||||
}
|
||||
}
|
||||
|
||||
private void LaunchTexmodButton_Clicked(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.applicationDetector.LaunchTexmod();
|
||||
}
|
||||
catch
|
||||
{
|
||||
this.viewManager.ShowView<SettingsView>();
|
||||
}
|
||||
}
|
||||
|
||||
private void LeftBrowser_FavoriteUriChanged(object sender, string e)
|
||||
{
|
||||
var config = this.configurationManager.GetConfiguration();
|
||||
|
||||
@@ -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>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,47 +8,118 @@
|
||||
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>
|
||||
<RowDefinition Height="auto"></RowDefinition>
|
||||
<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"
|
||||
<StackPanel Orientation="Vertical" Grid.Row="1">
|
||||
<TextBlock Text="Texmod path" FontSize="22" Foreground="White"></TextBlock>
|
||||
<TextBlock Text="GWToolbox path: " FontSize="22" Foreground="White"></TextBlock>
|
||||
<TextBlock Text="GWToolbox auto-launch: " FontSize="22" Foreground="White"></TextBlock>
|
||||
<TextBlock Text="Browsers enabled: " FontSize="22" Foreground="White"/>
|
||||
<TextBlock Text="Browsers address bar readonly: " FontSize="22" Foreground="White"/>
|
||||
<TextBlock Text="Left browser homepage: " FontSize="22" Foreground="White"></TextBlock>
|
||||
<TextBlock Text="Right browser homepage: " FontSize="22" Foreground="White"></TextBlock>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Vertical" Grid.Row="1" Grid.Column="1">
|
||||
<Grid>
|
||||
<TextBox HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch"
|
||||
FontSize="22" Margin="0, 0, 30, 0" Background="Transparent" Foreground="White"
|
||||
Text="{Binding ElementName=_this, Path=TexmodPath, Mode=TwoWay}"></TextBox>
|
||||
<controls:FilePickerGlyph Height="30" Width="30" HorizontalAlignment="Right"
|
||||
Foreground="White" BorderBrush="Gray" BorderThickness="0"
|
||||
Clicked="TexmodFilePickerGlyph_Clicked"></controls:FilePickerGlyph>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<TextBox HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch"
|
||||
FontSize="22" Margin="0, 0, 30, 0" Background="Transparent" Foreground="White"
|
||||
Text="{Binding ElementName=_this, Path=ToolboxPath, Mode=TwoWay}"></TextBox>
|
||||
<controls:FilePickerGlyph 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>
|
||||
</Grid>
|
||||
<ToggleButton HorizontalAlignment="Center" HorizontalContentAlignment="Stretch" Style="{StaticResource AnimatedSwitch}" Height="30" Width="40"
|
||||
FontSize="22" Foreground="White" IsChecked="{Binding ElementName=_this, Path=ToolboxAutoLaunch, Mode=TwoWay}"></ToggleButton>
|
||||
<ToggleButton HorizontalAlignment="Center" HorizontalContentAlignment="Stretch" Style="{StaticResource AnimatedSwitch}" Height="30" Width="40"
|
||||
FontSize="22" Foreground="White" IsChecked="{Binding ElementName=_this, Path=BrowsersEnabled, Mode=TwoWay}"></ToggleButton>
|
||||
<ToggleButton HorizontalAlignment="Center" HorizontalContentAlignment="Stretch" Style="{StaticResource AnimatedSwitch}" Height="30" Width="40"
|
||||
FontSize="22" Foreground="White" IsChecked="{Binding ElementName=_this, Path=AddressBarReadonly, Mode=TwoWay}"></ToggleButton>
|
||||
<TextBox HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch"
|
||||
FontSize="22" Background="Transparent" Foreground="White"
|
||||
Text="{Binding ElementName=_this, Path=LeftBrowserUrl, Mode=TwoWay}"
|
||||
TextChanged="LeftBrowserUrl_TextChanged"></TextBox>
|
||||
<TextBox HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch"
|
||||
FontSize="22" Background="Transparent" Foreground="White"
|
||||
Text="{Binding ElementName=_this, Path=RightBrowserUrl, Mode=TwoWay}"
|
||||
TextChanged="RightBrowserUrl_TextChanged"></TextBox>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
||||
@@ -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,65 @@ namespace Daybreak.Views
|
||||
/// </summary>
|
||||
public partial class SettingsView : UserControl
|
||||
{
|
||||
public static readonly DependencyProperty TexmodPathProperty =
|
||||
DependencyPropertyExtensions.Register<SettingsView, string>(nameof(TexmodPath));
|
||||
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 BrowsersEnabledProperty =
|
||||
DependencyPropertyExtensions.Register<SettingsView, bool>(nameof(BrowsersEnabled));
|
||||
public static readonly DependencyProperty LeftBrowserUrlProperty =
|
||||
DependencyPropertyExtensions.Register<SettingsView, string>(nameof(LeftBrowserUrl));
|
||||
public static readonly DependencyProperty RightBrowserUrlProperty =
|
||||
DependencyPropertyExtensions.Register<SettingsView, string>(nameof(RightBrowserUrl));
|
||||
public static readonly DependencyProperty ToolboxAutoLaunchProperty =
|
||||
DependencyPropertyExtensions.Register<SettingsView, bool>(nameof(ToolboxAutoLaunch));
|
||||
|
||||
private readonly IConfigurationManager configurationManager;
|
||||
private readonly ICredentialManager credentialManager;
|
||||
private readonly IViewManager viewManager;
|
||||
|
||||
public string TexmodPath
|
||||
{
|
||||
get => this.GetTypedValue<string>(TexmodPathProperty);
|
||||
set => this.SetValue(TexmodPathProperty, value);
|
||||
}
|
||||
public bool ToolboxAutoLaunch
|
||||
{
|
||||
get => this.GetTypedValue<bool>(ToolboxAutoLaunchProperty);
|
||||
set => this.SetValue(ToolboxAutoLaunchProperty, value);
|
||||
}
|
||||
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 bool BrowsersEnabled
|
||||
{
|
||||
get => this.GetTypedValue<bool>(BrowsersEnabledProperty);
|
||||
set => this.SetValue(BrowsersEnabledProperty, 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,37 +81,30 @@ 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.AddressBarReadonly = config.AddressBarReadonly;
|
||||
this.ToolboxPath = config.ToolboxPath;
|
||||
this.LeftBrowserUrl = config.LeftBrowserDefault;
|
||||
this.RightBrowserUrl = config.RightBrowserDefault;
|
||||
this.ToolboxAutoLaunch = config.ToolboxAutoLaunch;
|
||||
this.TexmodPath = config.TexmodPath;
|
||||
this.BrowsersEnabled = config.BrowsersEnabled;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
currentConfig.ToolboxPath = this.ToolboxPath;
|
||||
currentConfig.AddressBarReadonly = this.AddressBarReadonly;
|
||||
currentConfig.LeftBrowserDefault = this.LeftBrowserUrl;
|
||||
currentConfig.RightBrowserDefault = this.RightBrowserUrl;
|
||||
currentConfig.ToolboxAutoLaunch = this.ToolboxAutoLaunch;
|
||||
currentConfig.TexmodPath = this.TexmodPath;
|
||||
currentConfig.BrowsersEnabled = this.BrowsersEnabled;
|
||||
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()
|
||||
{
|
||||
@@ -73,11 +115,11 @@ 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 TexmodFilePickerGlyph_Clicked(object sender, EventArgs e)
|
||||
{
|
||||
var filePicker = new OpenFileDialog()
|
||||
{
|
||||
@@ -88,13 +130,23 @@ namespace Daybreak.Views
|
||||
};
|
||||
if (filePicker.ShowDialog() is true)
|
||||
{
|
||||
this.ToolboxPathTextbox.Text = filePicker.FileName;
|
||||
this.TexmodPath = filePicker.FileName;
|
||||
}
|
||||
}
|
||||
|
||||
private void BackButton_Clicked(object sender, System.EventArgs e)
|
||||
private void BackButton_Clicked(object sender, EventArgs e)
|
||||
{
|
||||
this.viewManager.ShowView<MainView>();
|
||||
this.viewManager.ShowView<SettingsCategoryView>();
|
||||
}
|
||||
|
||||
private void LeftBrowserUrl_TextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
this.LeftBrowserUrl = sender.As<TextBox>().Text;
|
||||
}
|
||||
|
||||
private void RightBrowserUrl_TextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
this.RightBrowserUrl = sender.As<TextBox>().Text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
@@ -1,15 +1,19 @@
|
||||
# Daybreak
|
||||
Custom client for Guildwars.
|
||||
Requires standalone version https://developer.microsoft.com/microsoft-edge/webview2.
|
||||
Requires webview2 runtime https://go.microsoft.com/fwlink/p/?LinkId=2124703.
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
## Features
|
||||
# Features
|
||||
Automatically detect if guildwars is running or not. Includes the ability to launch guildwars from the client.
|
||||
|
||||
Manages username and password combination.
|
||||
Multibox support.
|
||||
|
||||
Manages multiple username and password combinations.
|
||||
|
||||
Manages multiple executables.
|
||||
|
||||
Ability to set a character name which gets autoloaded during launch.
|
||||
|
||||
@@ -18,3 +22,24 @@ Embedded browser set on useful pages or links.
|
||||
Ability to set default page for each of the two browser windows.
|
||||
|
||||
Rotates screenshots from "Screenshots" folder. If no screenshots are present in the folder, downloads and rotates images from http://bloogum.net/guildwars (link to page is visible when showing images from the website).
|
||||
|
||||
# Examples/Usage
|
||||
To modify any settings, press the settings button on the titlebar
|
||||

|
||||
|
||||
To adjust functionality, choose one of the settings categories
|
||||

|
||||
|
||||
When in the main view, the browsers open the default/prefferred page. To change the prefferred page, navigate to it using one of the browsers and press the star button. The current loaded page will become the default for the selected browser. Preffered page can also be selected from settings.
|
||||

|
||||
|
||||
To display other images than the ones retrieved from "http://bloogum.net/guildwars", place images in the Screenshots folder, next to the Daybreak.exe executable. If the folder doesn't exist yet, either create it or run the launcher once so that it gets created automatically.
|
||||
|
||||
To adjust accounts, go into account settings. Clicking on the star next to an account sets it as the current account.
|
||||

|
||||
|
||||
To adjust executables, go into Guildwars settings. Clicking on the star next to the executable path sets it as the current executable.
|
||||

|
||||
|
||||
To enable multiboxing (multi-launch), go into Experimental settings. Then, switch between executables/accounts and launch them.
|
||||

|
||||
|
||||
Reference in New Issue
Block a user