mirror of
https://github.com/gwdevhub/Daybreak.git
synced 2026-09-16 13:29:30 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d4d09e7267 | ||
|
|
dd7bf02a97 | ||
|
|
6d0eeb478f | ||
|
|
d4e9de48b1 | ||
|
|
6bd9877925 | ||
|
|
d38df6596f | ||
|
|
b4e31e859c | ||
|
|
1acd07c1be | ||
|
|
b9b25bb098 | ||
|
|
5ea2981dc7 | ||
|
|
4fb96ca3a4 | ||
|
|
6de52f5585 |
@@ -0,0 +1,88 @@
|
||||
# Copyright (c) Microsoft Corporation.
|
||||
# Licensed under the MIT license.
|
||||
|
||||
# This continuous integration pipeline is triggered anytime a user pushes code to the repo.
|
||||
# This pipeline builds the Wpf project, runs unit tests, then saves the MSIX build artifact.
|
||||
name: Daybreak CD Pipeline
|
||||
|
||||
# Trigger on every master branch push and pull request
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
|
||||
build:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
targetplatform: [x64]
|
||||
|
||||
runs-on: windows-latest
|
||||
|
||||
env:
|
||||
Configuration: Release
|
||||
Solution_Path: Daybreak.sln
|
||||
Test_Project_Path: Daybreak.Tests\Daybreak.Tests.csproj
|
||||
Wpf_Project_Path: Daybreak\Daybreal.csproj
|
||||
Actions_Allow_Unsecure_Commands: true # Allows AddPAth and SetEnv commands
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0 # avoid shallow clone so nbgv can do its work.
|
||||
|
||||
# Install the .NET Core workload
|
||||
- name: Install .NET Core
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: '5.0.202'
|
||||
|
||||
# Add MsBuild to the PATH: https://github.com/microsoft/setup-msbuild
|
||||
- name: Setup MSBuild.exe
|
||||
uses: microsoft/setup-msbuild@v1.0.1
|
||||
|
||||
# Restore the application
|
||||
- name: Restore the Wpf application to populate the obj folder
|
||||
run: msbuild $env:Solution_Path /t:Restore /p:Configuration=$env:Configuration /p:RuntimeIdentifier=$env:RuntimeIdentifier
|
||||
env:
|
||||
RuntimeIdentifier: win-${{ matrix.targetplatform }}
|
||||
|
||||
# Build Daybreak project
|
||||
- name: Build Daybreak project
|
||||
run: dotnet build Daybreak -c $env:Configuration
|
||||
|
||||
# Set release version environment variable
|
||||
- name: Set version variable
|
||||
run: |
|
||||
$version = .\Scripts\GetBuildVersion.ps1
|
||||
echo "::set-env name=Version::$version"
|
||||
|
||||
# Publish release
|
||||
- name: Publish release
|
||||
run: dotnet publish .\Daybreak\Daybreak.csproj -c $env:Configuration -r $env:RuntimeIdentifier -p:PublishReadyToRun=true -p:PublishSingleFile=true --self-contained true -o .\Publish
|
||||
env:
|
||||
RuntimeIdentifier: win-${{ matrix.targetplatform }}
|
||||
|
||||
# Create release payload
|
||||
- name: Create release payload
|
||||
run: |
|
||||
Write-Host $env
|
||||
.\Scripts\BuildRelease.ps1 -version $env:Version
|
||||
shell: pwsh
|
||||
|
||||
# Post new release to github
|
||||
- name: Post release
|
||||
uses: Xotl/cool-github-releases@v1.1.2
|
||||
with:
|
||||
mode: update
|
||||
tag_name: v${{ env.Version }}
|
||||
release_name: Daybreak v${{ env.Version }}
|
||||
assets: .\Publish\daybreakv${{ env.Version }}.zip
|
||||
github_token: ${{ env.GITHUB_TOKEN }}
|
||||
replace_assets: true
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
# Copyright (c) Microsoft Corporation.
|
||||
# Licensed under the MIT license.
|
||||
|
||||
# This continuous integration pipeline is triggered anytime a user pushes code to the repo.
|
||||
# This pipeline builds the Wpf project, runs unit tests, then saves the MSIX build artifact.
|
||||
name: Daybreak CI Pipeline
|
||||
|
||||
# Trigger on every master branch push and pull request
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
|
||||
build:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
targetplatform: [x64]
|
||||
|
||||
runs-on: windows-latest
|
||||
|
||||
env:
|
||||
Solution_Path: Daybreak.sln
|
||||
Test_Project_Path: Daybreak.Tests\Daybreak.Tests.csproj
|
||||
Wpf_Project_Path: Daybreak\Daybreal.csproj
|
||||
Actions_Allow_Unsecure_Commands: true # Allows AddPAth and SetEnv commands
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0 # avoid shallow clone so nbgv can do its work.
|
||||
|
||||
# Install the .NET Core workload
|
||||
- name: Install .NET Core
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: '5.0.202'
|
||||
|
||||
# Add MsBuild to the PATH: https://github.com/microsoft/setup-msbuild
|
||||
- name: Setup MSBuild.exe
|
||||
uses: microsoft/setup-msbuild@v1.0.1
|
||||
|
||||
# Test
|
||||
- name: Execute Unit Tests
|
||||
run: dotnet test $env:Test_Project_Path
|
||||
|
||||
# Restore the application
|
||||
- name: Restore the Wpf application to populate the obj folder
|
||||
run: msbuild $env:Solution_Path /t:Restore /p:Configuration=$env:Configuration /p:RuntimeIdentifier=$env:RuntimeIdentifier
|
||||
env:
|
||||
Configuration: Debug
|
||||
RuntimeIdentifier: win-${{ matrix.targetplatform }}
|
||||
@@ -9,6 +9,7 @@
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
*.version
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Daybreak.Models;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Daybreak.Configuration
|
||||
@@ -30,5 +31,9 @@ namespace Daybreak.Configuration
|
||||
public bool AddressBarReadonly { get; set; } = true;
|
||||
[JsonProperty("ExperimentalFeatures")]
|
||||
public ExperimentalFeatures ExperimentalFeatures { get; set; } = new();
|
||||
[JsonProperty("ShortcutLocation")]
|
||||
public string ShortcutLocation { get; set; } = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
|
||||
[JsonProperty("PlaceShortcut")]
|
||||
public bool PlaceShortcut { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using Newtonsoft.Json;
|
||||
using Daybreak.Models;
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Daybreak.Configuration
|
||||
{
|
||||
@@ -12,5 +14,9 @@ namespace Daybreak.Configuration
|
||||
public bool DynamicBuildLoading { get; set; } = true;
|
||||
[JsonProperty("LaunchGuildwarsAsCurrentUser")]
|
||||
public bool LaunchGuildwarsAsCurrentUser { get; set; } = true;
|
||||
[JsonProperty("CanInterceptKeys")]
|
||||
public bool CanInterceptKeys { get; set; }
|
||||
[JsonProperty("Macros")]
|
||||
public List<KeyMacro> Macros { get; set; } = new();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ using Daybreak.Services.Privilege;
|
||||
using Daybreak.Services.Runtime;
|
||||
using Daybreak.Services.Screens;
|
||||
using Daybreak.Services.Screenshots;
|
||||
using Daybreak.Services.Shortcuts;
|
||||
using Daybreak.Services.Updater;
|
||||
using Daybreak.Services.ViewManagement;
|
||||
using Daybreak.Views;
|
||||
@@ -41,6 +42,7 @@ namespace Daybreak.Configuration
|
||||
serviceProducer.RegisterSingleton<IIconRetriever, IconRetriever>();
|
||||
serviceProducer.RegisterSingleton<IPrivilegeManager, PrivilegeManager>();
|
||||
serviceProducer.RegisterSingleton<IScreenManager, ScreenManager>();
|
||||
serviceProducer.RegisterSingleton<IShortcutManager, ShortcutManager>();
|
||||
}
|
||||
public static void RegisterLifetimeServices(IApplicationLifetimeProducer applicationLifetimeProducer)
|
||||
{
|
||||
@@ -49,6 +51,7 @@ namespace Daybreak.Configuration
|
||||
applicationLifetimeProducer.RegisterService<ILoggingDatabase>();
|
||||
applicationLifetimeProducer.RegisterService<IScreenshotProvider>();
|
||||
applicationLifetimeProducer.RegisterService<IApplicationUpdater>();
|
||||
applicationLifetimeProducer.RegisterService<IShortcutManager>();
|
||||
}
|
||||
public static void RegisterViews(IViewProducer viewProducer)
|
||||
{
|
||||
|
||||
@@ -19,20 +19,12 @@ namespace Daybreak.Controls
|
||||
/// <summary>
|
||||
/// Interaction logic for ChromiumBrowserWrapper.xaml
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0044:Add readonly modifier", Justification = "Fields used by source generator for DependencyProperty")]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "Used by source generators")]
|
||||
public partial class 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 readonly static DependencyProperty ControlsEnabledProperty = DependencyPropertyExtensions.Register<ChromiumBrowserWrapper, bool>(nameof(ControlsEnabled), new PropertyMetadata(true));
|
||||
public readonly static DependencyProperty CanNavigateProperty = DependencyPropertyExtensions.Register<ChromiumBrowserWrapper, bool>(nameof(CanNavigate), new PropertyMetadata(true));
|
||||
public readonly static DependencyProperty CanDownloadBuildProperty = DependencyPropertyExtensions.Register<ChromiumBrowserWrapper, bool>(nameof(CanDownloadBuild), new PropertyMetadata(false));
|
||||
|
||||
public event EventHandler<string> FavoriteUriChanged;
|
||||
public event EventHandler MaximizeClicked;
|
||||
public event EventHandler<Build> BuildDecoded;
|
||||
@@ -42,51 +34,24 @@ namespace Daybreak.Controls
|
||||
private readonly IBuildTemplateManager buildTemplateManager;
|
||||
private CoreWebView2Environment coreWebView2Environment;
|
||||
|
||||
public bool CanDownloadBuild
|
||||
{
|
||||
get => this.GetTypedValue<bool>(CanDownloadBuildProperty);
|
||||
set => this.SetTypedValue<bool>(CanDownloadBuildProperty, value);
|
||||
}
|
||||
public bool CanNavigate
|
||||
{
|
||||
get => this.GetTypedValue<bool>(CanNavigateProperty);
|
||||
set => this.SetTypedValue<bool>(CanNavigateProperty, value);
|
||||
}
|
||||
public string Address
|
||||
{
|
||||
get => this.GetTypedValue<string>(AddressProperty);
|
||||
set => this.SetTypedValue(AddressProperty, value);
|
||||
}
|
||||
public string FavoriteAddress
|
||||
{
|
||||
get => this.GetTypedValue<string>(FavoriteAddressProperty);
|
||||
set => this.SetTypedValue(FavoriteAddressProperty, value);
|
||||
}
|
||||
public bool Navigating
|
||||
{
|
||||
get => this.GetTypedValue<bool>(NavigatingProperty);
|
||||
private set => this.SetTypedValue<bool>(NavigatingProperty, value);
|
||||
}
|
||||
public bool AddressBarReadonly
|
||||
{
|
||||
get => this.GetTypedValue<bool>(AddressBarReadonlyProperty);
|
||||
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 bool ControlsEnabled
|
||||
{
|
||||
get => this.GetTypedValue<bool>(ControlsEnabledProperty);
|
||||
set => this.SetTypedValue<bool>(ControlsEnabledProperty, value);
|
||||
}
|
||||
[GenerateDependencyProperty(InitialValue = true)]
|
||||
private bool canDownloadBuild;
|
||||
[GenerateDependencyProperty(InitialValue = true)]
|
||||
private bool canNavigate;
|
||||
[GenerateDependencyProperty(InitialValue = true)]
|
||||
private bool controlsEnabled;
|
||||
[GenerateDependencyProperty(InitialValue = true)]
|
||||
private bool browserSupported;
|
||||
[GenerateDependencyProperty]
|
||||
private bool addressBarReadonly;
|
||||
[GenerateDependencyProperty]
|
||||
private bool browserEnabled;
|
||||
[GenerateDependencyProperty]
|
||||
private bool navigating;
|
||||
[GenerateDependencyProperty]
|
||||
private string favoriteAddress;
|
||||
[GenerateDependencyProperty]
|
||||
private string address;
|
||||
|
||||
public ChromiumBrowserWrapper()
|
||||
{
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Daybreak.Utils;
|
||||
using System;
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
@@ -39,7 +38,7 @@ namespace Daybreak.Controls
|
||||
}
|
||||
|
||||
nextVisible.Source = imageSource;
|
||||
this.Transition(currentVisible, nextVisible);
|
||||
Transition(currentVisible, nextVisible);
|
||||
}
|
||||
|
||||
private Image CurrentVisible()
|
||||
@@ -64,7 +63,7 @@ namespace Daybreak.Controls
|
||||
return this.Image1;
|
||||
}
|
||||
}
|
||||
private void Transition(Image from, Image to)
|
||||
private static void Transition(Image from, Image to)
|
||||
{
|
||||
to.Visibility = Visibility.Visible;
|
||||
to.Opacity = 0;
|
||||
|
||||
@@ -10,37 +10,21 @@ namespace Daybreak.Controls
|
||||
/// <summary>
|
||||
/// Interaction logic for AccountTemplate.xaml
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0044:Add readonly modifier", Justification = "Fields used by source generator for DependencyProperty")]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "Used by source generators")]
|
||||
public partial class 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);
|
||||
}
|
||||
|
||||
[GenerateDependencyProperty]
|
||||
private string username;
|
||||
[GenerateDependencyProperty]
|
||||
private string password;
|
||||
[GenerateDependencyProperty]
|
||||
private string characterName;
|
||||
[GenerateDependencyProperty]
|
||||
private bool isDefault;
|
||||
|
||||
public AccountTemplate()
|
||||
{
|
||||
|
||||
@@ -10,26 +10,16 @@ namespace Daybreak.Controls
|
||||
/// <summary>
|
||||
/// Interaction logic for AttributeTemplate.xaml
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0044:Add readonly modifier", Justification = "Fields used by source generator for DependencyProperty")]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "Used by source generators")]
|
||||
public partial class AttributeTemplate : UserControl
|
||||
{
|
||||
public readonly static DependencyProperty CanAddProperty =
|
||||
DependencyPropertyExtensions.Register<AttributeTemplate, bool>(nameof(CanAdd), new PropertyMetadata(false));
|
||||
public readonly static DependencyProperty CanSubtractProperty =
|
||||
DependencyPropertyExtensions.Register<AttributeTemplate, bool>(nameof(CanSubtract), new PropertyMetadata(false));
|
||||
|
||||
public event EventHandler<AttributeEntry> HelpClicked;
|
||||
|
||||
public bool CanAdd
|
||||
{
|
||||
get => this.GetTypedValue<bool>(CanAddProperty);
|
||||
private set => this.SetValue(CanAddProperty, value);
|
||||
}
|
||||
|
||||
public bool CanSubtract
|
||||
{
|
||||
get => this.GetTypedValue<bool>(CanSubtractProperty);
|
||||
private set => this.SetValue(CanSubtractProperty, value);
|
||||
}
|
||||
|
||||
[GenerateDependencyProperty(InitialValue = false)]
|
||||
private bool canAdd;
|
||||
[GenerateDependencyProperty(InitialValue = false)]
|
||||
private bool canSubtract;
|
||||
|
||||
public AttributeTemplate()
|
||||
{
|
||||
|
||||
@@ -1,103 +1,48 @@
|
||||
using Daybreak.Launch;
|
||||
using Daybreak.Models.Builds;
|
||||
using Daybreak.Services.IconRetrieve;
|
||||
using System.Collections;
|
||||
using Daybreak.Models.Builds;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Extensions;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Extensions;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace Daybreak.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for BuildTemplate.xaml
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0044:Add readonly modifier", Justification = "Fields used by source generator for DependencyProperty")]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "Used by source generators")]
|
||||
public partial class BuildTemplate : UserControl
|
||||
{
|
||||
private const string InfoNamePlaceholder = "[NAME]";
|
||||
private const string BaseAddress = $"https://wiki.guildwars.com/wiki/{InfoNamePlaceholder}";
|
||||
|
||||
public readonly static DependencyProperty PrimaryProfessionProperty =
|
||||
DependencyPropertyExtensions.Register<BuildTemplate, Profession>(nameof(PrimaryProfession), new PropertyMetadata(Profession.None));
|
||||
public readonly static DependencyProperty SecondaryProfessionProperty =
|
||||
DependencyPropertyExtensions.Register<BuildTemplate, Profession>(nameof(SecondaryProfession), new PropertyMetadata(Profession.None));
|
||||
public readonly static DependencyProperty Skill0Property =
|
||||
DependencyPropertyExtensions.Register<BuildTemplate, Skill>(nameof(Skill0), new PropertyMetadata(Skill.NoSkill));
|
||||
public readonly static DependencyProperty Skill1Property =
|
||||
DependencyPropertyExtensions.Register<BuildTemplate, Skill>(nameof(Skill1), new PropertyMetadata(Skill.NoSkill));
|
||||
public readonly static DependencyProperty Skill2Property =
|
||||
DependencyPropertyExtensions.Register<BuildTemplate, Skill>(nameof(Skill2), new PropertyMetadata(Skill.NoSkill));
|
||||
public readonly static DependencyProperty Skill3Property =
|
||||
DependencyPropertyExtensions.Register<BuildTemplate, Skill>(nameof(Skill3), new PropertyMetadata(Skill.NoSkill));
|
||||
public readonly static DependencyProperty Skill4Property =
|
||||
DependencyPropertyExtensions.Register<BuildTemplate, Skill>(nameof(Skill4), new PropertyMetadata(Skill.NoSkill));
|
||||
public readonly static DependencyProperty Skill5Property =
|
||||
DependencyPropertyExtensions.Register<BuildTemplate, Skill>(nameof(Skill5), new PropertyMetadata(Skill.NoSkill));
|
||||
public readonly static DependencyProperty Skill6Property =
|
||||
DependencyPropertyExtensions.Register<BuildTemplate, Skill>(nameof(Skill6), new PropertyMetadata(Skill.NoSkill));
|
||||
public readonly static DependencyProperty Skill7Property =
|
||||
DependencyPropertyExtensions.Register<BuildTemplate, Skill>(nameof(Skill7), new PropertyMetadata(Skill.NoSkill));
|
||||
|
||||
private bool loadedProperties = false;
|
||||
private BuildEntry loadedBuild;
|
||||
private SkillTemplate selectingSkillTemplate;
|
||||
|
||||
public Profession PrimaryProfession
|
||||
{
|
||||
get => this.GetTypedValue<Profession>(PrimaryProfessionProperty);
|
||||
set => this.SetValue(PrimaryProfessionProperty, value);
|
||||
}
|
||||
public Profession SecondaryProfession
|
||||
{
|
||||
get => this.GetTypedValue<Profession>(SecondaryProfessionProperty);
|
||||
set => this.SetValue(SecondaryProfessionProperty, value);
|
||||
}
|
||||
public Skill Skill0
|
||||
{
|
||||
get => this.GetTypedValue<Skill>(Skill0Property);
|
||||
set => this.SetValue(Skill0Property, value);
|
||||
}
|
||||
public Skill Skill1
|
||||
{
|
||||
get => this.GetTypedValue<Skill>(Skill1Property);
|
||||
set => this.SetValue(Skill1Property, value);
|
||||
}
|
||||
public Skill Skill2
|
||||
{
|
||||
get => this.GetTypedValue<Skill>(Skill2Property);
|
||||
set => this.SetValue(Skill2Property, value);
|
||||
}
|
||||
public Skill Skill3
|
||||
{
|
||||
get => this.GetTypedValue<Skill>(Skill3Property);
|
||||
set => this.SetValue(Skill3Property, value);
|
||||
}
|
||||
public Skill Skill4
|
||||
{
|
||||
get => this.GetTypedValue<Skill>(Skill4Property);
|
||||
set => this.SetValue(Skill4Property, value);
|
||||
}
|
||||
public Skill Skill5
|
||||
{
|
||||
get => this.GetTypedValue<Skill>(Skill5Property);
|
||||
set => this.SetValue(Skill5Property, value);
|
||||
}
|
||||
public Skill Skill6
|
||||
{
|
||||
get => this.GetTypedValue<Skill>(Skill6Property);
|
||||
set => this.SetValue(Skill6Property, value);
|
||||
}
|
||||
public Skill Skill7
|
||||
{
|
||||
get => this.GetTypedValue<Skill>(Skill7Property);
|
||||
set => this.SetValue(Skill7Property, value);
|
||||
}
|
||||
[GenerateDependencyProperty]
|
||||
private Profession primaryProfession;
|
||||
[GenerateDependencyProperty]
|
||||
private Profession secondaryProfession;
|
||||
[GenerateDependencyProperty]
|
||||
private Skill skill0;
|
||||
[GenerateDependencyProperty]
|
||||
private Skill skill1;
|
||||
[GenerateDependencyProperty]
|
||||
private Skill skill2;
|
||||
[GenerateDependencyProperty]
|
||||
private Skill skill3;
|
||||
[GenerateDependencyProperty]
|
||||
private Skill skill4;
|
||||
[GenerateDependencyProperty]
|
||||
private Skill skill5;
|
||||
[GenerateDependencyProperty]
|
||||
private Skill skill6;
|
||||
[GenerateDependencyProperty]
|
||||
private Skill skill7;
|
||||
public ObservableCollection<Skill> AvailableSkills { get; } = new ObservableCollection<Skill>();
|
||||
public ObservableCollection<AttributeEntry> Attributes { get; } = new ObservableCollection<AttributeEntry>();
|
||||
public ObservableCollection<Profession> Professions { get; } = new ObservableCollection<Profession>(Profession.Professions);
|
||||
@@ -105,12 +50,18 @@ namespace Daybreak.Controls
|
||||
public BuildTemplate()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
this.InitializeProperties();
|
||||
this.DataContextChanged += BuildTemplate_DataContextChanged;
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
base.OnPropertyChanged(e);
|
||||
if (this.loadedProperties is false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.Property == PrimaryProfessionProperty || e.Property == SecondaryProfessionProperty)
|
||||
{
|
||||
if (e.Property == PrimaryProfessionProperty)
|
||||
@@ -126,6 +77,21 @@ namespace Daybreak.Controls
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeProperties()
|
||||
{
|
||||
this.PrimaryProfession = Profession.None;
|
||||
this.SecondaryProfession = Profession.None;
|
||||
this.Skill0 = Skill.NoSkill;
|
||||
this.Skill1 = Skill.NoSkill;
|
||||
this.Skill2 = Skill.NoSkill;
|
||||
this.Skill3 = Skill.NoSkill;
|
||||
this.Skill4 = Skill.NoSkill;
|
||||
this.Skill5 = Skill.NoSkill;
|
||||
this.Skill6 = Skill.NoSkill;
|
||||
this.Skill7 = Skill.NoSkill;
|
||||
this.loadedProperties = true;
|
||||
}
|
||||
|
||||
private void BuildTemplate_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if(e.NewValue is BuildEntry)
|
||||
|
||||
@@ -11,24 +11,17 @@ namespace Daybreak.Controls
|
||||
/// <summary>
|
||||
/// Interaction logic for GuildwarsPathTemplate.xaml
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0044:Add readonly modifier", Justification = "Fields used by source generator for DependencyProperty")]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "Used by source generators")]
|
||||
public partial class 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);
|
||||
}
|
||||
[GenerateDependencyProperty]
|
||||
private string path;
|
||||
[GenerateDependencyProperty]
|
||||
private bool isDefault;
|
||||
|
||||
public GuildwarsPathTemplate()
|
||||
{
|
||||
|
||||
@@ -11,26 +11,16 @@ namespace Daybreak.Controls.Templates
|
||||
/// <summary>
|
||||
/// Interaction logic for ScreenTemplate.xaml
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0044:Add readonly modifier", Justification = "Fields used by source generator for DependencyProperty")]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "Used by source generators")]
|
||||
public partial class ScreenTemplate : UserControl
|
||||
{
|
||||
public static readonly DependencyProperty ScreenIdProperty =
|
||||
DependencyPropertyExtensions.Register<ScreenTemplate, string>(nameof(ScreenId));
|
||||
public static readonly DependencyProperty HighlightProperty =
|
||||
DependencyPropertyExtensions.Register<ScreenTemplate, Brush>(nameof(Highlight));
|
||||
|
||||
public event EventHandler<Screen> Clicked;
|
||||
|
||||
public string ScreenId
|
||||
{
|
||||
get => this.GetTypedValue<string>(ScreenIdProperty);
|
||||
set => this.SetValue(ScreenIdProperty, value);
|
||||
}
|
||||
|
||||
public Brush Highlight
|
||||
{
|
||||
get => this.GetTypedValue<Brush>(HighlightProperty);
|
||||
set => this.SetValue(HighlightProperty, value);
|
||||
}
|
||||
[GenerateDependencyProperty]
|
||||
private string screenId;
|
||||
[GenerateDependencyProperty]
|
||||
private Brush highlight;
|
||||
|
||||
public ScreenTemplate()
|
||||
{
|
||||
|
||||
@@ -16,28 +16,19 @@ namespace Daybreak.Controls
|
||||
/// <summary>
|
||||
/// Interaction logic for SkillTemplate.xaml
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0044:Add readonly modifier", Justification = "Fields used by source generator for DependencyProperty")]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "Used by source generators")]
|
||||
public partial class SkillTemplate : UserControl
|
||||
{
|
||||
public readonly static DependencyProperty ImageSourceProperty =
|
||||
DependencyPropertyExtensions.Register<SkillTemplate, ImageSource>(nameof(ImageSource));
|
||||
public readonly static DependencyProperty BorderOpacityProperty =
|
||||
DependencyPropertyExtensions.Register<SkillTemplate, double>(nameof(BorderOpacity), new PropertyMetadata(0d));
|
||||
|
||||
public event EventHandler<RoutedEventArgs> Clicked;
|
||||
public event EventHandler RemoveClicked;
|
||||
|
||||
private readonly IIconRetriever iconRetriever;
|
||||
|
||||
public ImageSource ImageSource
|
||||
{
|
||||
get => this.GetTypedValue<ImageSource>(ImageSourceProperty);
|
||||
set => this.SetValue(ImageSourceProperty, value);
|
||||
}
|
||||
public double BorderOpacity
|
||||
{
|
||||
get => this.GetTypedValue<double>(BorderOpacityProperty);
|
||||
set => this.SetValue(BorderOpacityProperty, value);
|
||||
}
|
||||
[GenerateDependencyProperty]
|
||||
private ImageSource imageSource;
|
||||
[GenerateDependencyProperty]
|
||||
private double borderOpacity;
|
||||
|
||||
public SkillTemplate()
|
||||
{
|
||||
|
||||
@@ -9,18 +9,21 @@
|
||||
<CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<ApplicationIcon>Daybreak.ico</ApplicationIcon>
|
||||
<Version>0.8.3</Version>
|
||||
<IncludePackageReferencesDuringMarkupCompilation>true</IncludePackageReferencesDuringMarkupCompilation>
|
||||
<Version>0.8.7</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.32" />
|
||||
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.818.41" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="Slim" Version="1.2.1" />
|
||||
<PackageReference Include="securifybv.ShellLink" Version="0.1.0" />
|
||||
<PackageReference Include="Slim" Version="1.2.2" />
|
||||
<PackageReference Include="System.Windows.Interactivity.WPF" Version="2.0.20525" />
|
||||
<PackageReference Include="SystemExtensions.NetStandard" Version="1.1.4" />
|
||||
<PackageReference Include="WCL" Version="1.0.2" />
|
||||
<PackageReference Include="WpfExtended" Version="0.2.0" />
|
||||
<PackageReference Include="WpfExtended" Version="0.2.1" />
|
||||
<PackageReference Include="WpfExtended.SourceGeneration" Version="0.1.1" />
|
||||
<PackageReference Include="WpfScreenHelper" Version="1.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -62,4 +65,8 @@
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
<Exec Command="echo.>$(Version).version" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -22,12 +22,10 @@ namespace Daybreak.Launch
|
||||
/// <summary>
|
||||
/// Interaction logic for MainWindow.xaml
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0044:Add readonly modifier", Justification = "Fields used by source generator for DependencyProperty")]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "Used by source generators")]
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
public static readonly DependencyProperty CreditTextProperty = DependencyPropertyExtensions.Register<MainWindow, string>(nameof(CreditText));
|
||||
public static readonly DependencyProperty CurrentVersionTextProperty = DependencyPropertyExtensions.Register<MainWindow, string>(nameof(CurrentVersionText));
|
||||
public static readonly DependencyProperty IsRunningAsAdminProperty = DependencyPropertyExtensions.Register<MainWindow, bool>(nameof(IsRunningAsAdmin));
|
||||
|
||||
private readonly IViewManager viewManager;
|
||||
private readonly IScreenshotProvider screenshotProvider;
|
||||
private readonly IBloogumClient bloogumClient;
|
||||
@@ -35,23 +33,12 @@ namespace Daybreak.Launch
|
||||
private readonly IPrivilegeManager privilegeManager;
|
||||
private readonly CancellationTokenSource cancellationToken = new();
|
||||
|
||||
public string CreditText
|
||||
{
|
||||
get => this.GetTypedValue<string>(CreditTextProperty);
|
||||
set => this.SetValue(CreditTextProperty, value);
|
||||
}
|
||||
|
||||
public string CurrentVersionText
|
||||
{
|
||||
get => this.GetTypedValue<string>(CurrentVersionTextProperty);
|
||||
set => this.SetValue(CurrentVersionTextProperty, value);
|
||||
}
|
||||
|
||||
public bool IsRunningAsAdmin
|
||||
{
|
||||
get => this.GetTypedValue<bool>(IsRunningAsAdminProperty);
|
||||
set => this.SetValue(IsRunningAsAdminProperty, value);
|
||||
}
|
||||
[GenerateDependencyProperty]
|
||||
private string creditText;
|
||||
[GenerateDependencyProperty]
|
||||
private string currentVersionText;
|
||||
[GenerateDependencyProperty]
|
||||
private bool isRunningAsAdmin;
|
||||
|
||||
public MainWindow(
|
||||
IViewManager viewManager,
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Daybreak.Models
|
||||
{
|
||||
public sealed class KeyMacro
|
||||
{
|
||||
public List<Keys> Keys { get; set; }
|
||||
public Keys TargetKey { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
namespace Daybreak.Models
|
||||
{
|
||||
public sealed class KeyboardHookEventArgs
|
||||
{
|
||||
public bool Handled { get; set; }
|
||||
public KeyboardState KeyboardState { get; }
|
||||
public KeyboardInput KeyboardInput { get; }
|
||||
|
||||
public KeyboardHookEventArgs(
|
||||
KeyboardState keyboardState,
|
||||
KeyboardInput keyboardInput)
|
||||
{
|
||||
this.KeyboardState = keyboardState;
|
||||
this.KeyboardInput = keyboardInput;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Daybreak.Models
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct KeyboardInput
|
||||
{
|
||||
/// <summary>
|
||||
/// A virtual-key code. The code must be a value in the range 1 to 254.
|
||||
/// </summary>
|
||||
public int VirtualCode;
|
||||
|
||||
// EDT: added a conversion from VirtualCode to Keys.
|
||||
/// <summary>
|
||||
/// The VirtualCode converted to typeof(Keys) for higher usability.
|
||||
/// </summary>
|
||||
public Keys Key { get { return (Keys)VirtualCode; } }
|
||||
|
||||
/// <summary>
|
||||
/// A hardware scan code for the key.
|
||||
/// </summary>
|
||||
public int HardwareScanCode;
|
||||
|
||||
/// <summary>
|
||||
/// The extended-key flag, event-injected Flags, context code, and transition-state flag. This member is specified as follows. An application can use the following values to test the keystroke Flags. Testing LLKHF_INJECTED (bit 4) will tell you whether the event was injected. If it was, then testing LLKHF_LOWER_IL_INJECTED (bit 1) will tell you whether or not the event was injected from a process running at lower integrity level.
|
||||
/// </summary>
|
||||
public int Flags;
|
||||
|
||||
/// <summary>
|
||||
/// The time stamp stamp for this message, equivalent to what GetMessageTime would return for this message.
|
||||
/// </summary>
|
||||
public int TimeStamp;
|
||||
|
||||
/// <summary>
|
||||
/// Additional information associated with the message.
|
||||
/// </summary>
|
||||
public IntPtr AdditionalInformation;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace Daybreak.Models
|
||||
{
|
||||
public enum KeyboardState
|
||||
{
|
||||
KeyDown = 0x0100,
|
||||
KeyUp = 0x0101,
|
||||
SysKeyDown = 0x0104,
|
||||
SysKeyUp = 0x0105
|
||||
}
|
||||
}
|
||||
@@ -179,10 +179,10 @@ namespace Daybreak.Services.ApplicationLauncher
|
||||
StartInfo = new ProcessStartInfo
|
||||
{
|
||||
Arguments = string.Join(" ", args),
|
||||
UserName = identity
|
||||
FileName = executable.Path
|
||||
}
|
||||
};
|
||||
if (Process.Start(executable.Path, args) is null)
|
||||
if (process.Start() is false)
|
||||
{
|
||||
throw new InvalidOperationException($"Unable to launch {executable}");
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Daybreak.Configuration;
|
||||
using Daybreak.Exceptions;
|
||||
using Daybreak.Services.Logging;
|
||||
using Daybreak.Utils;
|
||||
using System;
|
||||
@@ -15,6 +14,8 @@ namespace Daybreak.Services.Configuration
|
||||
private ApplicationConfiguration applicationConfiguration;
|
||||
private readonly ILogger logger;
|
||||
|
||||
public event EventHandler ConfigurationChanged;
|
||||
|
||||
public ConfigurationManager(ILogger logger)
|
||||
{
|
||||
this.logger = logger.ThrowIfNull(nameof(logger));
|
||||
@@ -39,6 +40,7 @@ namespace Daybreak.Services.Configuration
|
||||
{
|
||||
File.WriteAllText(ConfigName, applicationConfiguration.Serialize());
|
||||
this.applicationConfiguration = applicationConfiguration;
|
||||
this.ConfigurationChanged?.Invoke(this, new EventArgs());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
using Daybreak.Configuration;
|
||||
using System;
|
||||
|
||||
namespace Daybreak.Services.Configuration
|
||||
{
|
||||
public interface IConfigurationManager
|
||||
{
|
||||
event EventHandler ConfigurationChanged;
|
||||
ApplicationConfiguration GetConfiguration();
|
||||
void SaveConfiguration(ApplicationConfiguration applicationConfiguration);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
using Daybreak.Models;
|
||||
using Daybreak.Services.ApplicationLifetime;
|
||||
using System;
|
||||
|
||||
namespace Daybreak.Services.KeyboardHook
|
||||
{
|
||||
public interface IKeyboardHookService : IApplicationLifetimeService
|
||||
{
|
||||
event EventHandler<KeyboardHookEventArgs> KeyboardPressed;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
using Daybreak.Models;
|
||||
using Daybreak.Services.Logging;
|
||||
using Daybreak.Utils;
|
||||
using Pepa.Wpf.Utilities;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Extensions;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Daybreak.Services.KeyboardHook
|
||||
{
|
||||
// Based on https://gist.github.com/Stasonix
|
||||
// https://stackoverflow.com/questions/604410/global-keyboard-capture-in-c-sharp-application
|
||||
public sealed class KeyboardHookService : IKeyboardHookService, IDisposable
|
||||
{
|
||||
private readonly ILogger logger;
|
||||
private IntPtr windowsHookHandle;
|
||||
private IntPtr user32LibraryHandle;
|
||||
private NativeMethods.HookProc hookProc;
|
||||
|
||||
public event EventHandler<KeyboardHookEventArgs> KeyboardPressed;
|
||||
|
||||
public KeyboardHookService(
|
||||
ILogger logger)
|
||||
{
|
||||
this.logger = logger.ThrowIfNull(nameof(logger));
|
||||
this.Setup();
|
||||
}
|
||||
|
||||
public void OnStartup()
|
||||
{
|
||||
}
|
||||
|
||||
public void OnClosing()
|
||||
{
|
||||
this.Dispose();
|
||||
}
|
||||
|
||||
private void Setup()
|
||||
{
|
||||
this.windowsHookHandle = IntPtr.Zero;
|
||||
this.hookProc = this.LowLevelKeyboardProc; // we must keep alive _hookProc, because GC is not aware about SetWindowsHookEx behaviour.
|
||||
|
||||
this.user32LibraryHandle = NativeMethods.LoadLibrary("User32");
|
||||
if (this.user32LibraryHandle == IntPtr.Zero)
|
||||
{
|
||||
int errorCode = Marshal.GetLastWin32Error();
|
||||
this.logger.LogError($"Failed to load library 'User32.dll'. Error {errorCode}: {new Win32Exception(Marshal.GetLastWin32Error()).Message}.");
|
||||
}
|
||||
|
||||
this.windowsHookHandle = NativeMethods.SetWindowsHookEx(NativeMethods.WH_KEYBOARD_LL, this.hookProc, this.user32LibraryHandle, 0);
|
||||
if (this.windowsHookHandle == IntPtr.Zero)
|
||||
{
|
||||
int errorCode = Marshal.GetLastWin32Error();
|
||||
this.logger.LogError($"Failed to adjust keyboard hooks for '{Process.GetCurrentProcess().ProcessName}'. Error {errorCode}: {new Win32Exception(Marshal.GetLastWin32Error()).Message}.");
|
||||
}
|
||||
}
|
||||
|
||||
private IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam)
|
||||
{
|
||||
var handled = false;
|
||||
var wparamTyped = wParam.ToInt32();
|
||||
if (Enum.IsDefined(typeof(KeyboardState), wparamTyped))
|
||||
{
|
||||
var p = Marshal.PtrToStructure(lParam, typeof(KeyboardInput)).Cast<KeyboardInput>();
|
||||
var eventArguments = new KeyboardHookEventArgs(wparamTyped.Cast<KeyboardState>(), p);
|
||||
this.KeyboardPressed?.Invoke(this, eventArguments);
|
||||
handled = eventArguments.Handled;
|
||||
}
|
||||
|
||||
return handled ? (IntPtr)1 : NativeMethods.CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam);
|
||||
}
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
// because we can unhook only in the same thread, not in garbage collector thread
|
||||
if (this.windowsHookHandle != IntPtr.Zero)
|
||||
{
|
||||
if (NativeMethods.UnhookWindowsHookEx(this.windowsHookHandle) is false)
|
||||
{
|
||||
int errorCode = Marshal.GetLastWin32Error();
|
||||
this.logger.LogCritical($"Failed to remove keyboard hooks for '{Process.GetCurrentProcess().ProcessName}'. Error {errorCode}: {new Win32Exception(Marshal.GetLastWin32Error()).Message}.");
|
||||
}
|
||||
|
||||
this.windowsHookHandle = IntPtr.Zero;
|
||||
this.hookProc -= LowLevelKeyboardProc;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.user32LibraryHandle != IntPtr.Zero)
|
||||
{
|
||||
if (NativeMethods.FreeLibrary(this.user32LibraryHandle) is false) // reduces reference to library by 1.
|
||||
{
|
||||
int errorCode = Marshal.GetLastWin32Error();
|
||||
this.logger.LogCritical($"Failed to unload library 'User32.dll'. Error {errorCode}: {new Win32Exception(Marshal.GetLastWin32Error()).Message}.");
|
||||
}
|
||||
|
||||
this.user32LibraryHandle = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
~KeyboardHookService()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using Daybreak.Services.ApplicationLifetime;
|
||||
|
||||
namespace Daybreak.Services.KeyboardMacros
|
||||
{
|
||||
public interface IMacroService : IApplicationLifetimeService
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
using Daybreak.Models;
|
||||
using Daybreak.Services.Configuration;
|
||||
using Daybreak.Services.KeyboardHook;
|
||||
using Daybreak.Services.Logging;
|
||||
using Pepa.Wpf.Utilities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Extensions;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Daybreak.Services.KeyboardMacros
|
||||
{
|
||||
public sealed class MacroService : IMacroService
|
||||
{
|
||||
private readonly CancellationTokenSource cancellationTokenSource = new();
|
||||
private readonly ILogger logger;
|
||||
private readonly IKeyboardHookService keyboardHookService;
|
||||
private readonly IConfigurationManager configurationManager;
|
||||
private readonly HashSet<Keys> KeysDown = new();
|
||||
|
||||
private IEnumerable<KeyMacro> loadedMacros;
|
||||
private bool gameActive, hookEnabled;
|
||||
private IntPtr gwWindowHwnd;
|
||||
|
||||
public MacroService(
|
||||
ILogger logger,
|
||||
IKeyboardHookService keyboardHookService,
|
||||
IConfigurationManager configurationManager)
|
||||
{
|
||||
this.logger = logger.ThrowIfNull(nameof(logger));
|
||||
this.keyboardHookService = keyboardHookService.ThrowIfNull(nameof(keyboardHookService));
|
||||
this.configurationManager = configurationManager.ThrowIfNull(nameof(configurationManager));
|
||||
|
||||
this.configurationManager.ConfigurationChanged += (s, e) => this.LoadConfiguration();
|
||||
this.LoadConfiguration();
|
||||
this.keyboardHookService.KeyboardPressed += this.KeyboardHookService_KeyboardPressed;
|
||||
this.SetupGameActiveChecker();
|
||||
}
|
||||
|
||||
private void LoadConfiguration()
|
||||
{
|
||||
this.hookEnabled = this.configurationManager.GetConfiguration().ExperimentalFeatures.CanInterceptKeys;
|
||||
this.loadedMacros = this.configurationManager.GetConfiguration().ExperimentalFeatures.Macros ?? new List<KeyMacro>();
|
||||
}
|
||||
|
||||
private void SetupGameActiveChecker()
|
||||
{
|
||||
TaskExtensions.RunPeriodicAsync(() =>
|
||||
{
|
||||
var windowHandle = NativeMethods.GetForegroundWindow();
|
||||
var windowNameLength = NativeMethods.GetWindowTextLength(windowHandle);
|
||||
var sb = new StringBuilder(windowNameLength);
|
||||
_ = NativeMethods.GetWindowText(windowHandle, sb, windowNameLength + 1);
|
||||
if (sb.ToString() != "Guild Wars")
|
||||
{
|
||||
this.gameActive = false;
|
||||
return;
|
||||
}
|
||||
|
||||
this.gwWindowHwnd = windowHandle;
|
||||
this.gameActive = true;
|
||||
},
|
||||
TimeSpan.Zero,
|
||||
TimeSpan.FromMilliseconds(33),
|
||||
cancellationTokenSource.Token);
|
||||
}
|
||||
|
||||
private void KeyboardHookService_KeyboardPressed(object sender, KeyboardHookEventArgs e)
|
||||
{
|
||||
if (this.gameActive && this.hookEnabled)
|
||||
{
|
||||
if (e.KeyboardState == KeyboardState.KeyDown)
|
||||
{
|
||||
this.KeysDown.Add(e.KeyboardInput.Key);
|
||||
}
|
||||
else if (e.KeyboardState == KeyboardState.KeyUp)
|
||||
{
|
||||
this.KeysDown.Remove(e.KeyboardInput.Key);
|
||||
return;
|
||||
}
|
||||
|
||||
e.Handled = this.loadedMacros
|
||||
.Where(keyMacro => MacroContainsKey(keyMacro, e.KeyboardInput.Key))
|
||||
.Where(this.MacroHit)
|
||||
.Do(this.HandleMacro)
|
||||
.Any();
|
||||
}
|
||||
}
|
||||
|
||||
public void OnClosing()
|
||||
{
|
||||
this.cancellationTokenSource.Cancel();
|
||||
}
|
||||
|
||||
public void OnStartup()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
private bool MacroHit(KeyMacro keyMacro)
|
||||
{
|
||||
return this.KeysDown.Intersect(keyMacro.Keys).OrderBy(key => key).SequenceEqual(keyMacro.Keys.OrderBy(key => key));
|
||||
}
|
||||
|
||||
private void HandleMacro(KeyMacro keyMacro)
|
||||
{
|
||||
// TODO: Propagate key to guildwars executable.
|
||||
}
|
||||
|
||||
private static bool MacroContainsKey(KeyMacro keyMacro, Keys lastKey)
|
||||
{
|
||||
return keyMacro.Keys.Contains(lastKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using Daybreak.Services.ApplicationLifetime;
|
||||
|
||||
namespace Daybreak.Services.Shortcuts
|
||||
{
|
||||
public interface IShortcutManager : IApplicationLifetimeService
|
||||
{
|
||||
bool ShortcutEnabled { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
using Daybreak.Services.Configuration;
|
||||
using ShellLink;
|
||||
using System.Diagnostics;
|
||||
using System.Extensions;
|
||||
using System.IO;
|
||||
|
||||
namespace Daybreak.Services.Shortcuts
|
||||
{
|
||||
public sealed class ShortcutManager : IShortcutManager
|
||||
{
|
||||
private const string ShortcutName = "Daybreak.lnk";
|
||||
|
||||
private readonly IConfigurationManager configurationManager;
|
||||
|
||||
public bool ShortcutEnabled {
|
||||
get => this.ShortcutExists();
|
||||
set
|
||||
{
|
||||
if (value is true)
|
||||
{
|
||||
this.CreateShortcut();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.RemoveShortcut();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ShortcutManager(IConfigurationManager configurationManager)
|
||||
{
|
||||
this.configurationManager = configurationManager.ThrowIfNull(nameof(configurationManager));
|
||||
this.configurationManager.ConfigurationChanged += (_, _) => this.LoadConfiguration();
|
||||
this.LoadConfiguration();
|
||||
}
|
||||
|
||||
private void LoadConfiguration()
|
||||
{
|
||||
var shortcutEnabled = this.configurationManager.GetConfiguration().PlaceShortcut;
|
||||
if (shortcutEnabled && this.ShortcutEnabled is false)
|
||||
{
|
||||
this.ShortcutEnabled = true;
|
||||
}
|
||||
else if (shortcutEnabled is false && this.ShortcutEnabled is true)
|
||||
{
|
||||
this.ShortcutEnabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
private bool ShortcutExists()
|
||||
{
|
||||
var shortcutFolder = this.configurationManager.GetConfiguration().ShortcutLocation;
|
||||
var shortcutPath = $"{shortcutFolder}\\{ShortcutName}";
|
||||
if (File.Exists(shortcutPath))
|
||||
{
|
||||
var shortcut = Shortcut.ReadFromFile(shortcutPath);
|
||||
var currentExecutable = Process.GetCurrentProcess()?.MainModule?.FileName;
|
||||
if (shortcut.ExtraData?.EnvironmentVariableDataBlock?.TargetAnsi?.Equals(currentExecutable) is true)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void CreateShortcut()
|
||||
{
|
||||
if (this.ShortcutExists())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var shortcutFolder = this.configurationManager.GetConfiguration().ShortcutLocation;
|
||||
var shortcutPath = $"{shortcutFolder}\\{ShortcutName}";
|
||||
var currentExecutable = Process.GetCurrentProcess()?.MainModule?.FileName;
|
||||
var shortcut = Shortcut.CreateShortcut(currentExecutable);
|
||||
shortcut.StringData = new ShellLink.Structures.StringData
|
||||
{
|
||||
WorkingDir = Path.GetDirectoryName(currentExecutable),
|
||||
RelativePath = "Daybreak.exe"
|
||||
};
|
||||
shortcut.WriteToFile(shortcutPath);
|
||||
}
|
||||
|
||||
private void RemoveShortcut()
|
||||
{
|
||||
if (this.ShortcutExists() is false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var shortcutFolder = this.configurationManager.GetConfiguration().ShortcutLocation;
|
||||
var shortcutPath = $"{shortcutFolder}\\{ShortcutName}";
|
||||
File.Delete(shortcutPath);
|
||||
}
|
||||
|
||||
public void OnStartup()
|
||||
{
|
||||
}
|
||||
|
||||
public void OnClosing()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,9 +7,13 @@ namespace Pepa.Wpf.Utilities
|
||||
{
|
||||
static class NativeMethods
|
||||
{
|
||||
public static uint WM_KEYDOWN = 0x0100;
|
||||
public static uint SWP_SHOWWINDOW = 0x0040;
|
||||
public static IntPtr HWND_TOPMOST = new(-1);
|
||||
public static IntPtr HWND_TOP = IntPtr.Zero;
|
||||
public const int WH_KEYBOARD_LL = 13;
|
||||
|
||||
public delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct SystemHandleInformation
|
||||
@@ -93,7 +97,7 @@ namespace Pepa.Wpf.Utilities
|
||||
|
||||
public const int WM_SYSCOMMAND = 0x112;
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto)]
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern bool CloseHandle(IntPtr hObject);
|
||||
@@ -107,7 +111,7 @@ namespace Pepa.Wpf.Utilities
|
||||
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")]
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern bool QueryFullProcessImageName(IntPtr hProcess, uint dwFlags, StringBuilder lpExeName, ref uint lpdwSize);
|
||||
[DllImport("user32.dll")]
|
||||
public static extern bool SetWindowPos(IntPtr hwnd, IntPtr insertAfter, int x, int y, int cx, int cy, uint flags);
|
||||
@@ -115,7 +119,19 @@ namespace Pepa.Wpf.Utilities
|
||||
public static extern bool ShowWindow(IntPtr hwnd, int cmd);
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto)]
|
||||
public static extern int GetWindowTextLength(IntPtr hWnd);
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto)]
|
||||
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern IntPtr LoadLibrary(string lpFileName);
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
|
||||
public static extern bool FreeLibrary(IntPtr hModule);
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
public static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, int dwThreadId);
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
public static extern bool UnhookWindowsHookEx(IntPtr hHook);
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
public static extern IntPtr CallNextHookEx(IntPtr hHook, int code, IntPtr wParam, IntPtr lParam);
|
||||
[DllImport("user32.dll")]
|
||||
public static extern IntPtr GetForegroundWindow();
|
||||
}
|
||||
}
|
||||
@@ -1,35 +1,10 @@
|
||||
using Newtonsoft.Json;
|
||||
using System.IO;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using System.Text;
|
||||
|
||||
namespace Daybreak.Utils
|
||||
{
|
||||
public static class SerializationExtensions
|
||||
{
|
||||
public static byte[] SerializeBytes(this object obj)
|
||||
{
|
||||
byte[] returnArray;
|
||||
using (var memoryStream = new MemoryStream())
|
||||
{
|
||||
var bf = new BinaryFormatter();
|
||||
bf.Serialize(memoryStream, obj);
|
||||
returnArray = memoryStream.ToArray();
|
||||
}
|
||||
return returnArray;
|
||||
}
|
||||
|
||||
public static T DeserializeBytes<T>(this byte[] serializedObject)
|
||||
{
|
||||
T obj;
|
||||
using (var memoryStream = new MemoryStream(serializedObject))
|
||||
{
|
||||
var bf = new BinaryFormatter();
|
||||
obj = (T)bf.Deserialize(memoryStream);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
public static string Serialize<T>(this T obj)
|
||||
{
|
||||
return JsonConvert.SerializeObject(obj);
|
||||
|
||||
@@ -9,13 +9,19 @@
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid VerticalAlignment="Center" HorizontalAlignment="Center" Width="400" Height="200"
|
||||
Background="White">
|
||||
<TextBlock Text="An update has been detected. Do you wish to update?" FontSize="20" TextWrapping="Wrap"
|
||||
Foreground="Black"></TextBlock>
|
||||
<controls:OpaqueButton Text="No" Foreground="Black" TransparentBackground="Gray" BackgroundOpacity="0.2" Width="50" Height="30"
|
||||
FontSize="16" HorizontalAlignment="Center" Margin="0, 0, 80, 0"
|
||||
Clicked="NoButton_Clicked"></controls:OpaqueButton>
|
||||
<controls:OpaqueButton Text="Yes" Foreground="Black" TransparentBackground="Gray" BackgroundOpacity="0.2" Width="50" Height="30"
|
||||
FontSize="16" HorizontalAlignment="Center" Margin="80, 0, 0, 0"
|
||||
Clicked="YesButton_Clicked"></controls:OpaqueButton>
|
||||
<StackPanel VerticalAlignment="Center" Orientation="Vertical">
|
||||
<TextBlock Text="An update has been detected. Do you want to download the update?" HorizontalAlignment="Center"
|
||||
FontSize="16" Foreground="Black" Margin="10, 0, 10, 10" TextWrapping="Wrap"></TextBlock>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"></ColumnDefinition>
|
||||
<ColumnDefinition Width="*"></ColumnDefinition>
|
||||
</Grid.ColumnDefinitions>
|
||||
<controls:OpaqueButton Text="Yes" BackgroundOpacity="0.2" TransparentBackground="Gray" HorizontalAlignment="Center" Margin="10" Width="50" Height="25"
|
||||
Clicked="YesButton_Clicked" Foreground="Black" FontSize="16"></controls:OpaqueButton>
|
||||
<controls:OpaqueButton Text="No" BackgroundOpacity="0.2" TransparentBackground="Gray" HorizontalAlignment="Center" Margin="10" Width="50" Height="25"
|
||||
Clicked="NoButton_Clicked" Foreground="Black" Grid.Column="1" FontSize="16"></controls:OpaqueButton>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
||||
@@ -87,11 +87,11 @@
|
||||
<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>
|
||||
<TextBlock Text="Detect build templates (in browser)" Foreground="White" FontSize="22" VerticalAlignment="Center" Margin="0, 0, 15, 0" Height="30"></TextBlock>
|
||||
<TextBlock Text="Launch gw as current user" Foreground="White" FontSize="22" VerticalAlignment="Center" Margin="0, 0, 15, 0" Height="30"></TextBlock>
|
||||
<StackPanel Margin="0, 0, 15, 0">
|
||||
<TextBlock Text="Multi-launch support" Foreground="White" FontSize="22" Height="30"></TextBlock>
|
||||
<TextBlock Text="GWToolbox startup delay (in ms)" Foreground="White" FontSize="22" Height="30"></TextBlock>
|
||||
<TextBlock Text="Detect build templates (in browser)" Foreground="White" FontSize="22" Height="30"></TextBlock>
|
||||
<TextBlock Text="Launch gw as current user" Foreground="White" FontSize="22" Height="30"></TextBlock>
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="1">
|
||||
<ToggleButton IsChecked="{Binding ElementName=_this, Path=MultiLaunch, Mode=TwoWay}" Style="{StaticResource AnimatedSwitch}"
|
||||
|
||||
@@ -23,6 +23,8 @@ namespace Daybreak.Views
|
||||
DependencyPropertyExtensions.Register<ExperimentalSettingsView, bool>(nameof(DynamicBuildLoading));
|
||||
public static readonly DependencyProperty LaunchAsCurrentUserProperty =
|
||||
DependencyPropertyExtensions.Register<ExperimentalSettingsView, bool>(nameof(LaunchAsCurrentUser));
|
||||
public static readonly DependencyProperty MacrosEnabledProperty =
|
||||
DependencyPropertyExtensions.Register<ExperimentalSettingsView, bool>(nameof(MacrosEnabled));
|
||||
|
||||
private readonly IViewManager viewManager;
|
||||
private readonly IConfigurationManager configurationManager;
|
||||
@@ -47,6 +49,11 @@ namespace Daybreak.Views
|
||||
get => this.GetTypedValue<bool>(DynamicBuildLoadingProperty);
|
||||
set => this.SetValue(DynamicBuildLoadingProperty, value);
|
||||
}
|
||||
public bool MacrosEnabled
|
||||
{
|
||||
get => this.GetTypedValue<bool>(MacrosEnabledProperty);
|
||||
set => this.SetValue(MacrosEnabledProperty, value);
|
||||
}
|
||||
|
||||
public ExperimentalSettingsView(
|
||||
IViewManager viewManager,
|
||||
@@ -65,6 +72,7 @@ namespace Daybreak.Views
|
||||
this.GWToolboxLaunchDelay = config.ExperimentalFeatures.ToolboxAutoLaunchDelay.ToString();
|
||||
this.DynamicBuildLoading = config.ExperimentalFeatures.DynamicBuildLoading;
|
||||
this.LaunchAsCurrentUser = config.ExperimentalFeatures.LaunchGuildwarsAsCurrentUser;
|
||||
this.MacrosEnabled = config.ExperimentalFeatures.CanInterceptKeys;
|
||||
}
|
||||
|
||||
private void SaveExperimentalSettings()
|
||||
@@ -73,6 +81,7 @@ namespace Daybreak.Views
|
||||
config.ExperimentalFeatures.MultiLaunchSupport = this.MultiLaunch;
|
||||
config.ExperimentalFeatures.DynamicBuildLoading = this.DynamicBuildLoading;
|
||||
config.ExperimentalFeatures.LaunchGuildwarsAsCurrentUser = this.LaunchAsCurrentUser;
|
||||
config.ExperimentalFeatures.CanInterceptKeys = this.MacrosEnabled;
|
||||
if (int.TryParse(this.GWToolboxLaunchDelay, out var gwToolboxLaunchDelay))
|
||||
{
|
||||
config.ExperimentalFeatures.ToolboxAutoLaunchDelay = gwToolboxLaunchDelay;
|
||||
|
||||
@@ -18,27 +18,10 @@ namespace Daybreak.Views
|
||||
/// <summary>
|
||||
/// Interaction logic for StartupView.xaml
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0044:Add readonly modifier", Justification = "Fields used by source generator for DependencyProperty")]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "Used by source generators")]
|
||||
public partial class MainView : UserControl
|
||||
{
|
||||
public static readonly DependencyProperty ButtonsVisibleProperty =
|
||||
DependencyPropertyExtensions.Register<MainView, bool>(nameof(ButtonsVisible), new PropertyMetadata(true));
|
||||
public static readonly DependencyProperty LaunchButtonEnabledProperty =
|
||||
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 =
|
||||
DependencyPropertyExtensions.Register<MainView, string>(nameof(LeftBrowserAddress));
|
||||
public static readonly DependencyProperty RightBrowserFavoriteAddressProperty =
|
||||
DependencyPropertyExtensions.Register<MainView, string>(nameof(RightBrowserFavoriteAddress));
|
||||
public static readonly DependencyProperty LeftBrowserFavoriteAddressProperty =
|
||||
DependencyPropertyExtensions.Register<MainView, string>(nameof(LeftBrowserFavoriteAddress));
|
||||
|
||||
private readonly IApplicationLauncher applicationDetector;
|
||||
private readonly IViewManager viewManager;
|
||||
private readonly IConfigurationManager configurationManager;
|
||||
@@ -48,51 +31,24 @@ namespace Daybreak.Views
|
||||
private bool leftBrowserMaximized = false;
|
||||
private bool rightBrowserMaximized = false;
|
||||
|
||||
public bool ButtonsVisible
|
||||
{
|
||||
get => this.GetTypedValue<bool>(ButtonsVisibleProperty);
|
||||
set => this.SetTypedValue(ButtonsVisibleProperty, value);
|
||||
}
|
||||
public string RightBrowserFavoriteAddress
|
||||
{
|
||||
get => this.GetTypedValue<string>(RightBrowserFavoriteAddressProperty);
|
||||
set => this.SetTypedValue(RightBrowserFavoriteAddressProperty, value);
|
||||
}
|
||||
public string LeftBrowserFavoriteAddress
|
||||
{
|
||||
get => this.GetTypedValue<string>(LeftBrowserFavoriteAddressProperty);
|
||||
set => this.SetTypedValue(LeftBrowserFavoriteAddressProperty, value);
|
||||
}
|
||||
public string RightBrowserAddress
|
||||
{
|
||||
get => this.GetTypedValue<string>(RightBrowserAddressProperty);
|
||||
set => this.SetTypedValue(RightBrowserAddressProperty, value);
|
||||
}
|
||||
public string LeftBrowserAddress
|
||||
{
|
||||
get => this.GetTypedValue<string>(LeftBrowserAddressProperty);
|
||||
set => this.SetTypedValue(LeftBrowserAddressProperty, value);
|
||||
}
|
||||
public bool LaunchButtonEnabled
|
||||
{
|
||||
get => this.GetTypedValue<bool>(LaunchButtonEnabledProperty);
|
||||
set => this.SetTypedValue(LaunchButtonEnabledProperty, value);
|
||||
}
|
||||
public bool LaunchToolboxButtonEnabled
|
||||
{
|
||||
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);
|
||||
}
|
||||
[GenerateDependencyProperty(InitialValue = true)]
|
||||
private bool buttonsVisible;
|
||||
[GenerateDependencyProperty]
|
||||
private string rightBrowserFavoriteAddress;
|
||||
[GenerateDependencyProperty]
|
||||
private string leftBrowserFavoriteAddress;
|
||||
[GenerateDependencyProperty]
|
||||
private string rightBrowserAddress;
|
||||
[GenerateDependencyProperty]
|
||||
private string leftBrowserAddress;
|
||||
[GenerateDependencyProperty]
|
||||
private bool launchButtonEnabled;
|
||||
[GenerateDependencyProperty]
|
||||
private bool launchToolboxButtonEnabled;
|
||||
[GenerateDependencyProperty]
|
||||
private bool launchTexmodButtonEnabled;
|
||||
[GenerateDependencyProperty(InitialValue = true)]
|
||||
private bool browsersEnabled;
|
||||
|
||||
public MainView(
|
||||
IApplicationLauncher applicationDetector,
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<TextBlock Text="{Binding MessageToUser}" Margin="10, 0, 10, 0" Foreground="Black"
|
||||
TextWrapping="Wrap" HorizontalAlignment="Center" FontSize="16"></TextBlock>
|
||||
<TextBlock Text="Do you want to restart the application with administrator rights?" HorizontalAlignment="Center"
|
||||
FontSize="16" Foreground="Black" Margin="10, 0, 10, 10"></TextBlock>
|
||||
FontSize="16" Foreground="Black" Margin="10, 0, 10, 10" TextWrapping="Wrap"></TextBlock>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"></ColumnDefinition>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using Daybreak.Models;
|
||||
using Daybreak.Services.ApplicationLauncher;
|
||||
using Daybreak.Services.Logging;
|
||||
using Daybreak.Services.Privilege;
|
||||
using Daybreak.Services.ViewManagement;
|
||||
using Daybreak.Utils;
|
||||
using System.Extensions;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
xmlns:local="clr-namespace:Daybreak.Views"
|
||||
xmlns:controls="clr-namespace:Daybreak.Controls"
|
||||
mc:Ignorable="d"
|
||||
x:Name="_this"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid Background="#A0202020">
|
||||
<Grid.RowDefinitions>
|
||||
@@ -14,6 +15,10 @@
|
||||
</Grid.RowDefinitions>
|
||||
<controls:BackButton Foreground="White" Height="30" Width="30" Grid.Column="0" HorizontalAlignment="Left" Margin="5"
|
||||
Clicked="BackButton_Clicked"></controls:BackButton>
|
||||
<TextBlock Text="Choose screen" FontSize="18" Foreground="White" HorizontalAlignment="Center"></TextBlock>
|
||||
<controls:OpaqueButton Text="Test" Foreground="White" HighlightOpacity="0.3" Highlight="White" FontSize="18" Width="80"
|
||||
HorizontalAlignment="Right" Margin="0, 0, 50, 0" Clicked="OpaqueButton_Clicked"
|
||||
IsEnabled="{Binding ElementName=_this, Path=CanTest, Mode=OneWay}"></controls:OpaqueButton>
|
||||
<controls:SaveButton Foreground="White" Height="30" Width="30" Grid.Column="1" HorizontalAlignment="Right" Margin="5"
|
||||
Clicked="SaveButton_Clicked"></controls:SaveButton>
|
||||
<Viewbox Grid.Row="1">
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
using Daybreak.Controls.Templates;
|
||||
using Daybreak.Models;
|
||||
using Daybreak.Services.ApplicationLauncher;
|
||||
using Daybreak.Services.Configuration;
|
||||
using Daybreak.Services.Screens;
|
||||
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.Media;
|
||||
|
||||
namespace Daybreak.Views
|
||||
@@ -14,23 +17,32 @@ namespace Daybreak.Views
|
||||
/// <summary>
|
||||
/// Interaction logic for ScreenChoiceView.xaml
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0044:Add readonly modifier", Justification = "Fields used by source generator for DependencyProperty")]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "Used by source generators")]
|
||||
public partial class ScreenChoiceView : UserControl
|
||||
{
|
||||
{
|
||||
private readonly IScreenManager screenManager;
|
||||
private readonly IViewManager viewManager;
|
||||
private readonly IConfigurationManager configurationManager;
|
||||
private readonly IApplicationLauncher applicationLauncher;
|
||||
private int selectedId;
|
||||
|
||||
[GenerateDependencyProperty]
|
||||
private bool canTest;
|
||||
|
||||
public ScreenChoiceView(
|
||||
IViewManager viewManager,
|
||||
IScreenManager screenManager,
|
||||
IConfigurationManager configurationManager)
|
||||
IConfigurationManager configurationManager,
|
||||
IApplicationLauncher applicationLauncher)
|
||||
{
|
||||
this.viewManager = viewManager.ThrowIfNull(nameof(viewManager));
|
||||
this.screenManager = screenManager.ThrowIfNull(nameof(screenManager));
|
||||
this.configurationManager = configurationManager.ThrowIfNull(nameof(configurationManager));
|
||||
this.applicationLauncher = applicationLauncher.ThrowIfNull(nameof(applicationLauncher));
|
||||
this.InitializeComponent();
|
||||
this.selectedId = configurationManager.GetConfiguration().DesiredGuildwarsScreen;
|
||||
this.CanTest = applicationLauncher.IsGuildwarsRunning;
|
||||
this.SetupView();
|
||||
}
|
||||
|
||||
@@ -77,5 +89,16 @@ namespace Daybreak.Views
|
||||
this.configurationManager.GetConfiguration().DesiredGuildwarsScreen = this.selectedId;
|
||||
this.viewManager.ShowView<SettingsCategoryView>();
|
||||
}
|
||||
|
||||
private void OpaqueButton_Clicked(object sender, EventArgs e)
|
||||
{
|
||||
var screen = this.screenManager.Screens.Skip(this.selectedId).FirstOrDefault();
|
||||
if (screen is null)
|
||||
{
|
||||
throw new InvalidOperationException($"Unable to test placement. No screen with id {this.selectedId}");
|
||||
}
|
||||
|
||||
this.screenManager.MoveGuildwarsToScreen(screen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,71 +66,86 @@
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<Grid Background="#A0202020">
|
||||
<Grid.RowDefinitions>
|
||||
<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>
|
||||
<StackPanel Orientation="Vertical" Grid.Row="1">
|
||||
<TextBlock Text="Texmod path" FontSize="22" Foreground="White" Height="30"></TextBlock>
|
||||
<TextBlock Text="GWToolbox path: " FontSize="22" Foreground="White" Height="30"></TextBlock>
|
||||
<TextBlock Text="GWToolbox auto-launch: " FontSize="22" Foreground="White" Height="30"></TextBlock>
|
||||
<TextBlock Text="Browsers enabled: " FontSize="22" Foreground="White" Height="30"/>
|
||||
<TextBlock Text="Browsers address bar readonly: " FontSize="22" Foreground="White" Height="30"/>
|
||||
<TextBlock Text="Left browser homepage: " FontSize="22" Foreground="White" Height="30"></TextBlock>
|
||||
<TextBlock Text="Right browser homepage: " FontSize="22" Foreground="White" Height="30"></TextBlock>
|
||||
<TextBlock Text="Auto-place on desired screen: " FontSize="22" Foreground="White" Height="30"></TextBlock>
|
||||
<TextBlock Text="Desired screen id: " FontSize="22" Foreground="White" Height="30"></TextBlock>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Vertical" Grid.Row="1" Grid.Column="1">
|
||||
<Grid>
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto">
|
||||
<Grid Background="#A0202020">
|
||||
<Grid.RowDefinitions>
|
||||
<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>
|
||||
<StackPanel Orientation="Vertical" Grid.Row="1">
|
||||
<TextBlock Text="Texmod path" FontSize="22" Foreground="White" Height="30"></TextBlock>
|
||||
<TextBlock Text="GWToolbox auto-launch: " FontSize="22" Foreground="White" Height="30"></TextBlock>
|
||||
<TextBlock Text="GWToolbox path: " FontSize="22" Foreground="White" Height="30"></TextBlock>
|
||||
<TextBlock Text="Browsers enabled: " FontSize="22" Foreground="White" Height="30"/>
|
||||
<TextBlock Text="Browsers address bar readonly: " FontSize="22" Foreground="White" Height="30"/>
|
||||
<TextBlock Text="Left browser homepage: " FontSize="22" Foreground="White" Height="30"></TextBlock>
|
||||
<TextBlock Text="Right browser homepage: " FontSize="22" Foreground="White" Height="30"></TextBlock>
|
||||
<TextBlock Text="Auto-place on desired screen: " FontSize="22" Foreground="White" Height="30"></TextBlock>
|
||||
<TextBlock Text="Desired screen id: " FontSize="22" Foreground="White" Height="30"></TextBlock>
|
||||
<TextBlock Text="Place Shortcut" FontSize="22" Foreground="White" Height="30"></TextBlock>
|
||||
<TextBlock Text="Shortcut folder" FontSize="22" Foreground="White" Height="30"></TextBlock>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Vertical" Grid.Row="1" Grid.Column="1">
|
||||
<Grid Height="30">
|
||||
<TextBox HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch"
|
||||
FontSize="22" Margin="0, 0, 30, 0" Background="Transparent" Foreground="White"
|
||||
Text="{Binding ElementName=_this, Path=TexmodPath, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></TextBox>
|
||||
<controls:FilePickerGlyph Height="30" Width="30" HorizontalAlignment="Right"
|
||||
Foreground="White" BorderBrush="Gray" BorderThickness="0"
|
||||
Clicked="TexmodFilePickerGlyph_Clicked"></controls:FilePickerGlyph>
|
||||
</Grid>
|
||||
<ToggleButton HorizontalAlignment="Center" HorizontalContentAlignment="Stretch" Style="{StaticResource AnimatedSwitch}" Height="30" Width="40"
|
||||
FontSize="22" Foreground="White" IsChecked="{Binding ElementName=_this, Path=ToolboxAutoLaunch, Mode=TwoWay}"></ToggleButton>
|
||||
<Grid Height="30">
|
||||
<TextBox HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch"
|
||||
FontSize="22" Margin="0, 0, 30, 0" Background="Transparent" Foreground="White"
|
||||
Text="{Binding ElementName=_this, Path=ToolboxPath, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></TextBox>
|
||||
<controls:FilePickerGlyph Height="30" Width="30" HorizontalAlignment="Right"
|
||||
Foreground="White" BorderBrush="Gray" BorderThickness="0"
|
||||
Clicked="ToolboxFilePickerGlyph_Clicked"></controls:FilePickerGlyph>
|
||||
</Grid>
|
||||
<ToggleButton HorizontalAlignment="Center" HorizontalContentAlignment="Stretch" Style="{StaticResource AnimatedSwitch}" Height="30" Width="40"
|
||||
FontSize="22" Foreground="White" IsChecked="{Binding ElementName=_this, Path=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" Margin="0, 0, 30, 0" Background="Transparent" Foreground="White"
|
||||
Text="{Binding ElementName=_this, Path=TexmodPath, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></TextBox>
|
||||
<controls:FilePickerGlyph Height="30" Width="30" HorizontalAlignment="Right"
|
||||
Foreground="White" BorderBrush="Gray" BorderThickness="0"
|
||||
Clicked="TexmodFilePickerGlyph_Clicked"></controls:FilePickerGlyph>
|
||||
</Grid>
|
||||
<Grid>
|
||||
FontSize="22" Background="Transparent" Foreground="White" Height="30"
|
||||
Text="{Binding ElementName=_this, Path=LeftBrowserUrl, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></TextBox>
|
||||
<TextBox HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch"
|
||||
FontSize="22" Margin="0, 0, 30, 0" Background="Transparent" Foreground="White"
|
||||
Text="{Binding ElementName=_this, Path=ToolboxPath, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></TextBox>
|
||||
<controls:FilePickerGlyph Height="30" Width="30" HorizontalAlignment="Right"
|
||||
Foreground="White" BorderBrush="Gray" BorderThickness="0"
|
||||
Clicked="ToolboxFilePickerGlyph_Clicked"></controls:FilePickerGlyph>
|
||||
</Grid>
|
||||
<ToggleButton HorizontalAlignment="Center" HorizontalContentAlignment="Stretch" Style="{StaticResource AnimatedSwitch}" Height="30" Width="40"
|
||||
FontSize="22" Foreground="White" IsChecked="{Binding ElementName=_this, Path=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, UpdateSourceTrigger=PropertyChanged}"></TextBox>
|
||||
<TextBox HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch"
|
||||
FontSize="22" Background="Transparent" Foreground="White"
|
||||
Text="{Binding ElementName=_this, Path=RightBrowserUrl, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></TextBox>
|
||||
<ToggleButton HorizontalAlignment="Center" HorizontalContentAlignment="Stretch" Style="{StaticResource AnimatedSwitch}" Height="30" Width="40"
|
||||
FontSize="22" Foreground="White" IsChecked="{Binding ElementName=_this, Path=AutoPlaceOnScreen, Mode=TwoWay}"></ToggleButton>
|
||||
<Grid>
|
||||
<TextBox HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch"
|
||||
FontSize="22" Background="Transparent" Foreground="White"
|
||||
Text="{Binding ElementName=_this, Path=DesiredScreen, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
PreviewTextInput="TextBox_AllowOnlyNumbers" Margin="0, 0, 30, 0"></TextBox>
|
||||
<controls:FilePickerGlyph Height="30" Width="30" HorizontalAlignment="Right"
|
||||
Foreground="White" BorderBrush="Gray" BorderThickness="0"
|
||||
Clicked="ScreenPickerGlyph_Clicked"></controls:FilePickerGlyph>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
FontSize="22" Background="Transparent" Foreground="White" Height="30"
|
||||
Text="{Binding ElementName=_this, Path=RightBrowserUrl, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></TextBox>
|
||||
<ToggleButton HorizontalAlignment="Center" HorizontalContentAlignment="Stretch" Style="{StaticResource AnimatedSwitch}" Height="30" Width="40"
|
||||
FontSize="22" Foreground="White" IsChecked="{Binding ElementName=_this, Path=AutoPlaceOnScreen, Mode=TwoWay}"></ToggleButton>
|
||||
<Grid Height="30">
|
||||
<TextBox HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch"
|
||||
FontSize="22" Background="Transparent" Foreground="White"
|
||||
Text="{Binding ElementName=_this, Path=DesiredScreen, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
PreviewTextInput="TextBox_AllowOnlyNumbers" Margin="0, 0, 30, 0"></TextBox>
|
||||
<controls:FilePickerGlyph Height="30" Width="30" HorizontalAlignment="Right"
|
||||
Foreground="White" BorderBrush="Gray" BorderThickness="0"
|
||||
Clicked="ScreenPickerGlyph_Clicked"></controls:FilePickerGlyph>
|
||||
</Grid>
|
||||
<ToggleButton HorizontalAlignment="Center" HorizontalContentAlignment="Stretch" Style="{StaticResource AnimatedSwitch}" Height="30" Width="40"
|
||||
FontSize="22" Foreground="White" IsChecked="{Binding ElementName=_this, Path=ShortcutPlaced, Mode=TwoWay}"></ToggleButton>
|
||||
<Grid Height="30">
|
||||
<TextBox HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch"
|
||||
FontSize="22" Background="Transparent" Foreground="White"
|
||||
Text="{Binding ElementName=_this, Path=ShortcutFolder, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
Margin="0, 0, 30, 0"></TextBox>
|
||||
<controls:FilePickerGlyph Height="30" Width="30" HorizontalAlignment="Right"
|
||||
Foreground="White" BorderBrush="Gray" BorderThickness="0"
|
||||
Clicked="ShortcutFolderPickerGlyph_Clicked"></controls:FilePickerGlyph>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
</UserControl>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Daybreak.Services.Configuration;
|
||||
using Daybreak.Services.Shortcuts;
|
||||
using Daybreak.Services.ViewManagement;
|
||||
using Microsoft.Win32;
|
||||
using System;
|
||||
@@ -6,85 +7,47 @@ using System.Extensions;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Extensions;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Daybreak.Views
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for SettingsView.xaml
|
||||
/// </summary>
|
||||
public partial class SettingsView : UserControl
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0044:Add readonly modifier", Justification = "Fields used by source generator for DependencyProperty")]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "Used by source generators")]
|
||||
public partial class SettingsView : System.Windows.Controls.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));
|
||||
public static readonly DependencyProperty AutoPlaceOnScreenProperty =
|
||||
DependencyPropertyExtensions.Register<SettingsView, bool>(nameof(AutoPlaceOnScreen));
|
||||
public static readonly DependencyProperty DesiredScreenProperty =
|
||||
DependencyPropertyExtensions.Register<SettingsView, string>(nameof(DesiredScreen));
|
||||
|
||||
private readonly IConfigurationManager configurationManager;
|
||||
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 bool AutoPlaceOnScreen
|
||||
{
|
||||
get => this.GetTypedValue<bool>(AutoPlaceOnScreenProperty);
|
||||
set => this.SetValue(AutoPlaceOnScreenProperty, value);
|
||||
}
|
||||
public string DesiredScreen
|
||||
{
|
||||
get => this.GetTypedValue<string>(DesiredScreenProperty);
|
||||
set => this.SetValue(DesiredScreenProperty, value);
|
||||
}
|
||||
[GenerateDependencyProperty]
|
||||
private string texmodPath;
|
||||
[GenerateDependencyProperty]
|
||||
private bool toolboxAutoLaunch;
|
||||
[GenerateDependencyProperty]
|
||||
private string toolboxPath;
|
||||
[GenerateDependencyProperty]
|
||||
private bool addressBarReadonly;
|
||||
[GenerateDependencyProperty]
|
||||
private string leftBrowserUrl;
|
||||
[GenerateDependencyProperty]
|
||||
private string rightBrowserUrl;
|
||||
[GenerateDependencyProperty]
|
||||
private bool browsersEnabled;
|
||||
[GenerateDependencyProperty]
|
||||
private bool autoPlaceOnScreen;
|
||||
[GenerateDependencyProperty]
|
||||
private string desiredScreen;
|
||||
[GenerateDependencyProperty]
|
||||
private string shortcutFolder;
|
||||
[GenerateDependencyProperty]
|
||||
private bool shortcutPlaced;
|
||||
|
||||
public SettingsView(
|
||||
IConfigurationManager configurationManager,
|
||||
IViewManager viewManager)
|
||||
IViewManager viewManager,
|
||||
IShortcutManager shortcutManager)
|
||||
{
|
||||
this.configurationManager = configurationManager.ThrowIfNull(nameof(configurationManager));
|
||||
this.viewManager = viewManager.ThrowIfNull(nameof(viewManager));
|
||||
@@ -104,6 +67,9 @@ namespace Daybreak.Views
|
||||
this.BrowsersEnabled = config.BrowsersEnabled;
|
||||
this.AutoPlaceOnScreen = config.SetGuildwarsWindowSizeOnLaunch;
|
||||
this.DesiredScreen = config.DesiredGuildwarsScreen.ToString();
|
||||
this.ShortcutFolder = config.ShortcutLocation;
|
||||
this.ShortcutPlaced = config.PlaceShortcut;
|
||||
|
||||
}
|
||||
|
||||
private void SaveButton_Clicked(object sender, EventArgs e)
|
||||
@@ -118,13 +84,15 @@ namespace Daybreak.Views
|
||||
currentConfig.BrowsersEnabled = this.BrowsersEnabled;
|
||||
currentConfig.SetGuildwarsWindowSizeOnLaunch = this.AutoPlaceOnScreen;
|
||||
currentConfig.DesiredGuildwarsScreen = int.Parse(this.DesiredScreen);
|
||||
currentConfig.ShortcutLocation = this.ShortcutFolder;
|
||||
currentConfig.PlaceShortcut = this.ShortcutPlaced;
|
||||
this.configurationManager.SaveConfiguration(currentConfig);
|
||||
this.viewManager.ShowView<SettingsCategoryView>();
|
||||
}
|
||||
|
||||
private void ToolboxFilePickerGlyph_Clicked(object sender, EventArgs e)
|
||||
{
|
||||
var filePicker = new OpenFileDialog()
|
||||
var filePicker = new Microsoft.Win32.OpenFileDialog()
|
||||
{
|
||||
CheckFileExists = true,
|
||||
CheckPathExists = true,
|
||||
@@ -139,7 +107,7 @@ namespace Daybreak.Views
|
||||
|
||||
private void TexmodFilePickerGlyph_Clicked(object sender, EventArgs e)
|
||||
{
|
||||
var filePicker = new OpenFileDialog()
|
||||
var filePicker = new Microsoft.Win32.OpenFileDialog()
|
||||
{
|
||||
CheckFileExists = true,
|
||||
CheckPathExists = true,
|
||||
@@ -152,6 +120,21 @@ namespace Daybreak.Views
|
||||
}
|
||||
}
|
||||
|
||||
private void ShortcutFolderPickerGlyph_Clicked(object sender, EventArgs e)
|
||||
{
|
||||
var folderPicker = new FolderBrowserDialog()
|
||||
{
|
||||
Description = "Select shortcut folder",
|
||||
UseDescriptionForTitle = true,
|
||||
SelectedPath = this.ShortcutFolder,
|
||||
ShowNewFolderButton = true
|
||||
};
|
||||
if (folderPicker.ShowDialog() is DialogResult.OK)
|
||||
{
|
||||
this.ShortcutFolder = folderPicker.SelectedPath;
|
||||
}
|
||||
}
|
||||
|
||||
private void ScreenPickerGlyph_Clicked(object sender, EventArgs e)
|
||||
{
|
||||
this.viewManager.ShowView<ScreenChoiceView>();
|
||||
|
||||
@@ -9,14 +9,17 @@
|
||||
xmlns:controls="clr-namespace:Daybreak.Controls"
|
||||
Loaded="UpdateView_Loaded"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<UserControl.Resources>
|
||||
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"></BooleanToVisibilityConverter>
|
||||
</UserControl.Resources>
|
||||
<Grid VerticalAlignment="Center" HorizontalAlignment="Center" Background="White" MinHeight="200" MinWidth="400">
|
||||
<StackPanel VerticalAlignment="Center">
|
||||
<TextBlock Text="{Binding ElementName=_this, Path=Description, Mode=OneWay}" Margin="10, 0, 10, 10" Foreground="Black"
|
||||
TextWrapping="Wrap"></TextBlock>
|
||||
<TextBlock Text="{Binding ElementName=_this, Path=Description, Mode=OneWay}" Margin="10, 0, 10, 0" Foreground="Black"
|
||||
TextWrapping="Wrap" HorizontalAlignment="Center" FontSize="16"></TextBlock>
|
||||
<ProgressBar Minimum="0" Maximum="100" Value="{Binding ElementName=_this, Path=ProgressValue, Mode=OneWay}" Width="300" Height="20"></ProgressBar>
|
||||
<controls:OpaqueButton Text="Ok" BackgroundOpacity="0.2" TransparentBackground="Gray" HorizontalAlignment="Center" Margin="10" Width="30" Height="20"
|
||||
IsEnabled="{Binding ElementName=_this, Path=ContinueButtonEnabled, Mode=OneWay}"
|
||||
Clicked="OpaqueButton_Clicked" Foreground="Black"></controls:OpaqueButton>
|
||||
<controls:OpaqueButton Text="Ok" BackgroundOpacity="0.2" TransparentBackground="Gray" HorizontalAlignment="Center" Margin="10" Width="50" Height="25"
|
||||
Clicked="OpaqueButton_Clicked" Foreground="Black" FontSize="16"
|
||||
Visibility="{Binding ElementName=_this, Path=ContinueButtonEnabled, Mode=OneWay, Converter={StaticResource BooleanToVisibilityConverter}}"></controls:OpaqueButton>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
||||
@@ -12,37 +12,22 @@ namespace Daybreak.Views
|
||||
/// <summary>
|
||||
/// Interaction logic for UpdateView.xaml
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0044:Add readonly modifier", Justification = "Fields used by source generator for DependencyProperty")]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "Used by source generators")]
|
||||
public partial class UpdateView : UserControl
|
||||
{
|
||||
public readonly static DependencyProperty DescriptionProperty =
|
||||
DependencyPropertyExtensions.Register<UpdateView, string>(nameof(Description));
|
||||
public readonly static DependencyProperty ProgressValueProperty =
|
||||
DependencyPropertyExtensions.Register<UpdateView, double>(nameof(ProgressValue));
|
||||
public readonly static DependencyProperty ContinueButtonEnabledProperty =
|
||||
DependencyPropertyExtensions.Register<UpdateView, bool>(nameof(ContinueButtonEnabled));
|
||||
|
||||
private readonly ILogger logger;
|
||||
private readonly IViewManager viewManager;
|
||||
private readonly IApplicationUpdater applicationUpdater;
|
||||
private readonly UpdateStatus updateStatus = new();
|
||||
|
||||
private bool success = false;
|
||||
|
||||
public string Description
|
||||
{
|
||||
get => this.GetTypedValue<string>(DescriptionProperty);
|
||||
set => this.SetValue(DescriptionProperty, value);
|
||||
}
|
||||
public double ProgressValue
|
||||
{
|
||||
get => this.GetTypedValue<double>(ProgressValueProperty);
|
||||
set => this.SetValue(ProgressValueProperty, value);
|
||||
}
|
||||
public bool ContinueButtonEnabled
|
||||
{
|
||||
get => this.GetTypedValue<bool>(ContinueButtonEnabledProperty);
|
||||
set => this.SetValue(ContinueButtonEnabledProperty, value);
|
||||
}
|
||||
[GenerateDependencyProperty]
|
||||
private string description;
|
||||
[GenerateDependencyProperty]
|
||||
private double progressValue;
|
||||
[GenerateDependencyProperty]
|
||||
private bool continueButtonEnabled;
|
||||
|
||||
public UpdateView(
|
||||
IApplicationUpdater applicationUpdater,
|
||||
|
||||
@@ -25,33 +25,60 @@ 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).
|
||||
|
||||
Manages build templates. Load/save builds from the guildwars build folder. Ability to dynamically load build templates from the embeded browsers. Opens embeded browser for professions, attributes and skills when selected.
|
||||
|
||||
Screen placing/binding. If enabled, places guildwars executable on desired screen at launch.
|
||||
|
||||
Shortcut management. Can manage automatically shortcuts to desired folder.
|
||||
|
||||
# Examples/Usage
|
||||
|
||||
## Settings.
|
||||
To modify any settings, press the settings button on the titlebar
|
||||

|
||||
|
||||
## Settings categories.
|
||||
To adjust functionality, choose one of the settings categories
|
||||

|
||||
|
||||
## Using the embeded browsers.
|
||||
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.
|
||||

|
||||
|
||||
## Displaying screenshots
|
||||
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.
|
||||
|
||||
## Account management
|
||||
To adjust accounts, go into account settings. Clicking on the star next to an account sets it as the current account.
|
||||

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

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

|
||||
|
||||
## Build management / Template management
|
||||
To manage builds, go into Settings, Builds. Here you can select/remove builds.
|
||||

|
||||
|
||||
## Build editor
|
||||
Doubleclick on one of the builds to enter the template management view. Here you can click on skills to open the wiki page of the skill. You can adjust professions, attributes and add/remove skills.
|
||||

|
||||
|
||||
## Dynamically load build from browser
|
||||
To dynamically load a build, while browsing in the browsers from the main page, select and rightclick any text on the page that might be a template. If it is a template, the client will open a context menu with a button called "Load build template". Click on that button to load the build and switch to build template view.
|
||||
|
||||

|
||||
|
||||
## Screen selection/binding
|
||||
To launch the guildwars executable to a specific screen, open Settings, Launcher Settings either fill in the "Desired screen id",
|
||||

|
||||
or use the selection view. If you press Test button on screen selection view, it will automatically move the currently running guildwars to the selected screen.
|
||||

|
||||
|
||||
## Shortcuts
|
||||
To manage launcher shortcuts, use the Settings, Launcher Settings menu. If you want a different folder than the desktop, use the "Shortcut folder" setting to change to the desired place. By toggling "Shortcut placed" toggle, a shortcut will be created/deleted.
|
||||

|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
Param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$version
|
||||
) #end param
|
||||
|
||||
Write-Output "Deleting pdb file"
|
||||
Remove-item .\Publish\Daybreak.pdb
|
||||
$zipPath = "Publish\daybreakv$version.zip"
|
||||
Write-Output "Compressing binaries to $zipPath"
|
||||
Compress-Archive .\Publish\* $zipPath -Force
|
||||
Write-Output "Cleaning up files"
|
||||
foreach ($file in Get-ChildItem -Path .\Publish -Exclude *.zip -Recurse -ErrorAction SilentlyContinue)
|
||||
{
|
||||
Write-Output "Removing $file"
|
||||
Remove-item $file -Recurse -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
Write-Host "Retrieving version"
|
||||
$filepath = Get-ChildItem -Path .\Daybreak -Filter *.version
|
||||
$version = $filepath.BaseName
|
||||
Write-Host "Version: $version"
|
||||
return $version
|
||||
Reference in New Issue
Block a user