diff --git a/src/Launcher/Assets/AltButtons/Discord.png b/src/Launcher/Assets/AltButtons/Discord.png new file mode 100644 index 0000000..a99b71e Binary files /dev/null and b/src/Launcher/Assets/AltButtons/Discord.png differ diff --git a/src/Launcher/Assets/AltButtons/Discord_Hover.png b/src/Launcher/Assets/AltButtons/Discord_Hover.png new file mode 100644 index 0000000..590c1a2 Binary files /dev/null and b/src/Launcher/Assets/AltButtons/Discord_Hover.png differ diff --git a/src/Launcher/Assets/AltButtons/New.png b/src/Launcher/Assets/AltButtons/New.png new file mode 100644 index 0000000..50d509d Binary files /dev/null and b/src/Launcher/Assets/AltButtons/New.png differ diff --git a/src/Launcher/Assets/AltButtons/New_Hover.png b/src/Launcher/Assets/AltButtons/New_Hover.png new file mode 100644 index 0000000..6c5507d Binary files /dev/null and b/src/Launcher/Assets/AltButtons/New_Hover.png differ diff --git a/src/Launcher/Assets/AltButtons/Reddit.png b/src/Launcher/Assets/AltButtons/Reddit.png new file mode 100644 index 0000000..dcdae6e Binary files /dev/null and b/src/Launcher/Assets/AltButtons/Reddit.png differ diff --git a/src/Launcher/Assets/AltButtons/Reddit_Hover.png b/src/Launcher/Assets/AltButtons/Reddit_Hover.png new file mode 100644 index 0000000..4df04ba Binary files /dev/null and b/src/Launcher/Assets/AltButtons/Reddit_Hover.png differ diff --git a/src/Launcher/Assets/AltButtons/Settings.png b/src/Launcher/Assets/AltButtons/Settings.png new file mode 100644 index 0000000..f575ed2 Binary files /dev/null and b/src/Launcher/Assets/AltButtons/Settings.png differ diff --git a/src/Launcher/Assets/AltButtons/Settings_Hover.png b/src/Launcher/Assets/AltButtons/Settings_Hover.png new file mode 100644 index 0000000..60bb4c8 Binary files /dev/null and b/src/Launcher/Assets/AltButtons/Settings_Hover.png differ diff --git a/src/Launcher/Assets/AltButtons/Spacer.png b/src/Launcher/Assets/AltButtons/Spacer.png new file mode 100644 index 0000000..fe032ef Binary files /dev/null and b/src/Launcher/Assets/AltButtons/Spacer.png differ diff --git a/src/Launcher/Assets/Backgrounds/Back1.png b/src/Launcher/Assets/Backgrounds/Back1.png new file mode 100644 index 0000000..e610b8c Binary files /dev/null and b/src/Launcher/Assets/Backgrounds/Back1.png differ diff --git a/src/Launcher/Assets/Backgrounds/Back10.png b/src/Launcher/Assets/Backgrounds/Back10.png new file mode 100644 index 0000000..dbdcb29 Binary files /dev/null and b/src/Launcher/Assets/Backgrounds/Back10.png differ diff --git a/src/Launcher/Assets/Backgrounds/Back11.png b/src/Launcher/Assets/Backgrounds/Back11.png new file mode 100644 index 0000000..7016717 Binary files /dev/null and b/src/Launcher/Assets/Backgrounds/Back11.png differ diff --git a/src/Launcher/Assets/Backgrounds/Back12.png b/src/Launcher/Assets/Backgrounds/Back12.png new file mode 100644 index 0000000..3c353ee Binary files /dev/null and b/src/Launcher/Assets/Backgrounds/Back12.png differ diff --git a/src/Launcher/Assets/Backgrounds/Back13.png b/src/Launcher/Assets/Backgrounds/Back13.png new file mode 100644 index 0000000..55346a1 Binary files /dev/null and b/src/Launcher/Assets/Backgrounds/Back13.png differ diff --git a/src/Launcher/Assets/Backgrounds/Back14.png b/src/Launcher/Assets/Backgrounds/Back14.png new file mode 100644 index 0000000..e77a600 Binary files /dev/null and b/src/Launcher/Assets/Backgrounds/Back14.png differ diff --git a/src/Launcher/Assets/Backgrounds/Back15.png b/src/Launcher/Assets/Backgrounds/Back15.png new file mode 100644 index 0000000..c4844f8 Binary files /dev/null and b/src/Launcher/Assets/Backgrounds/Back15.png differ diff --git a/src/Launcher/Assets/Backgrounds/Back16.png b/src/Launcher/Assets/Backgrounds/Back16.png new file mode 100644 index 0000000..b0bce72 Binary files /dev/null and b/src/Launcher/Assets/Backgrounds/Back16.png differ diff --git a/src/Launcher/Assets/Backgrounds/Back17.png b/src/Launcher/Assets/Backgrounds/Back17.png new file mode 100644 index 0000000..6e76df3 Binary files /dev/null and b/src/Launcher/Assets/Backgrounds/Back17.png differ diff --git a/src/Launcher/Assets/Backgrounds/Back18.png b/src/Launcher/Assets/Backgrounds/Back18.png new file mode 100644 index 0000000..82bdf07 Binary files /dev/null and b/src/Launcher/Assets/Backgrounds/Back18.png differ diff --git a/src/Launcher/Assets/Backgrounds/Back19.png b/src/Launcher/Assets/Backgrounds/Back19.png new file mode 100644 index 0000000..5c7f404 Binary files /dev/null and b/src/Launcher/Assets/Backgrounds/Back19.png differ diff --git a/src/Launcher/Assets/Backgrounds/Back2.png b/src/Launcher/Assets/Backgrounds/Back2.png new file mode 100644 index 0000000..abaf730 Binary files /dev/null and b/src/Launcher/Assets/Backgrounds/Back2.png differ diff --git a/src/Launcher/Assets/Backgrounds/Back20.png b/src/Launcher/Assets/Backgrounds/Back20.png new file mode 100644 index 0000000..f08214c Binary files /dev/null and b/src/Launcher/Assets/Backgrounds/Back20.png differ diff --git a/src/Launcher/Assets/Backgrounds/Back3.png b/src/Launcher/Assets/Backgrounds/Back3.png new file mode 100644 index 0000000..da9078e Binary files /dev/null and b/src/Launcher/Assets/Backgrounds/Back3.png differ diff --git a/src/Launcher/Assets/Backgrounds/Back4.png b/src/Launcher/Assets/Backgrounds/Back4.png new file mode 100644 index 0000000..9b1a7b1 Binary files /dev/null and b/src/Launcher/Assets/Backgrounds/Back4.png differ diff --git a/src/Launcher/Assets/Backgrounds/Back5.png b/src/Launcher/Assets/Backgrounds/Back5.png new file mode 100644 index 0000000..19df82f Binary files /dev/null and b/src/Launcher/Assets/Backgrounds/Back5.png differ diff --git a/src/Launcher/Assets/Backgrounds/Back6.png b/src/Launcher/Assets/Backgrounds/Back6.png new file mode 100644 index 0000000..dc6abb4 Binary files /dev/null and b/src/Launcher/Assets/Backgrounds/Back6.png differ diff --git a/src/Launcher/Assets/Backgrounds/Back7.png b/src/Launcher/Assets/Backgrounds/Back7.png new file mode 100644 index 0000000..ff08a80 Binary files /dev/null and b/src/Launcher/Assets/Backgrounds/Back7.png differ diff --git a/src/Launcher/Assets/Backgrounds/Back8.png b/src/Launcher/Assets/Backgrounds/Back8.png new file mode 100644 index 0000000..b9794db Binary files /dev/null and b/src/Launcher/Assets/Backgrounds/Back8.png differ diff --git a/src/Launcher/Assets/Backgrounds/Back9.png b/src/Launcher/Assets/Backgrounds/Back9.png new file mode 100644 index 0000000..35500bc Binary files /dev/null and b/src/Launcher/Assets/Backgrounds/Back9.png differ diff --git a/src/Launcher/Assets/Frame/Offline_Button.png b/src/Launcher/Assets/Frame/Offline_Button.png new file mode 100644 index 0000000..9f6bef0 Binary files /dev/null and b/src/Launcher/Assets/Frame/Offline_Button.png differ diff --git a/src/Launcher/Assets/Frame/Play_Button.png b/src/Launcher/Assets/Frame/Play_Button.png new file mode 100644 index 0000000..7dd3bb6 Binary files /dev/null and b/src/Launcher/Assets/Frame/Play_Button.png differ diff --git a/src/Launcher/Assets/Frame/Play_Button_Hover.png b/src/Launcher/Assets/Frame/Play_Button_Hover.png new file mode 100644 index 0000000..ffd4256 Binary files /dev/null and b/src/Launcher/Assets/Frame/Play_Button_Hover.png differ diff --git a/src/Launcher/Assets/Frame/Stop_Button.png b/src/Launcher/Assets/Frame/Stop_Button.png new file mode 100644 index 0000000..16eb6c7 Binary files /dev/null and b/src/Launcher/Assets/Frame/Stop_Button.png differ diff --git a/src/Launcher/Assets/Frame/Stop_Button_Hover.png b/src/Launcher/Assets/Frame/Stop_Button_Hover.png new file mode 100644 index 0000000..85c1363 Binary files /dev/null and b/src/Launcher/Assets/Frame/Stop_Button_Hover.png differ diff --git a/src/Launcher/Assets/Hero/OSFRLogo.png b/src/Launcher/Assets/Hero/OSFRLogo.png new file mode 100644 index 0000000..36e1e3d Binary files /dev/null and b/src/Launcher/Assets/Hero/OSFRLogo.png differ diff --git a/src/Launcher/Assets/Hero/sanctuary.jpg b/src/Launcher/Assets/Hero/sanctuary.jpg new file mode 100644 index 0000000..7b85464 Binary files /dev/null and b/src/Launcher/Assets/Hero/sanctuary.jpg differ diff --git a/src/Launcher/Assets/ServerIcons/Edit.png b/src/Launcher/Assets/ServerIcons/Edit.png new file mode 100644 index 0000000..7c83c0c Binary files /dev/null and b/src/Launcher/Assets/ServerIcons/Edit.png differ diff --git a/src/Launcher/Assets/ServerIcons/Edit_Hover.png b/src/Launcher/Assets/ServerIcons/Edit_Hover.png new file mode 100644 index 0000000..142f6d5 Binary files /dev/null and b/src/Launcher/Assets/ServerIcons/Edit_Hover.png differ diff --git a/src/Launcher/Assets/ServerIcons/Online_Status.png b/src/Launcher/Assets/ServerIcons/Online_Status.png new file mode 100644 index 0000000..9a8b11e Binary files /dev/null and b/src/Launcher/Assets/ServerIcons/Online_Status.png differ diff --git a/src/Launcher/Assets/ServerIcons/Player_Count.png b/src/Launcher/Assets/ServerIcons/Player_Count.png new file mode 100644 index 0000000..1c3d8c6 Binary files /dev/null and b/src/Launcher/Assets/ServerIcons/Player_Count.png differ diff --git a/src/Launcher/Assets/ServerIcons/Server_Icon_Blue.png b/src/Launcher/Assets/ServerIcons/Server_Icon_Blue.png new file mode 100644 index 0000000..b51386e Binary files /dev/null and b/src/Launcher/Assets/ServerIcons/Server_Icon_Blue.png differ diff --git a/src/Launcher/Assets/ServerIcons/Server_Icon_Gray.png b/src/Launcher/Assets/ServerIcons/Server_Icon_Gray.png new file mode 100644 index 0000000..2d136fd Binary files /dev/null and b/src/Launcher/Assets/ServerIcons/Server_Icon_Gray.png differ diff --git a/src/Launcher/Assets/ServerIcons/Server_Icon_Green.png b/src/Launcher/Assets/ServerIcons/Server_Icon_Green.png new file mode 100644 index 0000000..3675e56 Binary files /dev/null and b/src/Launcher/Assets/ServerIcons/Server_Icon_Green.png differ diff --git a/src/Launcher/Assets/ServerIcons/Server_Icon_Orange.png b/src/Launcher/Assets/ServerIcons/Server_Icon_Orange.png new file mode 100644 index 0000000..2e06be7 Binary files /dev/null and b/src/Launcher/Assets/ServerIcons/Server_Icon_Orange.png differ diff --git a/src/Launcher/Assets/ServerIcons/Server_Icon_Pink.png b/src/Launcher/Assets/ServerIcons/Server_Icon_Pink.png new file mode 100644 index 0000000..3302385 Binary files /dev/null and b/src/Launcher/Assets/ServerIcons/Server_Icon_Pink.png differ diff --git a/src/Launcher/Assets/ServerIcons/Server_Icon_Purple.png b/src/Launcher/Assets/ServerIcons/Server_Icon_Purple.png new file mode 100644 index 0000000..078afcc Binary files /dev/null and b/src/Launcher/Assets/ServerIcons/Server_Icon_Purple.png differ diff --git a/src/Launcher/Assets/ServerIcons/Server_Icon_Red.png b/src/Launcher/Assets/ServerIcons/Server_Icon_Red.png new file mode 100644 index 0000000..3517e73 Binary files /dev/null and b/src/Launcher/Assets/ServerIcons/Server_Icon_Red.png differ diff --git a/src/Launcher/Assets/ServerIcons/Server_Icon_Teal.png b/src/Launcher/Assets/ServerIcons/Server_Icon_Teal.png new file mode 100644 index 0000000..3bd547a Binary files /dev/null and b/src/Launcher/Assets/ServerIcons/Server_Icon_Teal.png differ diff --git a/src/Launcher/Assets/ServerIcons/Server_Icon_Yellow.png b/src/Launcher/Assets/ServerIcons/Server_Icon_Yellow.png new file mode 100644 index 0000000..0a9757b Binary files /dev/null and b/src/Launcher/Assets/ServerIcons/Server_Icon_Yellow.png differ diff --git a/src/Launcher/Assets/ServerIcons/Server_Selected.png b/src/Launcher/Assets/ServerIcons/Server_Selected.png new file mode 100644 index 0000000..f368cab Binary files /dev/null and b/src/Launcher/Assets/ServerIcons/Server_Selected.png differ diff --git a/src/Launcher/Assets/ServerIcons/Server_Spacer.png b/src/Launcher/Assets/ServerIcons/Server_Spacer.png new file mode 100644 index 0000000..6f8ceff Binary files /dev/null and b/src/Launcher/Assets/ServerIcons/Server_Spacer.png differ diff --git a/src/Launcher/Assets/ServerIcons/Server_Template.png b/src/Launcher/Assets/ServerIcons/Server_Template.png new file mode 100644 index 0000000..dae5b3d Binary files /dev/null and b/src/Launcher/Assets/ServerIcons/Server_Template.png differ diff --git a/src/Launcher/ViewModels/AddServer.cs b/src/Launcher/ViewModels/AddServer.cs index 77d4ca8..535ae62 100644 --- a/src/Launcher/ViewModels/AddServer.cs +++ b/src/Launcher/ViewModels/AddServer.cs @@ -4,6 +4,7 @@ using System.Threading.Tasks; using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; using Launcher.Extensions; using Launcher.Helpers; @@ -17,12 +18,19 @@ public partial class AddServer : Popup { private static readonly Logger _logger = LogManager.GetCurrentClassLogger(); + private readonly ServerInfo? _editingInfo; + [Required] [ObservableProperty] [NotifyDataErrorInfo] [CustomValidation(typeof(AddServer), nameof(ValidateServerUrl))] private string serverUrl = string.Empty; + [ObservableProperty] + private string serverName = string.Empty; + + public bool IsEditMode => _editingInfo is not null; + public AddServer() { View = new Views.AddServer @@ -31,6 +39,42 @@ public AddServer() }; } + public AddServer(ServerInfo info) + { + _editingInfo = info; + + ServerUrl = info.Url; + ServerName = info.Name; + + View = new Views.AddServer + { + DataContext = this + }; + } + + [RelayCommand] + public void Delete() + { + if (_editingInfo is null) + return; + + Settings.Instance.ServerInfoList.Remove(_editingInfo); + Settings.Instance.Save(); + + App.CancelPopup(); + App.AddNotification("Server deleted.", false); + } + + [RelayCommand] + public void Register() + { + if (_editingInfo is null) + return; + + App.CancelPopup(); + App.ShowPopup(new Register(_editingInfo)); + } + public static ValidationResult? ValidateServerUrl(string serverUrl, ValidationContext context) { if (string.IsNullOrWhiteSpace(serverUrl)) @@ -54,7 +98,26 @@ public override Task ProcessAsync() { ProgressDescription = App.GetText("Text.Add_Server.Loading"); - return TryAddServerAsync(ServerUrl); + return IsEditMode ? OnEditServerAsync() : TryAddServerAsync(ServerUrl); + } + + private Task OnEditServerAsync() + { + try + { + _editingInfo!.Url = ServerUrl.Trim(); + _editingInfo.Name = ServerName.Trim(); + + Settings.Instance.Save(); + + return Task.FromResult(true); + } + catch (Exception ex) + { + _logger.Error(ex, "An exception occurred while updating server."); + App.AddNotification("An error occurred while updating server.", true); + return Task.FromResult(false); + } } public static async Task TryAddServerAsync(string serverUrl) diff --git a/src/Launcher/ViewModels/Main.cs b/src/Launcher/ViewModels/Main.cs index 34a3b26..874cec4 100644 --- a/src/Launcher/ViewModels/Main.cs +++ b/src/Launcher/ViewModels/Main.cs @@ -36,6 +36,10 @@ public partial class Main : ObservableObject [ObservableProperty] private SemanticVersion version = App.CurrentVersion; + public string DisplayName => Settings.Instance.DisplayName; + + public bool IsGameRunning => Servers.Any(x => x.Process is not null); + public AvaloniaList Servers { get; } = []; public AvaloniaList Notifications { get; } = []; @@ -54,6 +58,11 @@ public Main() // Subscribe to changes in the server list from settings to keep the UI in sync. Settings.Instance.ServerInfoList.CollectionChanged += ServerInfoList_CollectionChanged; Settings.Instance.DiscordActivityChanged += (_, _) => UpdateDiscordActivity(); + Settings.Instance.PropertyChanged += (_, e) => + { + if (e.PropertyName == nameof(Settings.DisplayName)) + OnPropertyChanged(nameof(DisplayName)); + }; } private void ServerInfoList_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) @@ -85,7 +94,7 @@ public void OnLoad() _logger.Info("No servers found in settings. Adding default servers."); foreach (var defaultServerUrl in Constants.DefaultServerUrls) { - _ = AddServer.TryAddServerAsync(defaultServerUrl); + _ = ViewModels.AddServer.TryAddServerAsync(defaultServerUrl); } } @@ -107,6 +116,11 @@ public void UpdateDiscordActivity() DiscordService.UpdateActivity(details, playingOn); } + public void RefreshRuntimeState() + { + OnPropertyChanged(nameof(IsGameRunning)); + } + [RelayCommand] public Task CheckForUpdates() => App.CheckForUpdatesAsync(); @@ -122,6 +136,43 @@ public void ShowSettings() [RelayCommand] public void ShowAddServer() => App.ShowPopup(new AddServer()); + [RelayCommand] + public void AddServer() => App.ShowPopup(new AddServer()); + + public void EditServer(Server server) + { + var viewModel = new AddServer(server.Info); + App.ShowPopup(viewModel, process: false); + } + + [RelayCommand] + public async Task OpenDiscordAsync() + { + try + { + var window = App.GetWindow(); + await window.Launcher.LaunchUriAsync(new Uri("https://discord.gg/x7Xfz99Ydv")); + } + catch + { + App.AddNotification("Unable to open Discord link.", true); + } + } + + [RelayCommand] + public async Task OpenRedditAsync() + { + try + { + var window = App.GetWindow(); + await window.Launcher.LaunchUriAsync(new Uri("https://www.reddit.com/r/freerealms/")); + } + catch + { + App.AddNotification("Unable to open Reddit link.", true); + } + } + [RelayCommand] public async Task OpenLogsAsync() { diff --git a/src/Launcher/ViewModels/Register.cs b/src/Launcher/ViewModels/Register.cs index e75fe1a..9b24bee 100644 --- a/src/Launcher/ViewModels/Register.cs +++ b/src/Launcher/ViewModels/Register.cs @@ -15,7 +15,8 @@ namespace Launcher.ViewModels; public partial class Register : Popup { - private readonly Server _server; + private readonly Server? _server; + private readonly ServerInfo? _serverInfo; private readonly Logger _logger = LogManager.GetCurrentClassLogger(); [ObservableProperty] @@ -57,6 +58,20 @@ public Register(Server server) }; } + public Register(ServerInfo serverInfo) + { + _serverInfo = serverInfo; + + AddSecureWarning(); + + View = new Views.Register + { + DataContext = this + }; + } + + private ServerInfo Info => _server?.Info ?? _serverInfo!; + public static ValidationResult? ValidateConfirmPassword(string confirmPassword, ValidationContext context) { if (context.ObjectInstance is not Register register) @@ -82,7 +97,7 @@ public override async Task ProcessAsync() Password = Password }; - var baseUri = new Uri(_server.Info.WebApiUrl); + var baseUri = new Uri(Info.WebApiUrl); var registerUri = new Uri(baseUri, "register"); @@ -101,7 +116,7 @@ public override async Task ProcessAsync() { App.AddNotification("Registration failed. Please check your username and password and try again", true); - _logger.Warn("Registration failed for server: '{Name}'. API returned {StatusCode}: {Reason}.", _server.Info.Name, httpResponse.StatusCode, httpResponse.ReasonPhrase); + _logger.Warn("Registration failed for server: '{Name}'. API returned {StatusCode}: {Reason}.", Info.Name, httpResponse.StatusCode, httpResponse.ReasonPhrase); Username = string.Empty; Password = string.Empty; @@ -117,7 +132,7 @@ public override async Task ProcessAsync() { App.AddNotification("Registration failed. Please check your username and password and try again", true); - _logger.Error(ex, "An exception occurred registering on server: '{Name}'.", _server.Info.Name); + _logger.Error(ex, "An exception occurred registering on server: '{Name}'.", Info.Name); return false; } @@ -125,7 +140,7 @@ public override async Task ProcessAsync() private void AddSecureWarning() { - if (Uri.TryCreate(_server.Info.WebApiUrl, UriKind.Absolute, out var webApiUrl) + if (Uri.TryCreate(Info.WebApiUrl, UriKind.Absolute, out var webApiUrl) && webApiUrl.Scheme != Uri.UriSchemeHttps) { Warning = App.GetText("Text.Server.SecureApiWarning"); diff --git a/src/Launcher/ViewModels/Server.cs b/src/Launcher/ViewModels/Server.cs index 1b357b5..436b345 100644 --- a/src/Launcher/ViewModels/Server.cs +++ b/src/Launcher/ViewModels/Server.cs @@ -9,6 +9,8 @@ using System.Threading.Tasks; using Avalonia.Media; +using Avalonia.Media.Imaging; +using Avalonia.Platform; using Avalonia.Platform.Storage; using CommunityToolkit.Mvvm.ComponentModel; @@ -67,6 +69,17 @@ public partial class Server : ObservableObject [ObservableProperty] private ObservableStringBuilder markdownBuilder = new(); + public bool IsLocalServer => false; + + public string ProfileTitle => Info?.Name ?? "Unknown Server"; + + public string ProfileSubtitle => IsOnline ? "Online" : "Offline"; + + private static readonly IImage IconGreen = new Bitmap(AssetLoader.Open(new Uri("avares://Launcher/Assets/ServerIcons/Server_Icon_Green.png"))); + private static readonly IImage IconRed = new Bitmap(AssetLoader.Open(new Uri("avares://Launcher/Assets/ServerIcons/Server_Icon_Red.png"))); + + public IImage ServerIconSource => IsOnline ? IconGreen : IconRed; + public Server() { #if DEBUG && DESIGNMODE @@ -107,6 +120,13 @@ public void ClientProcessExited(object? sender, EventArgs e) Process = null; } + [RelayCommand] + private async Task EditAsync() + { + _main.EditServer(this); + await OnShowAsync(); + } + [RelayCommand] private async Task OpenUriAsync(LinkClickedEventArgs args) { diff --git a/src/Launcher/ViewModels/Settings.cs b/src/Launcher/ViewModels/Settings.cs index fdcc773..3d7b5ca 100644 --- a/src/Launcher/ViewModels/Settings.cs +++ b/src/Launcher/ViewModels/Settings.cs @@ -34,6 +34,9 @@ public partial class Settings : ObservableObject [ObservableProperty] private LocaleType locale = LocaleType.en_US; + [ObservableProperty] + private string displayName = "User"; + [ObservableProperty] private AvaloniaList serverInfoList = []; @@ -71,6 +74,9 @@ public void Save() partial void OnLocaleChanged(LocaleType value) => LocaleChanged?.Invoke(this, EventArgs.Empty); + partial void OnDisplayNameChanged(string value) + => Save(); + partial void OnDiscordActivityChanged(bool value) { if (value) diff --git a/src/Launcher/Views/AddServer.axaml b/src/Launcher/Views/AddServer.axaml index 37dbad2..34b558d 100644 --- a/src/Launcher/Views/AddServer.axaml +++ b/src/Launcher/Views/AddServer.axaml @@ -11,7 +11,7 @@ x:DataType="vm:AddServer" mc:Ignorable="d"> - + - + @@ -41,12 +41,36 @@ Text="{Binding ServerUrl, Mode=TwoWay}" /> + + + + + + + + + + + - + ColumnDefinitions="Auto,Auto,Auto,Auto"> + + + + \ No newline at end of file diff --git a/src/Launcher/Views/Main.axaml b/src/Launcher/Views/Main.axaml index 57cb936..9520d13 100644 --- a/src/Launcher/Views/Main.axaml +++ b/src/Launcher/Views/Main.axaml @@ -2,325 +2,401 @@ - - - - + + + + + + + + + + + + + + + + + - + + + + + + + - - + + + + - - + + + + + + + + - - + + + + + + + + + + + - - + + - - + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - + + + + + - - + - - + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - + - - + - - + + + + + + + + + + + + + + + + + + + + + + - \ No newline at end of file + diff --git a/src/Launcher/Views/Main.axaml.cs b/src/Launcher/Views/Main.axaml.cs index 026c92d..c17de0a 100644 --- a/src/Launcher/Views/Main.axaml.cs +++ b/src/Launcher/Views/Main.axaml.cs @@ -1,8 +1,13 @@ +using System; using System.Linq; +using System.Runtime.InteropServices; using Avalonia.Controls; using Avalonia.Input; using Avalonia.Interactivity; +using Avalonia.Media; +using Avalonia.Media.Imaging; +using Avalonia.Platform; namespace Launcher.Views; @@ -15,11 +20,96 @@ public Main() DataContext = ViewModel; InitializeComponent(); + + PlayButtonHost.PointerEntered += (_, _) => UpdatePlayButtonImage(isHovered: true); + PlayButtonHost.PointerExited += (_, _) => UpdatePlayButtonImage(isHovered: false); + + SetupSidebarIcon(NewServerButton, NewServerIcon, "New"); + SetupSidebarIcon(SettingsButton, SettingsIcon, "Settings"); + SetupSidebarIcon(DiscordButton, DiscordIcon, "Discord"); + SetupSidebarIcon(RedditButton, RedditIcon, "Reddit"); + + ViewModel.PropertyChanged += (_, e) => + { + UpdatePlayButtonImage(isHovered: false); + }; } protected override void OnLoaded(RoutedEventArgs e) { ViewModel.OnLoad(); + SetRandomBackground(); + UpdatePlayButtonImage(isHovered: false); + } + + protected override void OnOpened(EventArgs e) + { + base.OnOpened(e); + DisableMaximizeButton(); + } + + private void DisableMaximizeButton() + { + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + return; + + if (TryGetPlatformHandle()?.Handle is not { } hwnd || hwnd == IntPtr.Zero) + return; + + const int GWL_STYLE = -16; + const int WS_MAXIMIZEBOX = 0x00010000; + + var style = GetWindowLong(hwnd, GWL_STYLE); + SetWindowLong(hwnd, GWL_STYLE, style & ~WS_MAXIMIZEBOX); + + const uint SWP_NOSIZE = 0x0001; + const uint SWP_NOMOVE = 0x0002; + const uint SWP_NOZORDER = 0x0004; + const uint SWP_FRAMECHANGED = 0x0020; + + SetWindowPos(hwnd, IntPtr.Zero, 0, 0, 0, 0, + SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED); + } + + [DllImport("user32.dll", EntryPoint = "GetWindowLongW")] + private static extern int GetWindowLong(IntPtr hWnd, int nIndex); + + [DllImport("user32.dll", EntryPoint = "SetWindowLongW")] + private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong); + + [DllImport("user32.dll")] + private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, + int x, int y, int cx, int cy, uint uFlags); + + private void SetupSidebarIcon(Button button, Image icon, string name) + { + icon.Source = LoadAltButton(name, hovered: false); + button.PointerEntered += (_, _) => icon.Source = LoadAltButton(name, hovered: true); + button.PointerExited += (_, _) => icon.Source = LoadAltButton(name, hovered: false); + } + + private static Bitmap LoadAltButton(string name, bool hovered) + { + var file = hovered ? $"{name}_Hover.png" : $"{name}.png"; + + return new Bitmap(AssetLoader.Open( + new Uri($"avares://Launcher/Assets/AltButtons/{file}"))); + } + + private void UpdatePlayButtonImage(bool isHovered) + { + var name = isHovered ? "Play_Button_Hover.png" : "Play_Button.png"; + + PlayButtonImage.Source = new Bitmap(AssetLoader.Open( + new Uri($"avares://Launcher/Assets/Frame/{name}"))); + } + + private void SetRandomBackground() + { + var index = Random.Shared.Next(1, 21); + var uri = new Uri($"avares://Launcher/Assets/Backgrounds/Back{index}.png"); + using var stream = AssetLoader.Open(uri); + HeroGrid.Background = new ImageBrush(new Bitmap(stream)) { Stretch = Stretch.UniformToFill }; } protected override void OnClosing(WindowClosingEventArgs e) diff --git a/src/Launcher/Views/Settings.axaml b/src/Launcher/Views/Settings.axaml index 14c7309..ad801c0 100644 --- a/src/Launcher/Views/Settings.axaml +++ b/src/Launcher/Views/Settings.axaml @@ -10,10 +10,10 @@ xmlns:vm="using:Launcher.ViewModels" Title="{StaticResource Text.Settings}" Width="400" - Height="220" + Height="250" MinWidth="400" - MinHeight="220" - d:DesignHeight="220" + MinHeight="250" + d:DesignHeight="250" d:DesignWidth="400" x:DataType="vm:Settings" Background="{StaticResource Color.Window}" @@ -22,29 +22,63 @@ WindowStartupLocation="CenterScreen" mc:Ignorable="d"> + + + + + + + RowDefinitions="30,30,30,40,40"> + + + + + - - - - - -