Add MessageBox.Avalonia and show error dialog on connection failure

This commit is contained in:
Stone_Red
2026-07-16 00:55:26 +02:00
parent 24b9e8ab71
commit 39c7fe4f48
3 changed files with 71 additions and 72 deletions
+1
View File
@@ -23,6 +23,7 @@
<IncludeAssets Condition="'$(Configuration)' != 'Debug'">None</IncludeAssets>
<PrivateAssets Condition="'$(Configuration)' != 'Debug'">All</PrivateAssets>
</PackageReference>
<PackageReference Include="MessageBox.Avalonia" Version="3.2.0" />
<PackageReference Include="Projektanker.Icons.Avalonia.FontAwesome" Version="9.6.2" />
<PackageReference Include="ReactiveUI.Avalonia" Version="11.3.8" />
<PackageReference Include="Romzetron.Avalonia" Version="11.3.4" />
+59 -42
View File
@@ -10,6 +10,9 @@ using EchoHub.Core.Constants;
using EchoHub.Core.DTOs;
using EchoHub.Core.Models;
using MsBox.Avalonia;
using MsBox.Avalonia.Enums;
using System.Reactive;
using System.Reactive.Linq;
@@ -69,21 +72,61 @@ public sealed class MainWindowViewModel : ViewModelBase
ConnectionService.Dispose();
}
private void AddServer()
private async void AddServer()
{
ServerModel placeholderServer = new ServerModel(
Guid.NewGuid().ToString("N"),
"New Server",
[],
isConnected: false);
if (_mainWindow is null)
{
return;
}
ServerViewModel serverVm = new ServerViewModel(placeholderServer);
serverVm.ConnectRequested += async () => await HandleServerConnectRequested(serverVm);
serverVm.DisconnectRequested += async () => await HandleServerDisconnectRequested(serverVm);
serverVm.RemoveRequested += async () => await HandleServerRemoveRequested(serverVm);
ClientConfig config = ConfigManager.Load();
ConnectDialogWindow dialog = new ConnectDialogWindow(config.SavedServers);
ConnectDialogResult? result = await dialog.ShowDialog<ConnectDialogResult?>(_mainWindow);
if (result is null)
{
return;
}
Sidebar.Servers.Add(serverVm);
StatusText = "Click Connect on the server to get started";
try
{
await ConnectAndSaveAsync(result);
}
catch (Exception ex)
{
var box = MessageBoxManager.GetMessageBoxStandard(
"Connection Failed",
$"Could not connect to server:\n{ex.Message}",
ButtonEnum.Ok);
await box.ShowWindowDialogAsync(_mainWindow);
}
}
private async Task ConnectAndSaveAsync(ConnectDialogResult result)
{
StatusText = "Connecting...";
if (result.IsSavedSession && result.SavedRefreshToken is not null)
{
await ConnectionService.ConnectWithSavedTokenAsync(
result.ServerUrl, result.Username, result.SavedRefreshToken, result.RememberMe);
}
else
{
_ = await ConnectionService.ConnectAsync(
result.ServerUrl, result.Username, result.Password, result.IsRegister, result.RememberMe);
}
string? refreshToken = ConnectionService.GetRefreshToken(result.ServerUrl);
SavedServer savedServer = new SavedServer
{
Name = new Uri(result.ServerUrl).Host,
Url = result.ServerUrl,
Username = result.Username,
RefreshToken = result.RememberMe ? refreshToken : null,
RememberMe = result.RememberMe,
LastConnected = DateTimeOffset.Now,
};
ConfigManager.SaveServer(savedServer);
}
private void WireCommandHandlerEvents()
@@ -397,13 +440,15 @@ public sealed class MainWindowViewModel : ViewModelBase
Avalonia.Threading.Dispatcher.UIThread.Post(() =>
{
int insertIndex = Sidebar.Servers.Count;
ServerViewModel? existing = Sidebar.GetServer(server.ServerUrl);
if (existing is not null)
{
insertIndex = Sidebar.Servers.IndexOf(existing);
_ = Sidebar.Servers.Remove(existing);
}
Sidebar.Servers.Add(serverVm);
Sidebar.Servers.Insert(insertIndex, serverVm);
if (serverVm.Channels.Count > 0)
{
serverVm.SelectedChannel = serverVm.Channels[0];
@@ -625,7 +670,6 @@ public sealed class MainWindowViewModel : ViewModelBase
private async Task HandleServerConnectRequested(ServerViewModel serverVm)
{
// Show connect dialog
if (_mainWindow is null)
{
return;
@@ -644,34 +688,7 @@ public sealed class MainWindowViewModel : ViewModelBase
try
{
serverVm.IsConnecting = true;
StatusText = "Connecting...";
if (result.IsSavedSession && result.SavedRefreshToken is not null)
{
await ConnectionService.ConnectWithSavedTokenAsync(
result.ServerUrl, result.Username, result.SavedRefreshToken, result.RememberMe);
}
else
{
_ = await ConnectionService.ConnectAsync(
result.ServerUrl, result.Username, result.Password, result.IsRegister, result.RememberMe);
}
// Remove the placeholder and let the real server added event handle it
Sidebar.RemoveServer(serverVm.ServerUrl);
// Save to config with refresh token
string? refreshToken = ConnectionService.GetRefreshToken(result.ServerUrl);
SavedServer savedServer = new SavedServer
{
Name = new Uri(result.ServerUrl).Host,
Url = result.ServerUrl,
Username = result.Username,
RefreshToken = result.RememberMe ? refreshToken : null,
RememberMe = result.RememberMe,
LastConnected = DateTimeOffset.Now,
};
ConfigManager.SaveServer(savedServer);
await ConnectAndSaveAsync(result);
}
catch (Exception ex)
{
+11 -30
View File
@@ -2,6 +2,9 @@ using Avalonia.Controls;
using EchoHub.Client.Config;
using MsBox.Avalonia;
using MsBox.Avalonia.Enums;
using System.Linq;
namespace Decho.Views;
@@ -16,7 +19,7 @@ public sealed partial class ConnectDialogWindow : Window
_savedServers = [];
}
public ConnectDialogWindow(List<SavedServer> savedServers, SavedServer? prefill)
public ConnectDialogWindow(List<SavedServer> savedServers, SavedServer? prefill = null)
{
InitializeComponent();
_savedServers = savedServers;
@@ -66,7 +69,8 @@ public sealed partial class ConnectDialogWindow : Window
if (string.IsNullOrEmpty(url) || string.IsNullOrEmpty(user))
{
await ShowMessageBox("Validation", "Server URL and username are required.");
var box = MessageBoxManager.GetMessageBoxStandard("Validation", "Server URL and username are required.", ButtonEnum.Ok);
await box.ShowWindowDialogAsync(this);
return;
}
@@ -90,7 +94,8 @@ public sealed partial class ConnectDialogWindow : Window
{
if (string.IsNullOrEmpty(pass))
{
await ShowMessageBox("Validation", "Password is required.");
var box = MessageBoxManager.GetMessageBoxStandard("Validation", "Password is required.", ButtonEnum.Ok);
await box.ShowWindowDialogAsync(this);
return;
}
@@ -105,7 +110,7 @@ public sealed partial class ConnectDialogWindow : Window
}
}
private void OnRegisterClick(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
private async void OnRegisterClick(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
{
string url = UrlBox.Text?.Trim() ?? "";
string user = UserBox.Text?.Trim() ?? "";
@@ -113,7 +118,8 @@ public sealed partial class ConnectDialogWindow : Window
if (string.IsNullOrEmpty(url) || string.IsNullOrEmpty(user) || string.IsNullOrEmpty(pass))
{
_ = ShowMessageBox("Validation", "Server URL, username, and password are required.");
var box = MessageBoxManager.GetMessageBoxStandard("Validation", "Server URL, username, and password are required.", ButtonEnum.Ok);
await box.ShowWindowDialogAsync(this);
return;
}
@@ -131,31 +137,6 @@ public sealed partial class ConnectDialogWindow : Window
{
Close(null);
}
private async Task ShowMessageBox(string title, string message)
{
Window msgBox = new Window
{
Title = title,
Width = 350,
Height = 150,
WindowStartupLocation = WindowStartupLocation.CenterOwner,
CanResize = false,
};
StackPanel stack = new StackPanel { Spacing = 10, Margin = new Avalonia.Thickness(15) };
stack.Children.Add(new TextBlock { Text = message, TextWrapping = Avalonia.Media.TextWrapping.Wrap });
Button okBtn = new Button { Content = "OK", HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center };
stack.Children.Add(okBtn);
msgBox.Content = stack;
TaskCompletionSource tcs = new TaskCompletionSource();
okBtn.Click += (_, _) => { msgBox.Close(); _ = tcs.TrySetResult(); };
msgBox.Closed += (_, _) => tcs.TrySetResult();
await msgBox.ShowDialog(this);
await tcs.Task;
}
}
public sealed class ConnectDialogResult