From 4b43373d5b640f2496f5133f10500dc36fa8ad01 Mon Sep 17 00:00:00 2001 From: Neonalig Date: Sun, 25 Oct 2020 12:09:20 +0800 Subject: [PATCH] UI Resizing, Regex Fixes, and Recommended Modes Replaced panels, layouts, etc. for most windows to allow for proper resizing Tweaked and adjusted Regex patterns to be more resilient and reliable Added an automatically retrieved list of recommended gamemodes from the 'Custom Rulesets Directory' https://github.com/ppy/osu/issues/5852 --- App.config | 58 ++++----- App.xaml | 5 +- App.xaml.cs | 10 +- Extensions/Extensions.cs | 30 ++++- Extensions/FileExtensions.cs | 24 ++-- Gamemode.cs | 29 +++-- Osu!ModeManager.csproj | 1 + Properties/AssemblyInfo.cs | 22 +++- UpdateStatus.cs | 16 +++ Windows/GamemodeEditor.xaml | 101 ++++++++++------ Windows/GamemodeEditor.xaml.cs | 157 +++++++++++++++++++++---- Windows/MainWindow.xaml | 196 ++++++++++++++++++------------- Windows/MainWindow.xaml.cs | 33 ++++-- Windows/OAuthWindow.xaml | 41 ++++--- Windows/OAuthWindow.xaml.cs | 30 ++++- Windows/ReleaseWindow.xaml | 32 ++--- Windows/ReleaseWindow.xaml.cs | 16 ++- Windows/SelfUpdateWindow.xaml | 41 ++++--- Windows/SelfUpdateWindow.xaml.cs | 28 +++-- Windows/UpdateWindow.xaml | 105 +++++++++-------- Windows/UpdateWindow.xaml.cs | 32 +++-- 21 files changed, 670 insertions(+), 337 deletions(-) create mode 100644 UpdateStatus.cs diff --git a/App.config b/App.config index 75f256e..87f432e 100644 --- a/App.config +++ b/App.config @@ -1,29 +1,33 @@ - + + - - -
- - - - - - - - - - - - - - - - - - - - - - - + + +
+ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/App.xaml b/App.xaml index fae09a3..cf307f7 100644 --- a/App.xaml +++ b/App.xaml @@ -9,8 +9,9 @@ - + - + \ No newline at end of file diff --git a/App.xaml.cs b/App.xaml.cs index e183cd2..0eb2850 100644 --- a/App.xaml.cs +++ b/App.xaml.cs @@ -1 +1,9 @@ -namespace OsuModeManager { public partial class App { } } \ No newline at end of file +#region Copyright (C) 2017-2020 Starflash Studios +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License (Version 3.0) +// as published by the Free Software Foundation. +// +// More information can be found here: https://www.gnu.org/licenses/gpl-3.0.en.html +#endregion + +namespace OsuModeManager { public partial class App { } } \ No newline at end of file diff --git a/Extensions/Extensions.cs b/Extensions/Extensions.cs index f68b809..a76c542 100644 --- a/Extensions/Extensions.cs +++ b/Extensions/Extensions.cs @@ -1,22 +1,33 @@ -using System.Collections.Generic; -using System.IO; +#region Copyright (C) 2017-2020 Starflash Studios +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License (Version 3.0) +// as published by the Free Software Foundation. +// +// More information can be found here: https://www.gnu.org/licenses/gpl-3.0.en.html +#endregion + +#region Using Directives + using System; -using System.Diagnostics; using System.Linq; -using System.Security; +using System.Collections.Generic; +using System.Diagnostics; using System.Threading; using System.Threading.Tasks; -using Ookii.Dialogs.Wpf; -namespace OsuModeManager { +#endregion + +namespace OsuModeManager.Extensions { public static class Extensions { public static bool TryGetFirst(this IEnumerable Enum, out T Result, bool Enumerate = false) { // ReSharper disable PossibleMultipleEnumeration if (Enumerate) { Enum = Enum.ToArray(); } + if (Enum != null && Enum.Any()) { Result = Enum.First(); return Result != null; } + Result = default; return false; // ReSharper restore PossibleMultipleEnumeration @@ -27,9 +38,11 @@ public static bool TryGetAt(this T[] Array, int Index, out T Result) { Result = default; return false; } + Result = Array[Index]; return Result != null; } + public static bool IsNullOrEmpty(this string String) => string.IsNullOrEmpty(String); public static int Clamp(this int Value, int Min = int.MinValue, int Max = int.MaxValue) => Value < Min ? Min : Value > Max ? Max : Value; @@ -46,5 +59,10 @@ public static Task WaitForExitAsync(this Process Process, return Tcs.Task; } + static readonly string[] _LineSplits = { + "\r\n", "\r", "\n" + }; + public static string[] GetLines(this string S, StringSplitOptions SplitOptions = StringSplitOptions.RemoveEmptyEntries) => S.Split(_LineSplits, SplitOptions); + } } diff --git a/Extensions/FileExtensions.cs b/Extensions/FileExtensions.cs index 6f72bd6..f26ec33 100644 --- a/Extensions/FileExtensions.cs +++ b/Extensions/FileExtensions.cs @@ -1,20 +1,30 @@ -using System; +#region Copyright (C) 2017-2020 Starflash Studios +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License (Version 3.0) +// as published by the Free Software Foundation. +// +// More information can be found here: https://www.gnu.org/licenses/gpl-3.0.en.html +#endregion + +#region Using Directives + +using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; -using System.Runtime.InteropServices; using System.Security; using System.Security.Cryptography; using System.Text; using Ookii.Dialogs.Wpf; - using Shell32; using Syroot.Windows.IO; -namespace OsuModeManager { - public static class FileExtensions { +#endregion +namespace OsuModeManager.Extensions { + public static class FileExtensions { + #region Assembly Reflection /// Returns the location of the ExecutingAssembly parsed as a . See also: . public static FileInfo GetExecutable() => new FileInfo(Assembly.GetExecutingAssembly().Location); @@ -297,11 +307,11 @@ public static FileInfo GetUserFile(string Title = "Pick a file", string Filter = #region FileInfo Reading public static string[] ReadAllLines(this FileInfo FileInfo) => File.ReadAllLines(FileInfo.FullName); - public static string[] ReadAllLines(this FileInfo FileInfo, System.Text.Encoding Encoding) => File.ReadAllLines(FileInfo.FullName, Encoding); + public static string[] ReadAllLines(this FileInfo FileInfo, Encoding Encoding) => File.ReadAllLines(FileInfo.FullName, Encoding); public static string ReadAllText(this FileInfo FileInfo) => File.ReadAllText(FileInfo.FullName); - public static string ReadAllText(this FileInfo FileInfo, System.Text.Encoding Encoding) => File.ReadAllText(FileInfo.FullName, Encoding); + public static string ReadAllText(this FileInfo FileInfo, Encoding Encoding) => File.ReadAllText(FileInfo.FullName, Encoding); public static byte[] ReadAllBytes(this FileInfo FileInfo) => File.ReadAllBytes(FileInfo.FullName); #endregion diff --git a/Gamemode.cs b/Gamemode.cs index 549d0bc..da8c904 100644 --- a/Gamemode.cs +++ b/Gamemode.cs @@ -1,11 +1,26 @@ -using System; +#region Copyright (C) 2017-2020 Starflash Studios +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License (Version 3.0) +// as published by the Free Software Foundation. +// +// More information can be found here: https://www.gnu.org/licenses/gpl-3.0.en.html +#endregion + +#region Using Directives + +using System; +using System.Linq; using System.Collections.Generic; using System.Diagnostics; using System.IO; -using System.Linq; using System.Threading.Tasks; +using System.Windows; using MahApps.Metro.IconPacks; using Octokit; +using OsuModeManager.Extensions; +using OsuModeManager.Windows; + +#endregion namespace OsuModeManager { public struct Gamemode : IEquatable, ICloneable { @@ -17,7 +32,7 @@ public struct Gamemode : IEquatable, ICloneable { public UpdateStatus UpdateStatus; - public System.Windows.Visibility DisplayAnyIcon => UpdateStatus == UpdateStatus.Unchecked ? System.Windows.Visibility.Hidden : System.Windows.Visibility.Visible; + public Visibility DisplayAnyIcon => UpdateStatus == UpdateStatus.Unchecked ? Visibility.Collapsed : Visibility.Visible; public PackIconMaterialKind DisplayIconType { get { @@ -148,7 +163,7 @@ public static IEnumerable ImportGamemodes(FileInfo GamemodeFile) { public override int GetHashCode() { unchecked { // ReSharper disable NonReadonlyMemberInGetHashCode - int HashCode = (GitHubUser != null ? GitHubUser.GetHashCode() : 0); + int HashCode = GitHubUser != null ? GitHubUser.GetHashCode() : 0; HashCode = (HashCode * 397) ^ (GitHubRepo != null ? GitHubRepo.GetHashCode() : 0); HashCode = (HashCode * 397) ^ (GitHubTagVersion != null ? GitHubTagVersion.GetHashCode() : 0); HashCode = (HashCode * 397) ^ (RulesetFilename != null ? RulesetFilename.GetHashCode() : 0); @@ -171,10 +186,4 @@ public bool Equals(Gamemode Other) => #endregion } - public enum UpdateStatus { - Unchecked, - UpToDate, - UpdateRequired, - FileMissing - } } diff --git a/Osu!ModeManager.csproj b/Osu!ModeManager.csproj index 1506445..153f97f 100644 --- a/Osu!ModeManager.csproj +++ b/Osu!ModeManager.csproj @@ -104,6 +104,7 @@ Designer + ReleaseWindow.xaml diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs index 8f6f83b..c6eed4c 100644 --- a/Properties/AssemblyInfo.cs +++ b/Properties/AssemblyInfo.cs @@ -1,16 +1,26 @@ -using System.Reflection; -using System.Resources; -using System.Runtime.CompilerServices; +#region Copyright (C) 2017-2020 Starflash Studios +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License (Version 3.0) +// as published by the Free Software Foundation. +// +// More information can be found here: https://www.gnu.org/licenses/gpl-3.0.en.html +#endregion + +#region Using Directives + +using System.Reflection; using System.Runtime.InteropServices; using System.Windows; +#endregion + // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("Osu!ModeManager")] -[assembly: AssemblyDescription("")] +[assembly: AssemblyDescription("A WPF-based osu!lazer gamemode update-checker utilising GitHub")] [assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] +[assembly: AssemblyCompany("Starflash Studios")] [assembly: AssemblyProduct("Osu!ModeManager")] [assembly: AssemblyCopyright("Copyright © 2020")] [assembly: AssemblyTrademark("")] @@ -51,5 +61,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.1.3.0")] +[assembly: AssemblyVersion("0.2.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/UpdateStatus.cs b/UpdateStatus.cs new file mode 100644 index 0000000..6a4e6a2 --- /dev/null +++ b/UpdateStatus.cs @@ -0,0 +1,16 @@ +#region Copyright (C) 2017-2020 Starflash Studios +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License (Version 3.0) +// as published by the Free Software Foundation. +// +// More information can be found here: https://www.gnu.org/licenses/gpl-3.0.en.html +#endregion + +namespace OsuModeManager { + public enum UpdateStatus { + Unchecked, + UpToDate, + UpdateRequired, + FileMissing + } +} \ No newline at end of file diff --git a/Windows/GamemodeEditor.xaml b/Windows/GamemodeEditor.xaml index 7dce62a..c7da5a5 100644 --- a/Windows/GamemodeEditor.xaml +++ b/Windows/GamemodeEditor.xaml @@ -1,41 +1,66 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + - - + + \ No newline at end of file diff --git a/Windows/MainWindow.xaml.cs b/Windows/MainWindow.xaml.cs index 3010763..5b521ae 100644 --- a/Windows/MainWindow.xaml.cs +++ b/Windows/MainWindow.xaml.cs @@ -1,19 +1,32 @@ -using System; +#region Copyright (C) 2017-2020 Starflash Studios +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License (Version 3.0) +// as published by the Free Software Foundation. +// +// More information can be found here: https://www.gnu.org/licenses/gpl-3.0.en.html +#endregion + +#region Using Directives + +using System; +using System.Linq; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.ComponentModel; using System.Diagnostics; using System.IO; -using System.Linq; using System.Reflection; using System.Windows; using System.Windows.Controls; +using System.Windows.Input; using System.Windows.Threading; - using Octokit; - +using OsuModeManager.Extensions; using OsuModeManager.Properties; -namespace OsuModeManager { +#endregion + +namespace OsuModeManager.Windows { public partial class MainWindow { public static DirectoryInfo LazerInstallationPath; public static GitHubClient Client; @@ -108,7 +121,7 @@ async void GamemodeListAdd_Click(object Sender, RoutedEventArgs E) { }, DispatcherPriority.Normal); } - async void GamemodeList_MouseDoubleClick(object Sender, System.Windows.Input.MouseButtonEventArgs E) { + async void GamemodeList_MouseDoubleClick(object Sender, MouseButtonEventArgs E) { int SelectedIndex = GamemodeList.SelectedIndex; if (SelectedIndex >= 0) { Gamemode NewGamemode = await GamemodeEditor.GetGamemodeEditor(Gamemodes[SelectedIndex]); @@ -164,7 +177,9 @@ async void UpdateCheckButton_Click(object Sender, RoutedEventArgs E) { case UpdateStatus.FileMissing: Debug.WriteLine(Gamemode.UpdateStatus + " for " + Gamemode + " | Newest release: " + LatestRelease.TagName); - Updates.Add(Gamemodes[G], LatestRelease); + if (!Updates.ContainsKey(Gamemodes[G])) { + Updates.Add(Gamemodes[G], LatestRelease); + } break; default: throw new ArgumentOutOfRangeException(); @@ -175,7 +190,9 @@ async void UpdateCheckButton_Click(object Sender, RoutedEventArgs E) { UpdateWindow UpdateWindow = new UpdateWindow(this, Updates); UpdateWindow.Show(); +#pragma warning disable IDE1006 // Naming Styles UpdateWindow.Closing += (_, __) => Dispatcher.Invoke(() => MainGrid.IsEnabled = true, DispatcherPriority.Normal); +#pragma warning restore IDE1006 // Naming Styles MainGrid.IsEnabled = false; SaveGamemodes(); @@ -251,7 +268,7 @@ public void SaveGamemodes() { Debug.WriteLine("Saving..."); } - void MainWindowElement_Closing(object Sender, System.ComponentModel.CancelEventArgs E) { + void MainWindowElement_Closing(object Sender, CancelEventArgs E) { if (!Gamemodes.SequenceEqual(LoadedGamemodes)) { // ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault switch (MessageBox.Show("Unsaved changes. Would you like to save now?", Title + "・Unsaved Changes", MessageBoxButton.YesNoCancel, MessageBoxImage.Warning)) { diff --git a/Windows/OAuthWindow.xaml b/Windows/OAuthWindow.xaml index bf069e9..0138884 100644 --- a/Windows/OAuthWindow.xaml +++ b/Windows/OAuthWindow.xaml @@ -1,23 +1,26 @@ - + - - + - + \ No newline at end of file diff --git a/Windows/OAuthWindow.xaml.cs b/Windows/OAuthWindow.xaml.cs index c029891..ae20562 100644 --- a/Windows/OAuthWindow.xaml.cs +++ b/Windows/OAuthWindow.xaml.cs @@ -1,10 +1,27 @@ -using System; +#region Copyright (C) 2017-2020 Starflash Studios +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License (Version 3.0) +// as published by the Free Software Foundation. +// +// More information can be found here: https://www.gnu.org/licenses/gpl-3.0.en.html +#endregion + +#region Using Directives + +using System; +using System.ComponentModel; using System.Diagnostics; using System.Text.RegularExpressions; using System.Threading.Tasks; +using System.Windows; +using System.Windows.Threading; +using CefSharp; using Octokit; +using OsuModeManager.Extensions; -namespace OsuModeManager { +#endregion + +namespace OsuModeManager.Windows { public partial class OAuthWindow { public static TaskCompletionSource OAuthCodeSource; @@ -25,6 +42,7 @@ public async Task GetOAuthToken(GitHubClient Client, string ClientID, st }; Uri OAuthLoginUrl = Client.Oauth.GetGitHubLoginUrl(Request); + Debug.WriteLine($"Logging into: {OAuthLoginUrl.AbsoluteUri}"); Browser.Address = OAuthLoginUrl.AbsoluteUri; //Browser.Navigate(OAuthLoginUrl); @@ -52,7 +70,7 @@ public static async Task GenerateTokenFromOAuth(GitHubClient Client, str //https://github.com/starflash-studios/Osu-ModeManager?code=67d7e5fa77a80370145f public const string OAuthCodeDecoder = @"(.+?)\?code=(?.+?)(?:\?.*?|$)"; - void Browser_LoadingStateChanged(object Sender, CefSharp.LoadingStateChangedEventArgs E) { + void Browser_LoadingStateChanged(object Sender, LoadingStateChangedEventArgs E) { if (OAuthCodeSource == null) { return; } string CurrentAddress = E.Browser.FocusedFrame.Url; @@ -69,11 +87,11 @@ void Browser_LoadingStateChanged(object Sender, CefSharp.LoadingStateChangedEven if (!BrowserTitle.IsNullOrEmpty()) { Title = BrowserTitle; } - }, System.Windows.Threading.DispatcherPriority.Normal); + }, DispatcherPriority.Normal); } - void Browser_Loaded(object Sender, System.Windows.RoutedEventArgs E) => Dispatcher.Invoke(() => Browser.Focus(), System.Windows.Threading.DispatcherPriority.Input); + void Browser_Loaded(object Sender, RoutedEventArgs E) => Dispatcher.Invoke(() => Browser.Focus(), DispatcherPriority.Input); - void MetroWindow_Closing(object Sender, System.ComponentModel.CancelEventArgs E) => OAuthCodeSource?.TrySetResult(null); + void MetroWindow_Closing(object Sender, CancelEventArgs E) => OAuthCodeSource?.TrySetResult(null); } } diff --git a/Windows/ReleaseWindow.xaml b/Windows/ReleaseWindow.xaml index 7ba922b..37a09e1 100644 --- a/Windows/ReleaseWindow.xaml +++ b/Windows/ReleaseWindow.xaml @@ -1,22 +1,22 @@ - + - @@ -28,7 +28,7 @@ --> - + - + \ No newline at end of file diff --git a/Windows/ReleaseWindow.xaml.cs b/Windows/ReleaseWindow.xaml.cs index 578ef1d..852b6b7 100644 --- a/Windows/ReleaseWindow.xaml.cs +++ b/Windows/ReleaseWindow.xaml.cs @@ -1,7 +1,19 @@ -using System; +#region Copyright (C) 2017-2020 Starflash Studios +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License (Version 3.0) +// as published by the Free Software Foundation. +// +// More information can be found here: https://www.gnu.org/licenses/gpl-3.0.en.html +#endregion + +#region Using Directives + +using System; using Octokit; -namespace OsuModeManager { +#endregion + +namespace OsuModeManager.Windows { public partial class ReleaseWindow { public ReleaseWindow() { InitializeComponent(); diff --git a/Windows/SelfUpdateWindow.xaml b/Windows/SelfUpdateWindow.xaml index d9c536f..4d9becb 100644 --- a/Windows/SelfUpdateWindow.xaml +++ b/Windows/SelfUpdateWindow.xaml @@ -1,28 +1,31 @@ - + - + - - + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Windows/UpdateWindow.xaml.cs b/Windows/UpdateWindow.xaml.cs index 1eb4e99..1ecb6b6 100644 --- a/Windows/UpdateWindow.xaml.cs +++ b/Windows/UpdateWindow.xaml.cs @@ -1,17 +1,31 @@ -using System; +#region Copyright (C) 2017-2020 Starflash Studios +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License (Version 3.0) +// as published by the Free Software Foundation. +// +// More information can be found here: https://www.gnu.org/licenses/gpl-3.0.en.html +#endregion + +#region Using Directives + +using System; +using System.Linq; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.IO; -using System.Linq; using System.Net; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; - +using System.Windows.Input; +using System.Windows.Threading; using Octokit; +using OsuModeManager.Extensions; + +#endregion -namespace OsuModeManager { +namespace OsuModeManager.Windows { public partial class UpdateWindow { public MainWindow MainWindow; @@ -55,14 +69,14 @@ async void UpdateSingleButton_Click(object Sender, RoutedEventArgs E) { CloseButton.Visibility = Visibility.Visible; } MainGrid.IsEnabled = true; - }, System.Windows.Threading.DispatcherPriority.Normal); + }, DispatcherPriority.Normal); } async void UpdateAllButton_Click(object Sender, RoutedEventArgs E) { MainGrid.IsEnabled = false; for (int G = GamemodeReleases.Count - 1; G >= 0; G--) { await Update(G); - Dispatcher.Invoke(UpdateList.GetBindingExpression(ItemsControl.ItemsSourceProperty).UpdateTarget, System.Windows.Threading.DispatcherPriority.Normal); + Dispatcher.Invoke(UpdateList.GetBindingExpression(ItemsControl.ItemsSourceProperty).UpdateTarget, DispatcherPriority.Normal); } if (FilesRecycled) { @@ -75,7 +89,7 @@ async void UpdateAllButton_Click(object Sender, RoutedEventArgs E) { CloseButton.Visibility = Visibility.Visible; } MainGrid.IsEnabled = true; - }, System.Windows.Threading.DispatcherPriority.Normal); + }, DispatcherPriority.Normal); } public async Task Update(int SelectedIndex) { @@ -111,7 +125,7 @@ public async Task Update(DirectoryInfo Destination, Gamemode Gamemode, Rel if (Destination == null || !Destination.Exists) { Dispatcher.Invoke(() => { MessageBox.Show("Selected osu!lazer installation path is invalid.", Title, MessageBoxButton.OK, MessageBoxImage.Error); - }, System.Windows.Threading.DispatcherPriority.Normal); + }, DispatcherPriority.Normal); MainWindow.UpdateLazerInstallationPath(false); return false; } @@ -159,7 +173,7 @@ void ConfirmButton_Click(object Sender, RoutedEventArgs E) { void CloseButton_Click(object Sender, RoutedEventArgs E) => Close(); - void UpdateList_MouseDoubleClick(object Sender, System.Windows.Input.MouseButtonEventArgs E) { + void UpdateList_MouseDoubleClick(object Sender, MouseButtonEventArgs E) { int SelectedIndex = UpdateList.SelectedIndex; if (SelectedIndex >= 0) { Release Release = GamemodeReleases[DisplayGamemodes[SelectedIndex]];