diff --git a/AvaloniaCommon/Assets/error.ico b/AvaloniaCommon/Assets/error.ico deleted file mode 100644 index 529371fe..00000000 Binary files a/AvaloniaCommon/Assets/error.ico and /dev/null differ diff --git a/AvaloniaCommon/Assets/information.ico b/AvaloniaCommon/Assets/information.ico deleted file mode 100644 index 3a7f9bdd..00000000 Binary files a/AvaloniaCommon/Assets/information.ico and /dev/null differ diff --git a/AvaloniaCommon/Assets/question.ico b/AvaloniaCommon/Assets/question.ico deleted file mode 100644 index db04d421..00000000 Binary files a/AvaloniaCommon/Assets/question.ico and /dev/null differ diff --git a/AvaloniaCommon/Assets/warning.ico b/AvaloniaCommon/Assets/warning.ico deleted file mode 100644 index d4bd0f53..00000000 Binary files a/AvaloniaCommon/Assets/warning.ico and /dev/null differ diff --git a/AvaloniaCommon/AvaloniaCommon.csproj b/AvaloniaCommon/AvaloniaCommon.csproj deleted file mode 100644 index d66957be..00000000 --- a/AvaloniaCommon/AvaloniaCommon.csproj +++ /dev/null @@ -1,19 +0,0 @@ - - - - $(CommonNetVersion) - enable - enable - true - - - - - - - - - - - - diff --git a/AvaloniaCommon/Enums/MessageBoxButton.cs b/AvaloniaCommon/Enums/MessageBoxButton.cs deleted file mode 100644 index 9dbd3571..00000000 --- a/AvaloniaCommon/Enums/MessageBoxButton.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace AvaloniaCommon.Enums; - -[Flags] -public enum MessageBoxButton -{ - No = 1, - Yes = 2, - Ok = 4, - Cancel = 8 -} \ No newline at end of file diff --git a/AvaloniaCommon/Enums/MessageBoxIcon.cs b/AvaloniaCommon/Enums/MessageBoxIcon.cs deleted file mode 100644 index 7d35f0fc..00000000 --- a/AvaloniaCommon/Enums/MessageBoxIcon.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace AvaloniaCommon.Enums; - -[Flags] -public enum MessageBoxIcon -{ - QUESTION = 1, - INFORMATION = 2, - WARNING = 4, - ERROR = 8 -} \ No newline at end of file diff --git a/AvaloniaCommon/MessageBox.cs b/AvaloniaCommon/MessageBox.cs deleted file mode 100644 index f88d7b51..00000000 --- a/AvaloniaCommon/MessageBox.cs +++ /dev/null @@ -1,91 +0,0 @@ -namespace AvaloniaCommon; - -using Avalonia.Controls; -using Avalonia.Threading; -using AvaloniaCommon.Enums; -using AvaloniaCommon.ViewModels; - -public static class MessageBox -{ - public static MessageBoxButton? Show(string title, string message) - { - return Show(title, "", message); - } - - public static MessageBoxButton? Error(string title, string message) - { - return Error(title, "", message); - } - - public static MessageBoxButton? Error(Exception e) - { - return Error(string.IsNullOrEmpty(e.Message) ? "Unknown error" : e.Message, e.Message, e.ToString()); - } - public static MessageBoxButton? QuestionYesNo(string title, string header, string message) - { - return Show(title, header, message, MessageBoxIcon.QUESTION, MessageBoxButton.No | MessageBoxButton.Yes); - } - public static MessageBoxButton? QuestionYesNoCancel(string title, string header, string message) - { - return Show(title, header, message, MessageBoxIcon.QUESTION, MessageBoxButton.No | MessageBoxButton.Yes | MessageBoxButton.Cancel); - } - public static MessageBoxButton? Info(string title, string header, string message) - { - return Show(title, header, message, MessageBoxIcon.INFORMATION); - } - public static MessageBoxButton? Warning(string title, string header, string message) - { - return Show(title, header, message, MessageBoxIcon.WARNING); - } - public static MessageBoxButton? Error(string title, string header, string message) - { - return Show(title, header, message, MessageBoxIcon.ERROR); - } - - public static MessageBoxButton? Show(string title, string header, string message) - { - return Show(title, header, message, MessageBoxIcon.INFORMATION); - } - - public static MessageBoxButton? Show(string title, string header, string message, MessageBoxIcon icon = MessageBoxIcon.INFORMATION, MessageBoxButton buttons = MessageBoxButton.Ok) - { - if (!Dispatcher.UIThread.CheckAccess()) - { - return Dispatcher.UIThread.Invoke(() => ShowInternal(title, header, message, icon, buttons)); - } - else - { - return ShowInternal(title, header, message, icon, buttons); - } - } - - internal static MessageBoxButton? ShowInternal(string title, string header, string message, MessageBoxIcon icon, MessageBoxButton buttons) - { - var messageBoxViewModel = new MessageBoxViewModel(icon, buttons) - { - Title = title, - Header = header, - Content = message - }; - - var messageBox = new Views.MessageBox(); - messageBoxViewModel.SetMessageBox(messageBox); - messageBox.DataContext = messageBoxViewModel; - - using (var source = new CancellationTokenSource()) - { - var tcs = new TaskCompletionSource(); - messageBox.Closing += (object? sender, WindowClosingEventArgs args) => - { - tcs.TrySetResult(messageBoxViewModel.ButtonClicked); - args.Cancel = false; - }; - - messageBox.Show(); - - tcs.Task.ContinueWith(t => source.Cancel(), TaskScheduler.FromCurrentSynchronizationContext()); - Dispatcher.UIThread.MainLoop(source.Token); - return tcs.Task.Result; - } - } -} diff --git a/AvaloniaCommon/Theme.cs b/AvaloniaCommon/Theme.cs deleted file mode 100644 index 8583c3f4..00000000 --- a/AvaloniaCommon/Theme.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using Avalonia; -using Avalonia.Media; -using Avalonia.Styling; - -namespace AvaloniaCommon; - -public class Theme -{ - public IBrush AccentButtonBackground - { - get - { - return (IBrush)GetResource("AccentButtonBackground"); - } - } - - public IBrush AccentButtonForeground - { - get - { - return (IBrush)GetResource("AccentButtonForeground"); - } - } - - public IBrush ButtonBackground - { - get - { - return (IBrush)GetResource("ButtonBackground"); - } - } - - public IBrush ButtonForeground - { - get - { - return (IBrush)GetResource("ButtonForeground"); - } - } - - private object GetResource(string key) - { - app.TryGetResource(key, ThemeVariant.Default, out object? val); - ThrowIfNull(val); - return val; - } - - private void ThrowIfNull([NotNull] object? val) - { - if (val == null) - { - throw new Exception("No styles where there should be"); - } - } - - private Application app; - public Theme(Application app) - { - this.app = app; - } -} \ No newline at end of file diff --git a/AvaloniaCommon/ViewModelBase.cs b/AvaloniaCommon/ViewModelBase.cs deleted file mode 100644 index 31430754..00000000 --- a/AvaloniaCommon/ViewModelBase.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; -using System.Diagnostics; -using CommunityToolkit.Mvvm.ComponentModel; - -namespace AvaloniaCommon; - -public partial class ViewModelBase : ObservableObject -{ - -} diff --git a/AvaloniaCommon/ViewModels/MessageBoxViewModel.cs b/AvaloniaCommon/ViewModels/MessageBoxViewModel.cs deleted file mode 100644 index 356eb700..00000000 --- a/AvaloniaCommon/ViewModels/MessageBoxViewModel.cs +++ /dev/null @@ -1,112 +0,0 @@ -using System; -using Avalonia.Controls; -using Avalonia.Media.Imaging; -using Avalonia.Platform; -using Avalonia.Threading; -using AvaloniaCommon.Enums; -using CommunityToolkit.Mvvm.ComponentModel; - -namespace AvaloniaCommon.ViewModels; - -public partial class MessageBoxViewModel : ViewModelBase -{ - [ObservableProperty] - private string title = ""; - - [ObservableProperty] - [NotifyPropertyChangedFor("HasHeader")] - private string header = ""; - public bool HasHeader => !string.IsNullOrEmpty(this.Header); - - [ObservableProperty] - private string content = ""; - - [ObservableProperty] - private string iconPath; - - [ObservableProperty] - private Bitmap icon; - - [ObservableProperty] - private WindowIcon windowIcon; - - [NotifyPropertyChangedFor("IsOkShowed")] - [NotifyPropertyChangedFor("IsYesShowed")] - [NotifyPropertyChangedFor("IsNoShowed")] - [NotifyPropertyChangedFor("IsCancelShowed")] - - [ObservableProperty] - private MessageBoxButton enabledButtons; - public MessageBoxButton? ButtonClicked { get; private set; } - public bool IsOkShowed => EnabledButtons.HasFlag(MessageBoxButton.Ok); - public bool IsYesShowed => EnabledButtons.HasFlag(MessageBoxButton.Yes); - public bool IsNoShowed => EnabledButtons.HasFlag(MessageBoxButton.No); - public bool IsCancelShowed => EnabledButtons.HasFlag(MessageBoxButton.Cancel); - public Action? Copy { get; set; } - public Action? EnterPressed { get; set; } - public Action? EscPressed { get; set; } - private AvaloniaCommon.Views.MessageBox? messageBox; - public MessageBoxViewModel(MessageBoxIcon icon, MessageBoxButton enabledButtons) - { - - this.enabledButtons = enabledButtons; - this.EnterPressed = PressDefaultIfPossible; - this.IconPath = $"avares://AvaloniaCommon/Assets/{icon.ToString().ToLowerInvariant()}.ico"; - this.Icon = new Bitmap(AssetLoader.Open(new Uri(this.iconPath))); - this.WindowIcon = new WindowIcon(this.Icon); - } - - // Clipboard isn't accessible from App, instead it's available from every Control, so do this hack which is totally against mvvm principles - public void SetMessageBox(AvaloniaCommon.Views.MessageBox messageBox) - { - this.messageBox = messageBox; - this.Copy = messageBox.Copy; - this.EscPressed = messageBox.Close; - } - - public void PressDefaultIfPossible() - { - // If there's only one button enabled, then click it - switch (EnabledButtons) - { - case MessageBoxButton.No: - NoClicked(); - break; - case MessageBoxButton.Yes: - YesClicked(); - break; - case MessageBoxButton.Cancel: - CancelClicked(); - break; - case MessageBoxButton.Ok: - OkClicked(); - break; - } - // If there's multiple, try to cancel, never take a yes action automatically - if (EnabledButtons.HasFlag(MessageBoxButton.Cancel)) - { - CancelClicked(); - } - } - public void OkClicked() - { - ButtonClicked = MessageBoxButton.Ok; - messageBox?.QueueClose(); - } - public void YesClicked() - { - ButtonClicked = MessageBoxButton.Yes; - messageBox?.QueueClose(); - } - public void NoClicked() - { - ButtonClicked = MessageBoxButton.No; - messageBox?.QueueClose(); - } - public void CancelClicked() - { - ButtonClicked = MessageBoxButton.Cancel; - messageBox?.QueueClose(); - } - -} \ No newline at end of file diff --git a/AvaloniaCommon/Views/MessageBox.axaml b/AvaloniaCommon/Views/MessageBox.axaml deleted file mode 100644 index 6e2eefb1..00000000 --- a/AvaloniaCommon/Views/MessageBox.axaml +++ /dev/null @@ -1,110 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/GameOverlayUI/Views/CustomWindowView.axaml.cs b/GameOverlayUI/Views/CustomWindowView.axaml.cs deleted file mode 100644 index 5532e098..00000000 --- a/GameOverlayUI/Views/CustomWindowView.axaml.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Avalonia.Controls; - -namespace GameOverlayUI.Views; - -public partial class CustomWindowView : UserControl -{ - public CustomWindowView() - { - InitializeComponent(); - } -} \ No newline at end of file diff --git a/GameOverlayUI/Views/MainView.axaml b/GameOverlayUI/Views/MainView.axaml deleted file mode 100644 index e1a78e21..00000000 --- a/GameOverlayUI/Views/MainView.axaml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - OSC Overlay Test - - - - - - - - - - diff --git a/GameOverlayUI/Views/MainView.axaml.cs b/GameOverlayUI/Views/MainView.axaml.cs deleted file mode 100644 index 09d8c369..00000000 --- a/GameOverlayUI/Views/MainView.axaml.cs +++ /dev/null @@ -1,111 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using Avalonia; -using Avalonia.Controls; -using Avalonia.VisualTree; -using GameOverlayUI.ViewModels; - -namespace GameOverlayUI.Views; - -public partial class MainView : Window { - private MainViewViewModel vm => (DataContext as MainViewViewModel)!; - public MainView() { - InitializeComponent(); - } - - [MemberNotNull(nameof(draggingWindowViewModel))] - private CustomWindowView? draggingWindow { get; set; } - - // The corner point where the dragging was initiated - private Point dragPoint; - private CustomWindowViewModel? draggingWindowViewModel => draggingWindow?.DataContext as CustomWindowViewModel; - - private void OnPointerPressed(object? sender, Avalonia.Input.PointerPressedEventArgs e) { - if (!e.GetCurrentPoint(null).Properties.IsLeftButtonPressed) { - return; - } - - var pos = e.GetPosition(Desktop); - Visual? vis = Desktop.GetVisualAt(pos); - Console.WriteLine("PRESSED at " + pos); - Console.WriteLine("Element is " + vis); - CustomWindowView? window = null; - bool isDrag = false; - while (window == null && vis != null) - { - Console.WriteLine("DC: " + vis.DataContext?.GetType()); - if (vis.DataContext is CustomWindowViewModel) { - isDrag = vis.Classes.Contains("draggable"); - window = vis.FindAncestorOfType(); - break; - } - - vis = vis?.Parent as Visual; - } - - var vm = window?.DataContext as CustomWindowViewModel; - - Console.WriteLine("Window is " + vm?.Title); - - if (window != null) { - ChangeFocusedWindow(vm); - } - - if (isDrag) { - draggingWindow = window; - - // This stops the window "teleporting" when it's being moved, and allows it to move wherever from a draggable area - dragPoint = e.GetPosition(Desktop) - new Point(draggingWindowViewModel.X, draggingWindowViewModel.Y); - } - } - - private void OnPointerMoved(object? sender, Avalonia.Input.PointerEventArgs e) { - var pos = e.GetPosition(Desktop); - if (draggingWindow != null) { - Console.WriteLine("MOVED to " + pos); - Console.WriteLine("W: " + draggingWindow.Bounds.Width); - Console.WriteLine("H: " + draggingWindow.Bounds.Height); - - Console.WriteLine("MW: " + Desktop.Bounds.Width); - Console.WriteLine("MH: " + Desktop.Bounds.Height); - - Console.WriteLine("DPX: " + dragPoint.X + ", DPY: " + dragPoint.Y); - - // This function does some advanced math to: - // 1. Ensure the window doesn't clip out of bounds at all - // 2. Move the window to the correct location upon dragging - // 3. Some other things I can't decipher from this code - // Don't ask me about this math, I wrote it half asleep at 3:30am, but work it does! Improve if needed. - double targetX = pos.X + draggingWindow.Bounds.Width - dragPoint.X; - double targetY = pos.Y + draggingWindow.Bounds.Height - dragPoint.Y; - - double X = Math.Clamp(targetX, 0.0 + draggingWindow.Bounds.Width, Desktop.Bounds.Width) - draggingWindow.Bounds.Width; - double Y = Math.Clamp(targetY, 0.0 + draggingWindow.Bounds.Height, Desktop.Bounds.Height) - draggingWindow.Bounds.Height; - draggingWindowViewModel.X = X; - draggingWindowViewModel.Y = Y; - - Console.WriteLine("CX: " + draggingWindowViewModel.X); - Console.WriteLine("CY: " + draggingWindowViewModel.Y); - } - } - - private CustomWindowViewModel? focusedWindow; - private void ChangeFocusedWindow(CustomWindowViewModel? newWindow) { - if (newWindow == focusedWindow) { - return; - } - - if (newWindow != null) { - newWindow.GotFocus(); - focusedWindow?.LostFocus(); - - focusedWindow = newWindow; - } - } - - private void OnPointerReleased(object? sender, Avalonia.Input.PointerReleasedEventArgs e) { - var pos = e.GetPosition(Desktop); - Console.WriteLine("RELEASED at " + pos); - draggingWindow = null; - dragPoint = new Point(0, 0); - } -} \ No newline at end of file diff --git a/GameOverlayUI/nuget.config b/GameOverlayUI/nuget.config deleted file mode 100644 index 42c6aa46..00000000 --- a/GameOverlayUI/nuget.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/Installer/Assets/opensteam-logo.ico b/Installer/Assets/opensteam-logo.ico deleted file mode 100644 index 4b4c1546..00000000 Binary files a/Installer/Assets/opensteam-logo.ico and /dev/null differ diff --git a/Installer/AvaloniaApp.axaml b/Installer/AvaloniaApp.axaml deleted file mode 100644 index a8ffd692..00000000 --- a/Installer/AvaloniaApp.axaml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - - M18.25,3 C18.6296958,3 18.943491,3.28215388 18.9931534,3.64822944 L19,3.75 L19,20.25 C19,20.6642136 18.6642136,21 18.25,21 C17.8703042,21 17.556509,20.7178461 17.5068466,20.3517706 L17.5,20.25 L17.5,3.75 C17.5,3.33578644 17.8357864,3 18.25,3 Z M5.21966991,3.21966991 C5.48593648,2.95340335 5.90260016,2.9291973 6.19621165,3.14705176 L6.28033009,3.21966991 L14.5303301,11.4696699 C14.7965966,11.7359365 14.8208027,12.1526002 14.6029482,12.4462117 L14.5303301,12.5303301 L6.28033009,20.7803301 C5.98743687,21.0732233 5.51256313,21.0732233 5.21966991,20.7803301 C4.95340335,20.5140635 4.9291973,20.0973998 5.14705176,19.8037883 L5.21966991,19.7196699 L12.9393398,12 L5.21966991,4.28033009 C4.9267767,3.98743687 4.9267767,3.51256313 5.21966991,3.21966991 Z - M5.75,3 C5.37030423,3 5.05650904,3.28215388 5.00684662,3.64822944 L5,3.75 L5,20.25 C5,20.6642136 5.33578644,21 5.75,21 C6.12969577,21 6.44349096,20.7178461 6.49315338,20.3517706 L6.5,20.25 L6.5,3.75 C6.5,3.33578644 6.16421356,3 5.75,3 Z M18.7803301,3.21966991 C18.5140635,2.95340335 18.0973998,2.9291973 17.8037883,3.14705176 L17.7196699,3.21966991 L9.46966991,11.4696699 C9.20340335,11.7359365 9.1791973,12.1526002 9.39705176,12.4462117 L9.46966991,12.5303301 L17.7196699,20.7803301 C18.0125631,21.0732233 18.4874369,21.0732233 18.7803301,20.7803301 C19.0465966,20.5140635 19.0708027,20.0973998 18.8529482,19.8037883 L18.7803301,19.7196699 L11.0606602,12 L18.7803301,4.28033009 C19.0732233,3.98743687 19.0732233,3.51256313 18.7803301,3.21966991 Z - M12,2 C17.5228,2 22,6.47715 22,12 C22,17.5228 17.5228,22 12,22 C6.47715,22 2,17.5228 2,12 C2,6.47715 6.47715,2 12,2 Z M12,3.5 C7.30558,3.5 3.5,7.30558 3.5,12 C3.5,16.6944 7.30558,20.5 12,20.5 C16.6944,20.5 20.5,16.6944 20.5,12 C20.5,7.30558 16.6944,3.5 12,3.5 Z M16.75,12 C17.1296833,12 17.4434889,12.2821653 17.4931531,12.6482323 L17.5,12.75 L17.5,15.75 C17.5,16.1642 17.1642,16.5 16.75,16.5 C16.3703167,16.5 16.0565111,16.2178347 16.0068469,15.8517677 L16,15.75 L16,15 C15.0881,16.2143 13.6362,17 11.9999,17 C10.4748,17 9.09587,16.316 8.17857,15.237 C7.91028,14.9214 7.94862,14.4481 8.2642,14.1798 C8.57979,13.9115 9.05311,13.9499 9.3214,14.2655 C9.96322,15.0204 10.9293,15.5 11.9999,15.5 C13.32553,15.5 14.4803167,14.7625672 15.0742404,13.6746351 L15.1633,13.5 L14,13.5 C13.5858,13.5 13.25,13.1642 13.25,12.75 C13.25,12.3703167 13.5321653,12.0565111 13.8982323,12.0068469 L14,12 L16.75,12 Z M11.9999,7 C13.5368,7 14.9041,7.66036 15.8268,8.77062 C16.0915,9.08918 16.0479,9.56205 15.7294,9.8268 C15.4108,10.0916 14.9379,10.0479 14.6732,9.72938 C14.0368,8.96361 13.093,8.5 11.9999,8.5 C10.5754318,8.5 9.34895806,9.35140335 8.80281957,10.5730172 L8.72948,10.75 L10,10.75 C10.4142,10.75 10.75,11.0858 10.75,11.5 C10.75,11.8796833 10.4678347,12.1934889 10.1017677,12.2431531 L10,12.25 L7.25,12.25 C6.8703075,12.25 6.55650958,11.9678347 6.50684668,11.6017677 L6.5,11.5 L6.5,8.25 C6.5,7.83579 6.83579,7.5 7.25,7.5 C7.6296925,7.5 7.94349042,7.78215688 7.99315332,8.14823019 L8,8.25 L8,8.99955 C8.9121,7.78531 10.364,7 11.9999,7 Z - M10.5001 7.7514C10.5001 4.57577 13.0745 2.0014 16.2501 2.0014C17.196 2.0014 18.0906 2.23039 18.8794 2.6366C19.0924 2.74625 19.2401 2.95101 19.2771 3.18765C19.314 3.42429 19.2358 3.66435 19.0664 3.83371L16.3006 6.59949L17.3613 7.66015L20.1398 4.8816C20.3081 4.71337 20.5461 4.63494 20.7814 4.67023C21.0167 4.70551 21.2213 4.85033 21.3327 5.06051C21.759 5.86417 22.0001 6.78074 22.0001 7.7514C22.0001 10.927 19.4258 13.5014 16.2501 13.5014C15.7895 13.5014 15.3408 13.4471 14.9104 13.3443L7.54552 20.9632C6.42372 22.1237 4.59212 22.2096 3.36665 21.1592C2.03293 20.016 1.93771 17.9855 3.15859 16.7225L10.6339 8.98943C10.5462 8.59014 10.5001 8.17579 10.5001 7.7514ZM16.2501 3.5014C13.9029 3.5014 12.0001 5.40419 12.0001 7.7514C12.0001 8.18337 12.0643 8.59897 12.1832 8.98991C12.2624 9.25049 12.1942 9.53355 12.0049 9.72937L4.23708 17.765C3.61648 18.407 3.66488 19.4392 4.34283 20.0203C4.96577 20.5542 5.8968 20.5106 6.46704 19.9207L14.1435 11.9795C14.3435 11.7726 14.6443 11.6984 14.9176 11.7885C15.3358 11.9265 15.7834 12.0014 16.2501 12.0014C18.5973 12.0014 20.5001 10.0986 20.5001 7.7514C20.5001 7.40926 20.4598 7.07703 20.3838 6.75896L17.8916 9.25114C17.5987 9.54403 17.1238 9.54403 16.831 9.25114L14.7096 7.12982C14.4167 6.83692 14.4167 6.36205 14.7096 6.06916L17.1763 3.60246C16.8785 3.53632 16.5686 3.5014 16.2501 3.5014Z - M24,7.25 C27.1017853,7.25 29.629937,9.70601719 29.7458479,12.7794443 L29.75,13 L37,13 C37.6903559,13 38.25,13.5596441 38.25,14.25 C38.25,14.8972087 37.7581253,15.4295339 37.1278052,15.4935464 L37,15.5 L35.909,15.5 L34.2058308,38.0698451 C34.0385226,40.2866784 32.1910211,42 29.9678833,42 L18.0321167,42 C15.8089789,42 13.9614774,40.2866784 13.7941692,38.0698451 L12.09,15.5 L11,15.5 C10.3527913,15.5 9.8204661,15.0081253 9.75645361,14.3778052 L9.75,14.25 C9.75,13.6027913 10.2418747,13.0704661 10.8721948,13.0064536 L11,13 L18.25,13 C18.25,9.82436269 20.8243627,7.25 24,7.25 Z M33.4021054,15.5 L14.5978946,15.5 L16.2870795,37.8817009 C16.3559711,38.7945146 17.116707,39.5 18.0321167,39.5 L29.9678833,39.5 C30.883293,39.5 31.6440289,38.7945146 31.7129205,37.8817009 L33.4021054,15.5 Z M27.25,20.75 C27.8972087,20.75 28.4295339,21.2418747 28.4935464,21.8721948 L28.5,22 L28.5,33 C28.5,33.6903559 27.9403559,34.25 27.25,34.25 C26.6027913,34.25 26.0704661,33.7581253 26.0064536,33.1278052 L26,33 L26,22 C26,21.3096441 26.5596441,20.75 27.25,20.75 Z M20.75,20.75 C21.3972087,20.75 21.9295339,21.2418747 21.9935464,21.8721948 L22,22 L22,33 C22,33.6903559 21.4403559,34.25 20.75,34.25 C20.1027913,34.25 19.5704661,33.7581253 19.5064536,33.1278052 L19.5,33 L19.5,22 C19.5,21.3096441 20.0596441,20.75 20.75,20.75 Z M24,9.75 C22.2669685,9.75 20.8507541,11.1064548 20.7551448,12.8155761 L20.75,13 L27.25,13 C27.25,11.2050746 25.7949254,9.75 24,9.75 Z - - \ No newline at end of file diff --git a/Installer/AvaloniaApp.axaml.cs b/Installer/AvaloniaApp.axaml.cs deleted file mode 100644 index 965db194..00000000 --- a/Installer/AvaloniaApp.axaml.cs +++ /dev/null @@ -1,66 +0,0 @@ -using Avalonia; -using Avalonia.Controls.ApplicationLifetimes; -using Avalonia.Input.Platform; -using Avalonia.Markup.Xaml; -using Installer.Translation; -using Installer.ViewModels; -using Installer.Views; -using System.Threading.Tasks; -using System; -using Avalonia.Controls; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using Avalonia.Input; -using Avalonia.Styling; -using System.Text; -using Avalonia.Threading; - -namespace Installer; - -public class AvaloniaApp : Application -{ - public static TranslationManager TranslationManager { get; } = new(); - public new static AvaloniaApp? Current; - public new IClassicDesktopStyleApplicationLifetime ApplicationLifetime => (base.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime)!; - public static bool DebugEnabled = false; - public static bool InLinuxDevelopment = false; - public Window? MainWindow => ApplicationLifetime.MainWindow; - - public override void Initialize() - { - AvaloniaXamlLoader.Load(this); - } - - public override void OnFrameworkInitializationCompleted() - { - TranslationManager.LoadCurrentSystemTranslation(); - base.OnFrameworkInitializationCompleted(); - OpenMainWindow(); - } - - public void OpenMainWindow() - { - if (ApplicationLifetime.MainWindow != null) - { - if (ApplicationLifetime.MainWindow.IsActive) - { - // Not closed but maybe hidden, maybe shown in background - ApplicationLifetime.MainWindow.Show(); - ApplicationLifetime.MainWindow.Activate(); - return; - } - } else { - var wnd = new MainWindow(); - wnd.DataContext = new MainWindowViewModel(wnd); - ApplicationLifetime.MainWindow = wnd; - ApplicationLifetime.MainWindow.Show(); - } - } - - public AvaloniaApp() - { - Current = this; - Name = "Installer"; - DataContext = new AvaloniaAppViewModel(); - } -} diff --git a/Installer/Controls/Translatable.cs b/Installer/Controls/Translatable.cs deleted file mode 100644 index f7965218..00000000 --- a/Installer/Controls/Translatable.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Windows.Input; -using Avalonia; -using Avalonia.Data; -using Avalonia.Input; -using Avalonia.Interactivity; - -namespace Installer.Controls; - -public class Translatable : AvaloniaObject -{ - public static readonly AttachedProperty TranslationKeyProperty = - AvaloniaProperty.RegisterAttached("TranslationKey", "", false, Avalonia.Data.BindingMode.OneWay); - - public static readonly AttachedProperty DefaultTextProperty = - AvaloniaProperty.RegisterAttached("DefaultText", "", false, Avalonia.Data.BindingMode.OneWay); - - public static void SetTranslationKey(AvaloniaObject element, string val) - { - element.SetValue(TranslationKeyProperty, val); - } - - public static string GetTranslationKey(AvaloniaObject element) - { - return element.GetValue(TranslationKeyProperty); - } - - public static void SetDefaultText(AvaloniaObject element, string val) - { - element.SetValue(DefaultTextProperty, val); - } - - public static string GetDefaultText(AvaloniaObject element) - { - return element.GetValue(DefaultTextProperty); - } -} \ No newline at end of file diff --git a/Installer/Core/InstallationManager.cs b/Installer/Core/InstallationManager.cs deleted file mode 100644 index 92f034b8..00000000 --- a/Installer/Core/InstallationManager.cs +++ /dev/null @@ -1,215 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Diagnostics; -using System.IO; -using System.IO.Compression; -using System.Linq; -using System.Net.Http; -using System.Security.AccessControl; -using System.Security.Principal; -using System.ServiceProcess; -using System.Threading.Tasks; -using Installer.Extensions; -using Installer.Translation; -using Microsoft.Win32; - -namespace Installer.Core; - -public static class InstallationManager { - public const string CommonFilesPath = "C:\\Program Files (x86)\\Common Files\\Steam"; - public static string InstallDir { - get { - if (AvaloniaApp.InLinuxDevelopment) { - return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "OpenSteamClient_Installer_TargetDir_Dev"); - } - - var val = (string?)Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\OpenSteamClient", "InstallPath", ""); - if (string.IsNullOrEmpty(val)) { - return ""; - } - - return val; - } - - set { - if (AvaloniaApp.InLinuxDevelopment) { - // Don't save it anywhere on linux - return; - } - - Registry.SetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\OpenSteamClient", "InstallPath", value); - } - } - - public static void CreateRegKeys(string installPath) { - if (AvaloniaApp.InLinuxDevelopment) { - return; - } - - var node = Registry.LocalMachine.OpenSubKey("SOFTWARE")!; - var steamSecurity = new RegistrySecurity(); - RegistryAccessRule rule = new("Users", - RegistryRights.ReadKey | RegistryRights.SetValue | RegistryRights.QueryValues | RegistryRights.ReadPermissions - | RegistryRights.Delete | RegistryRights.FullControl | RegistryRights.CreateSubKey | RegistryRights.EnumerateSubKeys | RegistryRights.Notify | RegistryRights.CreateLink | RegistryRights.WriteKey | RegistryRights.ExecuteKey, - InheritanceFlags.ContainerInherit, - PropagationFlags.None, - AccessControlType.Allow - ); - - steamSecurity.AddAccessRule(rule); - var opensteamnode = node.CreateOrOpen("OpenSteamClient", RegistryKeyPermissionCheck.Default, RegistryOptions.None, out bool _, steamSecurity); - var valvenode = node.OpenSubKey("WOW6432Node")!.CreateOrOpen("Valve", RegistryKeyPermissionCheck.Default, RegistryOptions.None, out bool _); - CreateSteamRegKeys(valvenode, steamSecurity, "Steam", "SteamService", ""); - CreateSteamRegKeys(opensteamnode, steamSecurity, "thiskey", serviceSubkey: "", installPath); - } - - private static void CreateSteamRegKeys(RegistryKey key, RegistrySecurity steamSecurity, string clientSubkey, string serviceSubkey, string installPath) { - if (!string.IsNullOrEmpty(serviceSubkey)) { - var serviceKey = key.CreateOrOpen(serviceSubkey, RegistryKeyPermissionCheck.Default, RegistryOptions.None, out bool createdService); - if (createdService) { - serviceKey.SetValue("installpath_default", installPath, RegistryValueKind.String); - } - } - - if (!string.IsNullOrEmpty(clientSubkey)) { - bool createdClient = true; - RegistryKey? clientKey; - if (clientSubkey == "thiskey") { - clientKey = key; - } else { - clientKey = key.CreateOrOpen(clientSubkey, RegistryKeyPermissionCheck.Default, RegistryOptions.None, out createdClient, steamSecurity); - } - - if (createdClient) { - clientKey.SetValue("InstallPath", installPath, RegistryValueKind.String); - clientKey.SetValue("language", ELanguageConversion.APINameFromELanguage(AvaloniaApp.TranslationManager.CurrentTranslation.Language), RegistryValueKind.String); - // This is the important one, this allows the service to start up - clientKey.SetValue("SteamPID", 0, RegistryValueKind.DWord); - clientKey.SetValue("TempAppCmdLine", "", RegistryValueKind.String); - clientKey.SetValue("ReLaunchCmdLine", "", RegistryValueKind.String); - clientKey.SetValue("ClientLauncherType", 0, RegistryValueKind.DWord); - clientKey.SetValue("Universe", "Public", RegistryValueKind.String); - clientKey.SetValue("BetaName", "", RegistryValueKind.String); - } - } - - - } - - /// - /// Install the Steam Service. - /// - /// The path to the extracted/existing Program Files (x86)/Common Files/Steam/steamservice.exe - public static async Task InstallSteamService(string steamServiceExePath) { - if (AvaloniaApp.InLinuxDevelopment) { - return; - } - - if (DoesServiceExist()) { - return; - } - - if (!File.Exists(steamServiceExePath)) { - throw new LocalizedException("#InstallError_ServiceInstallFailed"); - } - - var installproc = Process.Start(steamServiceExePath, "/install"); - await installproc.WaitForExitAsync(); - if (installproc.ExitCode != 0) { - // Uninstall and reinstall to fix permission issues - var uninstallproc = Process.Start(steamServiceExePath, "/uninstall"); - await uninstallproc.WaitForExitAsync(); - - // Try to install a second time - installproc = Process.Start(steamServiceExePath, "/install"); - await installproc.WaitForExitAsync(); - if (installproc.ExitCode != 0) { - // Give up after the second error - throw new LocalizedException("#InstallError_ServiceInstallFailed"); - } - } - } - - public static bool DoesServiceExist() - { - ServiceController[] services = ServiceController.GetServices(); - var service = services.FirstOrDefault(s => s.ServiceName == "Steam Client Service"); - return service != null; - } - - - public static void CreateUninstallRegs(string uninstallExe) { - if (AvaloniaApp.InLinuxDevelopment) { - return; - } - - var node = Registry.LocalMachine.OpenSubKey("SOFTWARE")!.OpenSubKey("Microsoft")!.OpenSubKey("Windows")!.OpenSubKey("CurrentVersion")!.OpenSubKey("Uninstall")!; - node.SetValue("DisplayName", "OpenSteamClient", RegistryValueKind.String); - node.SetValue("DisplayVersion", "", RegistryValueKind.String); - node.SetValue("Publisher", "Rosentti", RegistryValueKind.String); - node.SetValue("URLInfoAbout", "https://github.com/OpenSteamClient/OpenSteamClient", RegistryValueKind.String); - node.SetValue("HelpLink", "https://github.com/OpenSteamClient/OpenSteamClient/issues", RegistryValueKind.String); - node.SetValue("DisplayIcon", uninstallExe, RegistryValueKind.String); - node.SetValue("UninstallString", uninstallExe, RegistryValueKind.String); - node.SetValue("NoModify", 1, RegistryValueKind.DWord); - } - - public static async Task ExtractOpenSteamClientToPath(string path, IProgress progress) { - - } - - // If other files ever start mattering, copy them over too, but for now this seems to be enough - // drivers.exe, steamservice.dll and others just magically appear after Steam starts - public static readonly ReadOnlyCollection CommonFiles = new(new List() - { - "steamservice.exe", - }); - - public static bool CommonFilesNeedsSetup() { - if (Directory.Exists(CommonFilesPath)) { - foreach (var item in CommonFiles) - { - if (!File.Exists(Path.Combine(CommonFilesPath, item))) { - return true; - } - } - } else { - return true; - } - - return false; - } - - public static async Task SetupCommonFiles(IProgress progress, IProgress currentOperationLocToken) { - currentOperationLocToken.Report("#InstallProgress_DownloadingService"); - using var stream = new MemoryStream(); - await HttpClient.DownloadAsync(SteamManifest.bins_win32, stream, progress); - Directory.CreateDirectory(CommonFilesPath); - - currentOperationLocToken.Report("#InstallProgress_ExtractingService"); - progress.Report(0); - using var archive = new ZipArchive(stream, ZipArchiveMode.Read, true); - await archive.ExtractToDirectory(CommonFilesPath, progress); - } - - public static readonly HttpClient HttpClient = new(); - - static InstallationManager() { - HttpClient.DefaultRequestHeaders.Add("User-Agent", "opensteamclient-installer/1.0"); - } - - public static async Task RunAllInstallSteps(string targetPath, IProgress progress, IProgress currentOperationLocToken) { - // Do the things that are more likely to fail first - if (CommonFilesNeedsSetup()) { - await SetupCommonFiles(progress, currentOperationLocToken); - } - - if (!DoesServiceExist()) { - currentOperationLocToken.Report("#InstallProgress_InstallingService"); - await InstallSteamService(Path.Combine(CommonFilesPath, "steamservice.exe")); - } - - - } -} \ No newline at end of file diff --git a/Installer/Core/LocalizedException.cs b/Installer/Core/LocalizedException.cs deleted file mode 100644 index 0efba394..00000000 --- a/Installer/Core/LocalizedException.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Installer.Core; - -//TODO: copy this to OpenSteamworks? -[System.Serializable] -public class LocalizedException : System.Exception -{ - public LocalizedException() { } - public LocalizedException(string loctoken) : base(AvaloniaApp.TranslationManager.GetTranslationForKey(loctoken)) { } - public LocalizedException(string loctoken, System.Exception inner) : base(AvaloniaApp.TranslationManager.GetTranslationForKey(loctoken), inner) { } - protected LocalizedException( - System.Runtime.Serialization.SerializationInfo info, - System.Runtime.Serialization.StreamingContext context) : base(info, context) { } -} \ No newline at end of file diff --git a/Installer/Core/SteamManifest.cs b/Installer/Core/SteamManifest.cs deleted file mode 100644 index 9d9d80cb..00000000 --- a/Installer/Core/SteamManifest.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Installer.Core; - -//TODO: auto update this with OSWUpdater -public static class SteamManifest { - public const string bins_win32 = "bins_win32.zip.91ea83c7794514f93f01180f9a07d2edf1589ab6"; - public const int bins_win32_size = 51784912; -} \ No newline at end of file diff --git a/Installer/Enums/InstallAction.cs b/Installer/Enums/InstallAction.cs deleted file mode 100644 index 24065377..00000000 --- a/Installer/Enums/InstallAction.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; - -namespace Installer.Enums; - -[Flags] -public enum InstallAction { - None = 0, - Install = 1 << 1, - Repair = 1 << 2, - Uninstall = 1 << 3 -} \ No newline at end of file diff --git a/Installer/Extensions/ControlExtensions.cs b/Installer/Extensions/ControlExtensions.cs deleted file mode 100644 index bb992559..00000000 --- a/Installer/Extensions/ControlExtensions.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System; -using Avalonia.Controls; -using Avalonia.VisualTree; -using Installer.Translation; - -namespace Installer.Extensions; - -public static class ControlExtensions -{ - // - // Summary: - // Finds the named control under all of this Control's children - // - // Parameters: - // control: - // The control to look in. - // - // name: - // The name of the control to find. - // - // Type parameters: - // T: - // The type of the control to find. - // - // Returns: - // The control or null if not found. - public static T? FindControlNested(this Control control, string name) where T : Control - { - foreach (var item in control.GetVisualChildren()) - { - if (item is Control c) { - var ctrl = FindControlNested(c, name); - if (ctrl != null) { - return ctrl; - } - } - } - - return control.FindControl(name); - } - - public static bool TryTranslateSelf(this Control control, bool dueToLayoutChange = false) - { - if (AvaloniaApp.TranslationManager.CurrentTranslation.Language == ELanguage.None) - { - return false; - } - - Console.WriteLine($"Translating control {control.GetType().Name}{(dueToLayoutChange ? " (due to layout change)" : "")}"); - AvaloniaApp.TranslationManager.TranslateVisual(control); - return true; - } - - public static void TranslatableInit(this Control control) - { - control.TryTranslateSelf(); - // Disable this for now, until I can find a way to filter out mouseover etc events from affecting this - // Ideally we should never need to re-update translations during runtime except on language change, but if objects get added to the visual tree, they might not be translated yet (such as in ItemsControl cases, where you can't translate the fundamental template object since it gets removed at compile time) - //control.LayoutUpdated += (object? sender, EventArgs e) => { control.TryTranslateSelf(true); }; - control.Initialized += (object? sender, EventArgs e) => { control.TryTranslateSelf(true); }; - - // Register some events for auto-retranslate - if (control is TopLevel) - { - (control as TopLevel)!.Opened += (object? sender, System.EventArgs e) => control.TryTranslateSelf(); - } - } -} \ No newline at end of file diff --git a/Installer/Extensions/HttpClientExtensions.cs b/Installer/Extensions/HttpClientExtensions.cs deleted file mode 100644 index a6a37037..00000000 --- a/Installer/Extensions/HttpClientExtensions.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System; -using System.IO; -using System.Net.Http; -using System.Threading; -using System.Threading.Tasks; -using System.Timers; - -namespace Installer.Extensions; - -public static class HttpClientExtensions -{ - public static async Task DownloadAsync(this HttpClient client, string requestUri, Stream destination, IProgress progress, long knownLength = 0, CancellationToken cancellationToken = default) - { - // Get the http headers first to examine the content length - using (var response = await client.GetAsync(requestUri, HttpCompletionOption.ResponseHeadersRead)) - { - long contentLength = 0; - if (knownLength > 0) { - contentLength = knownLength; - } else if (response.Content.Headers.ContentLength != null) { - contentLength = (long)response.Content.Headers.ContentLength; - } - - using (var download = await response.Content.ReadAsStreamAsync()) - { - // Ignore progress reporting when no progress reporter was - // passed or when the content length is unknown - if (progress == null || contentLength == 0) - { - await download.CopyToAsync(destination); - return; - } - - bool cancelledDueToTimeout = false; - - using (CancellationTokenSource source = new CancellationTokenSource()) - { - System.Timers.Timer timer = new System.Timers.Timer(15000); - timer.AutoReset = false; - timer.Start(); - timer.Elapsed += (object? sender, ElapsedEventArgs args) => { - cancelledDueToTimeout = true; - source.Cancel(); - }; - - // Convert absolute progress (bytes downloaded) into relative progress (0% - 100%) - // Also reset the timer by setting it's interval - var relativeProgress = new Progress((long totalBytes) => { - progress.Report((int)(((float)totalBytes / contentLength)*100)); - timer.Interval = 20000; - }); - - CancellationToken token = source.Token; - cancellationToken.Register(() => { - cancelledDueToTimeout = false; - source.Cancel(); - }); - - try - { - // Use extension method to report progress while downloading - await download.CopyToAsync(destination, 81920, relativeProgress, token); - // If download finished, stop the timer - timer.Stop(); - } - catch (OperationCanceledException) - { - if (!cancelledDueToTimeout) { - throw; - } - throw new Exception("Lost connection to server"); - } - } - - progress.Report(100); - } - } - } -} \ No newline at end of file diff --git a/Installer/Extensions/RegistryKeyExtensions.cs b/Installer/Extensions/RegistryKeyExtensions.cs deleted file mode 100644 index 11235bf7..00000000 --- a/Installer/Extensions/RegistryKeyExtensions.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Security.AccessControl; -using Microsoft.Win32; - -namespace Installer.Extensions; - -public static class RegistryKeyExtensions { - public static RegistryKey CreateOrOpen(this RegistryKey regkey, string subkey, RegistryKeyPermissionCheck permissionCheck, RegistryOptions registryOptions, out bool created, RegistrySecurity? security = null) { - var key = regkey.OpenSubKey(subkey, permissionCheck); - - created = key == null; - if (key == null) { - key = regkey.CreateSubKey(subkey, permissionCheck, registryOptions, security); - } - - return key; - } -} \ No newline at end of file diff --git a/Installer/Extensions/StreamExtensions.cs b/Installer/Extensions/StreamExtensions.cs deleted file mode 100644 index 401a8890..00000000 --- a/Installer/Extensions/StreamExtensions.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using System.IO; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; - -namespace Installer; - -public static class StreamExtensions -{ - public static async Task CopyToAsync(this Stream source, Stream destination, int bufferSize, IProgress progress, CancellationToken cancellationToken = default) { - if (source == null) - throw new ArgumentNullException(nameof(source)); - if (!source.CanRead) - throw new ArgumentException("Has to be readable", nameof(source)); - if (destination == null) - throw new ArgumentNullException(nameof(destination)); - if (!destination.CanWrite) - throw new ArgumentException("Has to be writable", nameof(destination)); - if (bufferSize < 0) - throw new ArgumentOutOfRangeException(nameof(bufferSize)); - - var buffer = new byte[bufferSize]; - long totalBytesRead = 0; - int bytesRead; - while ((bytesRead = await source.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false)) != 0) { - await destination.WriteAsync(buffer, 0, bytesRead, cancellationToken).ConfigureAwait(false); - totalBytesRead += bytesRead; - progress.Report(totalBytesRead); - } - } - - public static bool AreEqual(this MemoryStream first, MemoryStream second) { - if (first.Length != second.Length) { - return false; - } - - first.Position = 0; - second.Position = 0; - - return first.ToArray().SequenceEqual(second.ToArray()); - } -} diff --git a/Installer/Extensions/VisualExtensions.cs b/Installer/Extensions/VisualExtensions.cs deleted file mode 100644 index 96b7a0f4..00000000 --- a/Installer/Extensions/VisualExtensions.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Collections.Generic; -using Avalonia; -using Avalonia.LogicalTree; -using Avalonia.VisualTree; - -namespace Installer.Extensions; - -public static class VisualExtensions -{ - public static IEnumerable GetAllVisualChildrenTree(this Visual visual) - { - List allVisuals = new() - { - visual - }; - - // First get all logical children - foreach (var item in visual.GetLogicalChildren()) - { - // Then try to cast them to Visual (most of the time should be valid) - if (item is Visual) - { - allVisuals.AddRange(GetAllVisualChildrenTree((Visual)item!)); - } - } - - return allVisuals; - } -} \ No newline at end of file diff --git a/Installer/Extensions/ZipArchiveExtensions.cs b/Installer/Extensions/ZipArchiveExtensions.cs deleted file mode 100644 index e451d542..00000000 --- a/Installer/Extensions/ZipArchiveExtensions.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.IO; -using System.IO.Compression; -using System.Text; -using System.Threading.Tasks; - -namespace Installer; - -public static class ZipArchiveExtensions -{ - public static async Task ExtractToDirectory(this ZipArchive source, string destinationDirectoryName, IProgress prog, Action? afterExtractHook = null) - { - foreach (ZipArchiveEntry entry in source.Entries) - { - var FullNameFixed = entry.FullName; - - // Fixup slashes for Non-Windows platforms - if (!OperatingSystem.IsWindows()) - { - FullNameFixed = FullNameFixed.Replace('\\', '/'); - } - - var FullPath = Path.Combine(destinationDirectoryName, FullNameFixed); - - if (entry.Length == 0 && (FullNameFixed.EndsWith('/') || FullNameFixed.EndsWith('\\'))) - { - Directory.CreateDirectory(FullPath); - continue; - } - - Directory.CreateDirectory(Path.GetDirectoryName(FullPath)!); - - using (Stream zipstream = entry.Open()) - { - using (var file = new FileStream(FullPath, FileMode.Create, FileAccess.Write, FileShare.None)) - { - // Convert absolute progress (bytes unzipped) into relative progress (0% - 100%) - var relativeProgress = new Progress(totalBytes => prog.Report((int)(((float)totalBytes / entry.Length) * 100))); - - // Use extension method to report progress while downloading - await zipstream.CopyToAsync(file, 81920, relativeProgress, default); - afterExtractHook?.Invoke(entry, FullNameFixed); - } - } - } - } -} \ No newline at end of file diff --git a/Installer/Installer.csproj b/Installer/Installer.csproj deleted file mode 100644 index fb531602..00000000 --- a/Installer/Installer.csproj +++ /dev/null @@ -1,69 +0,0 @@ - - - WinExe - $(CommonNetVersion)-windows - enable - true - full - app.manifest - true - - - en - true - false - - - - - - win-x64 - false - None - true - true - - - - win-x64;linux-x64;osx-x64 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Installer/Program.cs b/Installer/Program.cs deleted file mode 100644 index b2cd3e2d..00000000 --- a/Installer/Program.cs +++ /dev/null @@ -1,54 +0,0 @@ -using Avalonia; -using System; -using System.Linq; -using System.Security.Principal; - -namespace Installer; - -public static class Program -{ - // Initialization code. Don't use any Avalonia, third-party APIs or any - // SynchronizationContext-reliant code before AppMain is called: things aren't initialized - // yet and stuff might break. - [STAThread] - public static void Main(string[] args) - { -#if DEBUG - if (!OperatingSystem.IsWindows()) { - AvaloniaApp.InLinuxDevelopment = true; - } -#endif - - if (args.Contains("-debug")) - { - AvaloniaApp.DebugEnabled = true; - } -#if DEBUG - Console.WriteLine("Running DEBUG build, debug mode forced on"); - AvaloniaApp.DebugEnabled = true; -#endif - - if (!AvaloniaApp.InLinuxDevelopment) { - if (!IsAdministrator()) { - return; - } - } - - BuildAvaloniaApp().StartWithClassicDesktopLifetime(args, Avalonia.Controls.ShutdownMode.OnMainWindowClose); - } - - public static bool IsAdministrator() - { - var identity = WindowsIdentity.GetCurrent(); - var principal = new WindowsPrincipal(identity); - return principal.IsInRole(WindowsBuiltInRole.Administrator); - } - - // Avalonia configuration, don't remove; also used by visual designer. - public static AppBuilder BuildAvaloniaApp() - => AppBuilder.Configure() - .UsePlatformDetect() - .WithInterFont() - .UseSkia() - .LogToTrace(); -} diff --git a/Installer/Translation/ELanguage.cs b/Installer/Translation/ELanguage.cs deleted file mode 100644 index dec8a4fb..00000000 --- a/Installer/Translation/ELanguage.cs +++ /dev/null @@ -1,91 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Installer.Translation; - -public enum ELanguage -{ - None = -1, - English = 0, - German = 1, - French = 2, - Italian = 3, - Korean = 4, - Spanish = 5, - Simplified_Chinese = 6, - Traditional_Chinese = 7, - Russian = 8, - Thai = 9, - Japanese = 10, - Portuguese = 11, - Polish = 12, - Danish = 13, - Dutch = 14, - Finnish = 15, - Norwegian = 16, - Swedish = 17, - Hungarian = 18, - Czech = 19, - Romanian = 20, - Turkish = 21, - Brazilian = 22, - Bulgarian = 23, - Greek = 24, - Arabic = 25, - Ukrainian = 26, - Latam_Spanish = 27, - Vietnamese = 28, -} - -public static class ELanguageConversion { - private static readonly Dictionary ELanguageToAPINameMap = new() { - {ELanguage.None, ""}, - {ELanguage.English, "english"}, - {ELanguage.German, "german"}, - {ELanguage.French, "french"}, - {ELanguage.Italian, "italian"}, - {ELanguage.Korean, "korean"}, - {ELanguage.Spanish, "spanish"}, - {ELanguage.Simplified_Chinese, "schinese"}, // Is this correct? - {ELanguage.Traditional_Chinese, "tchinese"}, // Is this correct? - {ELanguage.Russian, "russian"}, - {ELanguage.Thai, "thai"}, - {ELanguage.Japanese, "japanese"}, - {ELanguage.Portuguese, "portuguese"}, - {ELanguage.Polish, "polish"}, - {ELanguage.Danish, "danish"}, - {ELanguage.Dutch, "dutch"}, - {ELanguage.Finnish, "finnish"}, - {ELanguage.Norwegian, "norwegian"}, - {ELanguage.Swedish, "swedish"}, - {ELanguage.Hungarian, "hungarian"}, - {ELanguage.Czech, "czech"}, - {ELanguage.Romanian, "romanian"}, - {ELanguage.Turkish, "turkish"}, - {ELanguage.Brazilian, "brazilian"}, - {ELanguage.Bulgarian, "bulgarian"}, - {ELanguage.Greek, "greek"}, - {ELanguage.Arabic, "arabic"}, - {ELanguage.Ukrainian, "ukrainian"}, - {ELanguage.Latam_Spanish, "latam_spanish"}, - {ELanguage.Vietnamese, "vietnamese"}, - }; - - // Add language here when making a translation - public static Dictionary TwoLetterISOCodesToLanguages = new() { - {"iv", ELanguage.None}, - {"en", ELanguage.English}, - {"fi", ELanguage.Finnish}, - }; - - public readonly static Dictionary APINameToELanguageMap = ELanguageToAPINameMap.ToDictionary(x => x.Value, x => x.Key); - - public static ELanguage ELanguageFromAPIName(string apiName) { - return APINameToELanguageMap[apiName]; - } - - public static string APINameFromELanguage(ELanguage eLanguage) { - return ELanguageToAPINameMap[eLanguage]; - } -} \ No newline at end of file diff --git a/Installer/Translation/TranslationManager.cs b/Installer/Translation/TranslationManager.cs deleted file mode 100644 index 0db1ffb0..00000000 --- a/Installer/Translation/TranslationManager.cs +++ /dev/null @@ -1,285 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Text.Json; -using System.Text.Json.Serialization; -using System.Threading.Tasks; -using Avalonia; -using Avalonia.Controls; -using Avalonia.LogicalTree; -using Avalonia.Threading; -using Avalonia.VisualTree; -using Installer.Extensions; -using Microsoft.Extensions.FileProviders; - -namespace Installer.Translation; - -[JsonSourceGenerationOptions(WriteIndented = true)] -[JsonSerializable(typeof(Translation))] -internal partial class SourceGenerationContext : JsonSerializerContext -{ -} - -public class Translation -{ - public ELanguage Language { get; set; } = ELanguage.None; - public string LanguageFriendlyName { get; set; } = ""; - public string ISOCode { get; set; } = ""; - public Dictionary TranslationKeys { get; set; } = new(); -} - -public class TranslationManager -{ - public Translation CurrentTranslation = new(); - private readonly List RefreshableObjects = new(); - public static IEnumerable ValidUILanguages => new ELanguage[] { ELanguage.English, ELanguage.Finnish }; - - public event EventHandler? TranslationChanged; - - public TranslationManager() - { - - } - - public void SetLanguage(ELanguage language) - { - var lang = ELanguageToString(language); - if (lang == null) - { - throw new ArgumentException($"Language {language} was not valid."); - } - - if (!ValidUILanguages.Contains(language)) { - throw new InvalidOperationException("No translation for " + language); - } - - CurrentTranslation = GetForLanguage(language); - - Dispatcher.UIThread.Invoke(() => - { - foreach (var obj in RefreshableObjects) - { - TranslateAvaloniaObject(obj); - } - }); - - TranslationChanged?.Invoke(this, EventArgs.Empty); - } - - public string GetTranslationForKey(string key) - { - this.CurrentTranslation.TranslationKeys.TryGetValue(key, out string? val); - if (val == null) - { - val = $"TRANSLATION FAILED (key '{key}')"; - } - - return val; - } - - private Translation GetForLanguage(ELanguage language) - { - string? langname = ELanguageToString(language); - if (langname == null) - { - throw new ArgumentOutOfRangeException("Invalid ELanguage " + language + " specified."); - } - - // Fetch the translations from this assembly. The translations are embedded in the installer - var embeddedProvider = new EmbeddedFileProvider(Assembly.GetExecutingAssembly()); - string filename = "Translations/" + langname + ".json"; - IFileInfo fileInfo = embeddedProvider.GetFileInfo(filename); - if (!fileInfo.Exists) { - if (language == ELanguage.English) - { - throw new Exception("Base language not found!"); - } - - throw new Exception("Language " + language + " not found"); - } - - string text; - using (var stream = fileInfo.CreateReadStream()) - { - using (var reader = new StreamReader(stream)) - { - text = reader.ReadToEnd(); - } - } - - var newTranslation = JsonSerializer.Deserialize(text, SourceGenerationContext.Default.Translation); - ArgumentNullException.ThrowIfNull(newTranslation); - return newTranslation; - } - - /// - /// This function is for creating and translating elements in code behind - /// - public T CreateTranslated(T visualCreated, string translationKey, string? defaultStr = null) where T : Visual - { - visualCreated[Controls.Translatable.TranslationKeyProperty] = translationKey; - visualCreated[Controls.Translatable.DefaultTextProperty] = defaultStr; - TranslateVisual(visualCreated); - return visualCreated; - } - - public void TranslateVisual(Visual visual) - { - foreach (var vis in visual.GetAllVisualChildrenTree()) - { - Console.WriteLine("vis " + vis.Name); - TranslateAvaloniaObject(vis); - } - } - - public void TranslateTrayIcon(TrayIcon icon) - { - List objs = new() - { - icon - }; - - if (icon.Menu != null) - { - objs.Add(icon.Menu); - foreach (var item in icon.Menu.Items) - { - objs.Add(item); - } - } - - foreach (var item in objs) - { - TranslateAvaloniaObject(item); - } - } - public void TranslateAvaloniaObject(AvaloniaObject obj) - { - if (!RefreshableObjects.Contains(obj)) - { - RefreshableObjects.Add(obj); - } - - string? translationKey = (string?)obj[Controls.Translatable.TranslationKeyProperty]; - string? defaultStr = (string?)obj[Controls.Translatable.DefaultTextProperty]; - if (!string.IsNullOrEmpty(translationKey)) - { - bool translationFailed = false; - string translatedText = $"TRANSLATION FAILED (key '{translationKey}')"; - if (!this.CurrentTranslation.TranslationKeys.ContainsKey(translationKey)) - { - translationFailed = true; - Console.WriteLine("Cannot translate " + translationKey + ", no key!"); - } - else - { - translatedText = this.CurrentTranslation.TranslationKeys[translationKey]; - Console.WriteLine("Got translation " + translatedText); - } - - void TranslateTextInternal(StyledProperty property) - { - bool isEmptyOrNull = false; - T val = obj.GetValue(property); - if (val == null) - { - isEmptyOrNull = true; - } - else if (val is string str) - { - isEmptyOrNull = string.IsNullOrEmpty(str); - } - - if (!translationKey.StartsWith('#')) - { - // User probably meant to set the text directly. - obj.SetValue(property, translationKey); - return; - } - - // Don't replace text with TRANSLATION FAILED if there's pre-existing text in the control - if (translationFailed && !isEmptyOrNull) - { - return; - } - else - { - // And if there's no pre existing text, but the translation failed, show the default string if it is not empty - if (!string.IsNullOrEmpty(defaultStr)) - { - obj.SetValue(property, defaultStr); - return; - } - } - - Console.WriteLine("Set property " + property + " to " + translatedText + " for " + obj.GetType()); - if (obj is Control c) { - Console.WriteLine("with name " + c.Name); - } - - obj.SetValue(property, translatedText); - } - - // Window eventually inherits from ContentControl, as do lots of other controls. We don't want to override a window's content... - if (obj is Window) - { - TranslateTextInternal(Window.TitleProperty); - } - else if (obj is MenuItem) - { - TranslateTextInternal(MenuItem.HeaderProperty); - } - else if (obj is TextBox) - { - TranslateTextInternal(TextBox.WatermarkProperty); - } - else if (obj is ContentControl) - { - TranslateTextInternal(ContentControl.ContentProperty); - } - else if (obj is TextBlock) - { - TranslateTextInternal(TextBlock.TextProperty); - } - else if (obj is NativeMenuItem) - { - TranslateTextInternal(NativeMenuItem.HeaderProperty); - } - else if (obj is TrayIcon) - { - TranslateTextInternal(TrayIcon.ToolTipTextProperty); - } - } - } - - public static string? ELanguageToString(ELanguage lang) - { - try - { - return ELanguageConversion.APINameFromELanguage(lang); - } - catch (System.Exception) - { - return null; - } - } - - public string GetPrettyNameForLanguage(ELanguage lang) - { - return GetForLanguage(lang).LanguageFriendlyName; - } - - //TODO: we should copy this over to OpenSteamClient as well - public void LoadCurrentSystemTranslation() - { - if (ELanguageConversion.TwoLetterISOCodesToLanguages.TryGetValue(CultureInfo.CurrentUICulture.TwoLetterISOLanguageName, out ELanguage lang)) { - SetLanguage(lang); - } else { - SetLanguage(ELanguage.English); - } - } -} \ No newline at end of file diff --git a/Installer/Translations/english.json b/Installer/Translations/english.json deleted file mode 100644 index 4ce1bd37..00000000 --- a/Installer/Translations/english.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "Language": 0, - "LanguageFriendlyName": "English", - "ISOCode": "en", - "TranslationKeys": { - "#LanguageNameTranslated": "English", - "#Dialog_Cancel": "Cancel", - "#Dialog_OK": "OK", - "#Dialog_Yes": "Yes", - "#Dialog_No": "No", - "#Dialog_Next": "Next", - "#Dialog_Previous": "Previous", - "#Dialog_Finish": "Finish", - "#Dialog_Install": "Install", - "#MainWindow_Title": "OpenSteamClient Installer", - "#LocalizedSteamSSALink": "https://store.steampowered.com/subscriber_agreement/", - "#Welcome_WindowTitle": "Welcome", - "#Welcome_Title": "Welcome to the OpenSteamClient setup", - "#Welcome_FeatureText": "OpenSteamClient is a community alternative to the official Steam Client. Here are some of it's features: ", - "#Welcome_Features": " - Lightweight\n - Not browser based\n - Extensive customization\n - Community support\n - 64-bit", - "#Welcome_AgreeText": "Please agree to the below terms to use OpenSteamClient.", - "#Welcome_ViewSSAButton": "View Steam Subscriber Agreement", - "#Welcome_AgreeSSACheckbox": "I agree to the Steam Subscriber Agreement", - "#Welcome_AgreeOSCDevelopersCheckbox": "I agree to not hold OpenSteamClient's developers responsible if my Steam account gets terminated for any reason", - "#ChooseActionPage_Install": "Install", - "#ChooseActionPage_InstallSubtext": "Install OpenSteamClient", - "#ChooseActionPage_Repair": "Repair", - "#ChooseActionPage_RepairSubtext": "Repair OpenSteamClient", - "#ChooseActionPage_Uninstall": "Uninstall", - "#ChooseActionPage_UninstallSubtext": "Uninstall OpenSteamClient", - "#PickInstallDirectory_WindowTitle": "Choose install directory", - "#PickInstallDirectory_ButtonText": "Browse", - "#PickInstallDirectory_Title": "Choose an install directory to install OpenSteamClient", - "#PickInstallDirectory_FolderPickerTitle": "Select an install directory to install OpenSteamClient", - "#PickInstallDirectory_Text": "Games and apps may be installed in this directory, but you can also add alternative directories and drives later.", - "#InstallError_NoSpaceError": "Selected drive does not have enough space. At least 1GB is required.", - "#InstallError_DirectoryNotFoundError": "Install folder does not exist", - "#InstallError_ContainsFilesError": "Install folder contains files", - "#InstallError_PathNotAbsoluteError": "Provided path is not absolute", - "#InstallError_ServiceInstallFailed": "Service installation failed with code {0}, error: {1}", - "#InstallError_GenericErrorCode": "Got error code {0} while installing", - "#InstallError_GenericError": "Got error {0} while installing", - "#InstallProgress_DownloadingService": "Downloading Steam Client Service", - "#InstallProgress_InstallingService": "Installing Steam Client Service", - "#InstallProgress_UnzippingOSC": "Unzipping OpenSteamClient", - "#InstallProgress_WritingRegistryKeys": "Writing registry keys" - } -} \ No newline at end of file diff --git a/Installer/Translations/finnish.json b/Installer/Translations/finnish.json deleted file mode 100644 index 8bd500c8..00000000 --- a/Installer/Translations/finnish.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "Language": 15, - "LanguageFriendlyName": "Finnish", - "ISOCode": "fi", - "TranslationKeys": { - "#SettingsWindow_YourCurrentLanguage": "Tämänhetkinen kielesi on {0} ({1})", - "#LanguageNameTranslated": "Suomi", - "#Dialog_Cancel": "Peruuta", - "#Dialog_OK": "OK", - "#Dialog_Yes": "Kyllä", - "#Dialog_No": "Ei", - "#Dialog_Next": "Seuraava", - "#Dialog_Previous": "Edellinen", - "#Dialog_Finish": "Lopeta", - "#Dialog_Install": "Asenna", - "#LocalizedSteamSSALink": "https://store.steampowered.com/subscriber_agreement/?l=finnish", - "#MainWindow_Title": "OpenSteamClient -asennusohjelma", - "#Welcome_WindowTitle": "Tervetuloa", - "#Welcome_Title": "Tervetuloa OpenSteamClient -asennusohjelmaan", - "#Welcome_FeatureText": "OpenSteamClient on vaihtoehtoinen yhteisön rakentama Steam-ohjelma. Sen ominaisuuksiin kuuluu: ", - "#Welcome_Features": " - Kevyt\n - Ei selainpohjainen\n - Laajat kustomointivaihtoehdot\n - Yhteisön tuki\n - 64-bittinen", - "#Welcome_AgreeText": "Hyväksy alla olevat ehdot käyttääksesi OpenSteamClient:ia", - "#Welcome_ViewSSAButton": "Katso Steam-tilaussopimus", - "#Welcome_AgreeSSACheckbox": "Hyväksyn Steam-tilaussopimuksen ehdot", - "#Welcome_AgreeOSCDevelopersCheckbox": "Hyväksyn, etten pidä OpenSteamClient:in kehittäjiä vastuullisena, jos Steam-tilini lakkautetaan mistään syystä", - "#ChooseActionPage_Install": "Asenna", - "#ChooseActionPage_InstallSubtext": "Asenna OpenSteamClient", - "#ChooseActionPage_Repair": "Korjaa", - "#ChooseActionPage_RepairSubtext": "Korjaa OpenSteamClient", - "#ChooseActionPage_Uninstall": "Poista asennus", - "#ChooseActionPage_UninstallSubtext": "Poista OpenSteamClient:in asennus", - "#PickInstallDirectory_WindowTitle": "Valitse asennuskansio", - "#PickInstallDirectory_ButtonText": "Selaa", - "#PickInstallDirectory_Title": "Valitse kansio minne OpenSteamClient asennetaan", - "#PickInstallDirectory_FolderPickerTitle": "Valitse kansio minne OpenSteamClient asennetaan", - "#PickInstallDirectory_Text": "Pelit ja sovellukset voidaan asennetaan tähänkin kansioon, mutta voit myös lisätä muita kansioita ja asemia myöhemmin. ", - "#InstallError_NoSpaceError": "Valitulla levyllä ei ole tarpeeksi tilaa asentaa OpenSteamClient:iä. Vaaditaan ainakin 1GB.", - "#InstallError_DirectoryNotFoundError": "Asennuskansioa ei ole olemassa.", - "#InstallError_ContainsFilesError": "Asennuskansio sisältää tiedostoja", - "#InstallError_PathNotAbsoluteError": "Polku ei ole absoluutti", - "#InstallError_GenericErrorCode": "Tapahtui virhekoodi {0}", - "#InstallError_GenericError": "Tapahtui virhe {0}", - "#InstallError_ServiceInstallFailed": "Palvelun asennus epäonnistui virhekoodilla {0}, virhe: {1}", - "#InstallProgress_DownloadingService": "Ladataan Steam-palvelua", - "#InstallProgress_InstallingService": "Asennetaan Steam-palvelua", - "#InstallProgress_UnzippingOSC": "Puretaan OpenSteamClient:ia", - "#InstallProgress_WritingRegistryKeys": "Kirjoitetaan rekisteriarvoja" - } -} \ No newline at end of file diff --git a/Installer/ViewModels/AvaloniaAppViewModel.cs b/Installer/ViewModels/AvaloniaAppViewModel.cs deleted file mode 100644 index 14887a41..00000000 --- a/Installer/ViewModels/AvaloniaAppViewModel.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace Installer.ViewModels; - -public partial class AvaloniaAppViewModel : AvaloniaCommon.ViewModelBase { - -} \ No newline at end of file diff --git a/Installer/ViewModels/LanguageViewModel.cs b/Installer/ViewModels/LanguageViewModel.cs deleted file mode 100644 index ae305a41..00000000 --- a/Installer/ViewModels/LanguageViewModel.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Installer.Translation; - -namespace Installer.ViewModels; - -public partial class LanguageViewModel : AvaloniaCommon.ViewModelBase { - public string Name { get; init; } - public ELanguage ELang { get; init; } - public LanguageViewModel(ELanguage lang) { - this.ELang = lang; - this.Name = AvaloniaApp.TranslationManager.GetPrettyNameForLanguage(lang); - } -} \ No newline at end of file diff --git a/Installer/ViewModels/MainWindowViewModel.cs b/Installer/ViewModels/MainWindowViewModel.cs deleted file mode 100644 index f82dbcca..00000000 --- a/Installer/ViewModels/MainWindowViewModel.cs +++ /dev/null @@ -1,269 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.ComponentModel; -using System.Globalization; -using System.Linq; -using System.Windows.Input; -using Avalonia.Controls; -using Avalonia.Media; -using Avalonia.Media.Imaging; -using Avalonia.Platform; -using CommunityToolkit.Mvvm.ComponentModel; -using CommunityToolkit.Mvvm.Input; -using Installer.Enums; -using Installer.Extensions; -using Installer.Translation; -using Installer.ViewModels.Pages; -using Installer.Views; - -namespace Installer.ViewModels; - -public partial class MainWindowViewModel : AvaloniaCommon.ViewModelBase { - [ObservableProperty] - private UserControl currentPage; - - [ObservableProperty] - private Bitmap openSteamLogo; - - public bool CanClose => OnCancel != null; - public bool PreviousEnabled => CanClose && OnPrevious != null; - public bool NextEnabled => CanClose && OnNext != null; - - [NotifyPropertyChangedFor(nameof(CanClose))] - [NotifyPropertyChangedFor(nameof(PreviousEnabled))] - [NotifyPropertyChangedFor(nameof(NextEnabled))] - [ObservableProperty] - private ICommand? onCancel; - - [NotifyPropertyChangedFor(nameof(PreviousEnabled))] - [ObservableProperty] - private ICommand? onPrevious; - - [NotifyPropertyChangedFor(nameof(NextEnabled))] - [ObservableProperty] - private ICommand? onNext; - - [ObservableProperty] - private LanguageViewModel selectedLanguage; - - public LinearGradientBrush PanelBackground { get; init; } - public ObservableCollection Languages { get; init; } = new(); - - private readonly MainWindow window; - private readonly List Pages = new(); - - private bool canGoBack = true; - public bool CanGoBack { - get => canGoBack; - set { - canGoBack = value; - UpdateActions(); - } - } - - public InstallAction AvailableActions { get; set; } - private InstallAction selectedAction = InstallAction.None; - public InstallAction SelectedAction { - get => selectedAction; - set { - selectedAction = value; - UpdateActions(); - } - } - - private bool canGoNext = false; - public bool CanGoNext { - get => canGoNext; - set { - canGoNext = value; - UpdateActions(); - } - } - - private bool HasPrevious => CanGoBack && Pages.IndexOf(CurrentPage) > 0; - private bool HasNext => CanGoNext && Pages.IndexOf(CurrentPage) + 1 < Pages.Count; - private readonly UserControl chooseActionPage; - private readonly UserControl placeholderPage; - private readonly PlaceholderPageViewModel placeholderPageViewModel; - - public MainWindowViewModel(MainWindow window) { - this.PanelBackground = new LinearGradientBrush(); - PanelBackground.StartPoint = new Avalonia.RelativePoint(0, 0, Avalonia.RelativeUnit.Relative); - PanelBackground.EndPoint = new Avalonia.RelativePoint(1, 1, Avalonia.RelativeUnit.Relative); - PanelBackground.GradientStops.Add(new GradientStop() { - Offset = 0, - Color = Color.Parse("#ff0000"), - }); - - PanelBackground.GradientStops.Add(new GradientStop() { - Offset = 1, - Color = Color.Parse("#7b0000"), - }); - - foreach (var item in TranslationManager.ValidUILanguages) - { - Languages.Add(new LanguageViewModel(item)); - } - - SelectedLanguage = Languages.First(l => AvaloniaApp.TranslationManager.CurrentTranslation.Language == l.ELang); - - this.window = window; - - //TODO: check install status here and determine the available actions - AvailableActions = InstallAction.Install | InstallAction.Repair | InstallAction.Uninstall; - - { - var page = new WelcomePage(); - page.DataContext = new WelcomePageViewModel(this); - Pages.Add(page); - } - - { - chooseActionPage = new ChooseActionPage(); - chooseActionPage.DataContext = new ChooseActionPageViewModel(this); - Pages.Add(chooseActionPage); - } - - { - placeholderPage = new PlaceholderPage(); - placeholderPageViewModel = new PlaceholderPageViewModel(); - placeholderPage.DataContext = placeholderPageViewModel; - Pages.Add(placeholderPage); - } - - { - var page = new InstallingPage(); - page.DataContext = new InstallingPageViewModel(); - Pages.Add(page); - } - - this.CurrentPage = Pages.First(); - - this.OpenSteamLogo = new Bitmap(AssetLoader.Open(new Uri("avares://Installer/Assets/opensteam-logo.ico"))); - this.PropertyChanged += InternalOnPropertyChanged; - this.OnCancel = new RelayCommand(Cancel); - this.OnNext = new RelayCommand(Next); - - window.Closing += OnClosing; - - UpdateActions(); - } - - private void OnClosing(object? sender, WindowClosingEventArgs e) - { - e.Cancel = !CanClose; - } - - private void InternalOnPropertyChanged(object? sender, PropertyChangedEventArgs e) - { - if (e.PropertyName == nameof(CanClose)) { - if (CanClose) { - WindowToolbar.EnableCloseButton(window); - } else { - WindowToolbar.DisableCloseButton(window); - } - } - - if (e.PropertyName == nameof(SelectedLanguage)) { - AvaloniaApp.TranslationManager.SetLanguage(SelectedLanguage.ELang); - } - } - - private void Cancel() { - AvaloniaApp.Current?.MainWindow?.Close(); - } - - private void Previous() { - if (HasPrevious) { - CurrentPage = Pages.ElementAt(Pages.IndexOf(CurrentPage) - 1); - } - - UpdateActions(); - } - - private void Next() { - if (HasNext) { - var nextPage = Pages.ElementAt(Pages.IndexOf(CurrentPage) + 1); - if (nextPage is PlaceholderPage) { - switch (SelectedAction) - { - case InstallAction.None: - placeholderPageViewModel.InternalControl = new TextBlock() { - Text = "No install action selected! (You should not be able to see this screen)" - }; - break; - case InstallAction.Install: - var page = new ChooseInstallDirectoryPage(); - page.DataContext = new ChooseInstallDirectoryPageViewModel(page, this); - placeholderPageViewModel.InternalControl = page; - break; - case InstallAction.Repair: - placeholderPageViewModel.InternalControl = new TextBlock() { - Text = "Repair page" - }; - break; - case InstallAction.Uninstall: - placeholderPageViewModel.InternalControl = new TextBlock() { - Text = "Uninstall page" - }; - break; - } - } - - if (nextPage is InstallingPage) { - OnCancel = null; - } - - CurrentPage = nextPage; - } - - UpdateActions(); - } - - private void UpdateActions() { - if (HasPrevious) { - OnPrevious = new RelayCommand(Previous); - } else { - OnPrevious = null; - } - - if (CurrentPage is ChooseActionPage) { - if (SelectedAction == InstallAction.None) { - OnNext = null; - return; - } - } - - if (!CanGoNext) { - OnNext = null; - return; - } - - Console.WriteLine("CurrentPage is " + (CurrentPage == null ? "null" : CurrentPage.GetType().Name)); - Console.WriteLine("InternalControl is " + (placeholderPageViewModel.InternalControl == null ? "null" : placeholderPageViewModel.InternalControl!.GetType().Name)); - - if (HasNext) { - OnNext = new RelayCommand(Next); - - var nextBtn = window.FindControlNested - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/OpenSteamClient/Controls/BaseWebPage.axaml.cs b/OpenSteamClient/Controls/BaseWebPage.axaml.cs deleted file mode 100644 index 41e0e238..00000000 --- a/OpenSteamClient/Controls/BaseWebPage.axaml.cs +++ /dev/null @@ -1,216 +0,0 @@ -using System; -using System.Collections.Generic; -using OpenSteamClient.Extensions; -using Avalonia.Controls; -using Avalonia.Markup.Xaml; -using Avalonia.Controls.Primitives; -using Avalonia; -using CommunityToolkit.Mvvm.ComponentModel; -using OpenSteamClient.Controls; -using Avalonia.Interactivity; -using System.Diagnostics.CodeAnalysis; -using OpenSteamworks; -using OpenSteamworks.Callbacks; -using OpenSteamworks.Callbacks.Structs; -using Avalonia.Threading; -using CommunityToolkit.Mvvm.Input; -using OpenSteamClient.DI; - -namespace OpenSteamClient.Controls; - -public partial class BaseWebPage : BasePage -{ - /// - /// Defines the property. - /// - public static readonly AttachedProperty URLProperty = - AvaloniaProperty.RegisterAttached(nameof(URL), typeof(BaseWebPage), "", true); - - /// - /// Defines the property. - /// - public static readonly AttachedProperty CustomCSSProperty = - AvaloniaProperty.RegisterAttached(nameof(CustomCSS), typeof(BaseWebPage), "", true); - - /// - /// Defines the property. - /// - public static readonly AttachedProperty UserAgentProperty = - AvaloniaProperty.RegisterAttached(nameof(UserAgent), typeof(BaseWebPage), "Valve Steam Client", true); - - /// - /// Defines the property. - /// - public static readonly AttachedProperty SetSteamCookiesProperty = - AvaloniaProperty.RegisterAttached(nameof(SetSteamCookies), typeof(BaseWebPage), false, true); - - /// - /// Gets or sets the url of the page to display. - /// - public string URL - { - get => this.GetValue(URLProperty); - set => this.SetValue(URLProperty, value); - } - - /// - /// Gets or sets the custom css. - /// - public string? CustomCSS - { - get => this.GetValue(CustomCSSProperty); - set => this.SetValue(CustomCSSProperty, value); - } - - /// - /// Gets or sets the user agent. - /// - public string UserAgent - { - get => this.GetValue(UserAgentProperty); - set => this.SetValue(UserAgentProperty, value); - } - - /// - /// Gets or sets if the webview should set steam cookies for auth. - /// - public bool SetSteamCookies - { - get => this.GetValue(SetSteamCookiesProperty); - set => this.SetValue(SetSteamCookiesProperty, value); - } - - private HTMLSurface? webviewControl; - - //I'd love to use bindings here, but due to us being inherited from control we can't. - private readonly ContentControl webviewContainer; - private readonly Button prevButton; - private readonly Button nextButton; - private readonly Button refreshButton; - private readonly Button openDevToolsButton; - private readonly TextBox currentURLTextBox; - private bool hasLoaded = false; - - public BaseWebPage() : base() - { - AvaloniaXamlLoader.Load(this); - this.TranslatableInit(); - - var webviewContainer = this.FindControl("WebviewContainer"); - if (webviewContainer == null) - { - throw new NullReferenceException("webviewContainer not found"); - } - this.webviewContainer = webviewContainer; - - var prevButton = this.FindControl - - - diff --git a/OpenSteamClient/Views/Debugging/HTMLSurfaceTest.axaml.cs b/OpenSteamClient/Views/Debugging/HTMLSurfaceTest.axaml.cs deleted file mode 100644 index d46332bc..00000000 --- a/OpenSteamClient/Views/Debugging/HTMLSurfaceTest.axaml.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System; -using System.Threading.Tasks; -using Avalonia.Controls; -using Avalonia.Interactivity; -using Avalonia.Threading; -using OpenSteamClient.DI; -using OpenSteamClient.PlatformSpecific; -using OpenSteamworks; -using OpenSteamworks.Callbacks; -using OpenSteamworks.Callbacks.Structs; -using OpenSteamworks.Client.Startup; -using static OpenSteamworks.Callbacks.CallbackManager; - -namespace OpenSteamClient.Views; - -public partial class HTMLSurfaceTest : Window -{ - private Controls.HTMLSurface surfaceControl; - private ISteamClient client; - public HTMLSurfaceTest() : base() - { - InitializeComponent(); - - this.client = AvaloniaApp.Container.Get(); - surfaceControl = new(); - this.FindControl("webviewContainer")!.Children.Add(surfaceControl); - - this.Closing += (object? sender, WindowClosingEventArgs e) => - { - surfaceControl.RemoveBrowser(); - }; - - this.client.CallbackManager.Register(OnHTML_ChangedTitle_t); - } - - public async Task Init(string userAgent, string url) - { - var handle = await this.surfaceControl.CreateBrowserAsync(userAgent, ""); - this.client.IClientHTMLSurface.LoadURL(handle, url, null); - } - - private void OnHTML_ChangedTitle_t(ICallbackHandler handler, HTML_ChangedTitle_t data) - { - if (surfaceControl.BrowserHandle == data.unBrowserHandle) - { - Dispatcher.UIThread.InvokeAsync(() => - { - this.Title = data.pchTitle; - }); - } - } -} diff --git a/OpenSteamClient/Views/Dialogs/PickLaunchOptionDialog.axaml b/OpenSteamClient/Views/Dialogs/PickLaunchOptionDialog.axaml deleted file mode 100644 index 3f896bfc..00000000 --- a/OpenSteamClient/Views/Dialogs/PickLaunchOptionDialog.axaml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/OpenSteamClient/Views/Library/FocusedAppPane.axaml.cs b/OpenSteamClient/Views/Library/FocusedAppPane.axaml.cs deleted file mode 100644 index 8fd02add..00000000 --- a/OpenSteamClient/Views/Library/FocusedAppPane.axaml.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; -using System.Collections.Generic; -using OpenSteamClient.Extensions; -using Avalonia.Controls; -using Avalonia.Interactivity; -using Avalonia.Markup.Xaml; -using OpenSteamClient.Controls; -using Avalonia.Media.Imaging; -using OpenSteamClient.DI; -using OpenSteamClient.ViewModels; -using OpenSteamClient.ViewModels.Library; -using OpenSteamClient.Views.Windows; -using OpenSteamworks; -using OpenSteamworks.Data.Structs; -using OpenSteamworks.Client.Apps; -using OpenSteamworks.Helpers; - -namespace OpenSteamClient.Views.Library; - -public partial class FocusedAppPane : BasePage -{ - public FocusedAppPane() : base() - { - InitializeComponent(); - this.TranslatableInit(); - } - - public void OpenSettingsForApp(object? sender, RoutedEventArgs routedEventArgs) - { - if (DataContext is not FocusedAppPaneViewModel vm) - return; - - var wnd = new AppSettingsWindow - { - DataContext = new AppSettingsWindowViewModel(AvaloniaApp.Container.Get(), vm.App) - }; - - wnd.Show(AvaloniaApp.Current!.MainWindow!); - } -} diff --git a/OpenSteamClient/Views/Pages/ConsolePage.axaml b/OpenSteamClient/Views/Pages/ConsolePage.axaml deleted file mode 100644 index 6deb88ed..00000000 --- a/OpenSteamClient/Views/Pages/ConsolePage.axaml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/OpenSteamClient/Views/Pages/LibraryPage.axaml.cs b/OpenSteamClient/Views/Pages/LibraryPage.axaml.cs deleted file mode 100644 index a7ad14d0..00000000 --- a/OpenSteamClient/Views/Pages/LibraryPage.axaml.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Collections.Generic; -using OpenSteamClient.Extensions; -using Avalonia.Controls; -using Avalonia.Markup.Xaml; -using OpenSteamClient.Controls; - -namespace OpenSteamClient.Views; - -public partial class LibraryPage : BasePage -{ - public LibraryPage() : base() - { - InitializeComponent(); - this.TranslatableInit(); - } -} \ No newline at end of file diff --git a/OpenSteamClient/Views/Pages/WebBased/CommunityPage.axaml.cs b/OpenSteamClient/Views/Pages/WebBased/CommunityPage.axaml.cs deleted file mode 100644 index 2a30bb2c..00000000 --- a/OpenSteamClient/Views/Pages/WebBased/CommunityPage.axaml.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Collections.Generic; -using OpenSteamClient.Extensions; -using Avalonia.Controls; -using Avalonia.Markup.Xaml; -using OpenSteamClient.Controls; - -namespace OpenSteamClient.Views; - -public partial class CommunityPage : BaseWebPage -{ - public CommunityPage() : base() - { - this.URL = "https://steamcommunity.com"; - this.SetSteamCookies = true; - } -} \ No newline at end of file diff --git a/OpenSteamClient/Views/Pages/WebBased/StorePage.axaml.cs b/OpenSteamClient/Views/Pages/WebBased/StorePage.axaml.cs deleted file mode 100644 index 92d2817f..00000000 --- a/OpenSteamClient/Views/Pages/WebBased/StorePage.axaml.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Collections.Generic; -using OpenSteamClient.Extensions; -using Avalonia.Controls; -using Avalonia.Markup.Xaml; -using OpenSteamClient.Controls; - -namespace OpenSteamClient.Views; - -public partial class StorePage : BaseWebPage -{ - public StorePage() : base() - { - this.URL = "https://store.steampowered.com"; - this.SetSteamCookies = true; - } -} \ No newline at end of file diff --git a/OpenSteamClient/Views/README.md b/OpenSteamClient/Views/README.md deleted file mode 100644 index f72a4016..00000000 --- a/OpenSteamClient/Views/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# Views -Views define the UI. They don't define any logic, that is driven by properties and methods in ViewModels, which all views should bind to. -In something like a login window with multiple possible "sub-views" like an account picker and credential input, you can use a property in a ViewModel to define what View should be visible. Then use a ContentControl and bind it's Content property to that ViewModel. - -# Windows vs Dialogs -Windows are non-blocking, meaning they don't prevent input to the window that summoned them. -Dialogs are blocking, until the user takes action by closing the dialog, where they will stop input to the window that summoned them. - -# I don't know where I should put my View -Just place it in the Views folder if unsure. It'll be handled when reviewing your PR, or kept there if needed. \ No newline at end of file diff --git a/OpenSteamClient/Views/Windows/AccountPickerWindow.axaml b/OpenSteamClient/Views/Windows/AccountPickerWindow.axaml deleted file mode 100644 index 0e823b87..00000000 --- a/OpenSteamClient/Views/Windows/AccountPickerWindow.axaml +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/OpenSteamClient/Views/Windows/AccountPickerWindow.axaml.cs b/OpenSteamClient/Views/Windows/AccountPickerWindow.axaml.cs deleted file mode 100644 index 00d56782..00000000 --- a/OpenSteamClient/Views/Windows/AccountPickerWindow.axaml.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.IO; -using Avalonia.Controls; -using OpenSteamClient.Extensions; -using OpenSteamClient.ViewModels; -using QRCoder; - -namespace OpenSteamClient.Views; - -public partial class AccountPickerWindow : Window -{ - public AccountPickerWindow() - { - InitializeComponent(); - this.TranslatableInit(); - } - -} \ No newline at end of file diff --git a/OpenSteamClient/Views/Windows/AppSettingsWindow.axaml b/OpenSteamClient/Views/Windows/AppSettingsWindow.axaml deleted file mode 100644 index 655af82f..00000000 --- a/OpenSteamClient/Views/Windows/AppSettingsWindow.axaml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - diff --git a/OpenSteamClient/Views/Windows/AppSettingsWindow.axaml.cs b/OpenSteamClient/Views/Windows/AppSettingsWindow.axaml.cs deleted file mode 100644 index 2a04fa89..00000000 --- a/OpenSteamClient/Views/Windows/AppSettingsWindow.axaml.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Avalonia; -using Avalonia.Controls; -using Avalonia.Markup.Xaml; -using OpenSteamworks.Client.Apps; - -namespace OpenSteamClient.Views.Windows; - -public partial class AppSettingsWindow : Window -{ - public AppSettingsWindow() - { - InitializeComponent(); - } -} - diff --git a/OpenSteamClient/Views/Windows/LoginWindow.axaml b/OpenSteamClient/Views/Windows/LoginWindow.axaml deleted file mode 100644 index 8f1b1ef9..00000000 --- a/OpenSteamClient/Views/Windows/LoginWindow.axaml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/OpenSteamClient/Views/Windows/MainWindow.axaml.cs b/OpenSteamClient/Views/Windows/MainWindow.axaml.cs deleted file mode 100644 index 6cc1856e..00000000 --- a/OpenSteamClient/Views/Windows/MainWindow.axaml.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Collections.Generic; -using OpenSteamClient.Extensions; -using Avalonia.Controls; -using Avalonia.Markup.Xaml; - -namespace OpenSteamClient.Views; - -public partial class MainWindow : Window -{ - public MainWindow() - { - InitializeComponent(); - this.TranslatableInit(); - } -} \ No newline at end of file diff --git a/OpenSteamClient/Views/Windows/ProgressWindow.axaml b/OpenSteamClient/Views/Windows/ProgressWindow.axaml deleted file mode 100644 index 4a581f24..00000000 --- a/OpenSteamClient/Views/Windows/ProgressWindow.axaml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - diff --git a/OpenSteamClient/Views/Windows/ProgressWindow.axaml.cs b/OpenSteamClient/Views/Windows/ProgressWindow.axaml.cs deleted file mode 100644 index bfb67043..00000000 --- a/OpenSteamClient/Views/Windows/ProgressWindow.axaml.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using Avalonia.Controls; -using OpenSteamClient.ViewModels; -using OpenSteamworks.Client.Utils; - -namespace OpenSteamClient.Views; - -public partial class ProgressWindow : Window -{ - public ProgressWindow(ProgressWindowViewModel vm) - { - this.DataContext = vm; - InitializeComponent(); - } - - private void Window_OnClosing(object? sender, WindowClosingEventArgs e) - { - if (this.DataContext is ProgressWindowViewModel progVm) - progVm.OnClosed?.Invoke(e); - } -} diff --git a/OpenSteamClient/Views/Windows/SettingsWindow.axaml b/OpenSteamClient/Views/Windows/SettingsWindow.axaml deleted file mode 100644 index 7a9c441f..00000000 --- a/OpenSteamClient/Views/Windows/SettingsWindow.axaml +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - -