mirror of
https://github.com/Stone-Red-Code/Decho.git
synced 2026-09-04 00:46:11 +02:00
Replace ConnectDialog with ConnectDialogWindow and move UI to XAML
This commit is contained in:
@@ -634,9 +634,8 @@ public sealed class MainWindowViewModel : ViewModelBase
|
||||
ClientConfig config = ConfigManager.Load();
|
||||
SavedServer? prefill = config.SavedServers.FirstOrDefault(s =>
|
||||
string.Equals(s.Url, serverVm.ServerUrl, StringComparison.OrdinalIgnoreCase));
|
||||
ConnectDialog dialog = new ConnectDialog(config.SavedServers, prefill);
|
||||
|
||||
ConnectDialogResult? result = await dialog.ShowAsync(_mainWindow);
|
||||
ConnectDialogWindow dialog = new ConnectDialogWindow(config.SavedServers, prefill);
|
||||
ConnectDialogResult? result = await dialog.ShowDialog<ConnectDialogResult?>(_mainWindow);
|
||||
if (result is null)
|
||||
{
|
||||
return;
|
||||
@@ -754,228 +753,3 @@ public sealed class MainWindowViewModel : ViewModelBase
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ConnectDialogResult
|
||||
{
|
||||
public string ServerUrl { get; set; } = string.Empty;
|
||||
public string Username { get; set; } = string.Empty;
|
||||
public string Password { get; set; } = string.Empty;
|
||||
public bool IsRegister { get; set; }
|
||||
public bool RememberMe { get; set; }
|
||||
public bool IsSavedSession { get; set; }
|
||||
public string? SavedRefreshToken { get; set; }
|
||||
}
|
||||
|
||||
public sealed class ConnectDialog(List<SavedServer> savedServers, SavedServer? prefill = null)
|
||||
{
|
||||
private readonly List<SavedServer> _savedServers = savedServers;
|
||||
private readonly SavedServer? _prefill = prefill;
|
||||
|
||||
public async Task<ConnectDialogResult?> ShowAsync(Window owner)
|
||||
{
|
||||
Window dialog = new Window
|
||||
{
|
||||
Title = "Connect to Server",
|
||||
Width = 450,
|
||||
Height = 380,
|
||||
WindowStartupLocation = WindowStartupLocation.CenterOwner,
|
||||
CanResize = false,
|
||||
};
|
||||
|
||||
StackPanel stack = new StackPanel { Spacing = 8, Margin = new Avalonia.Thickness(15) };
|
||||
|
||||
TextBlock urlLabel = new TextBlock { Text = "Server URL:" };
|
||||
TextBox urlBox = new TextBox { Watermark = "http://localhost:5000", Text = "http://localhost:5000" };
|
||||
stack.Children.Add(urlLabel);
|
||||
stack.Children.Add(urlBox);
|
||||
|
||||
TextBlock userLabel = new TextBlock { Text = "Username:" };
|
||||
TextBox userBox = new TextBox { Watermark = "username" };
|
||||
stack.Children.Add(userLabel);
|
||||
stack.Children.Add(userBox);
|
||||
|
||||
TextBlock passLabel = new TextBlock { Text = "Password:" };
|
||||
TextBox passBox = new TextBox { Watermark = "password", PasswordChar = '*' };
|
||||
stack.Children.Add(passLabel);
|
||||
stack.Children.Add(passBox);
|
||||
|
||||
CheckBox rememberMe = new CheckBox { Content = "Remember me", IsChecked = true };
|
||||
stack.Children.Add(rememberMe);
|
||||
|
||||
StackPanel buttonPanel = new StackPanel { Orientation = Avalonia.Layout.Orientation.Horizontal, HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center, Spacing = 10 };
|
||||
|
||||
Button loginBtn = new Button { Content = "Login", Width = 100 };
|
||||
Button registerBtn = new Button { Content = "Register", Width = 100 };
|
||||
Button cancelBtn = new Button { Content = "Cancel", Width = 100 };
|
||||
buttonPanel.Children.Add(loginBtn);
|
||||
buttonPanel.Children.Add(registerBtn);
|
||||
buttonPanel.Children.Add(cancelBtn);
|
||||
stack.Children.Add(buttonPanel);
|
||||
|
||||
ListBox? serversList = null;
|
||||
if (_savedServers.Count > 0)
|
||||
{
|
||||
TextBlock sep = new TextBlock { Text = "--- Saved Servers ---", HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center };
|
||||
stack.Children.Add(sep);
|
||||
|
||||
serversList = new ListBox
|
||||
{
|
||||
Height = 100,
|
||||
ItemsSource = _savedServers.Select(s => $"{s.Name} ({s.Url}) - {s.Username ?? "?"}").ToList()
|
||||
};
|
||||
stack.Children.Add(serversList);
|
||||
|
||||
serversList.SelectionChanged += (_, _) =>
|
||||
{
|
||||
int idx = serversList.SelectedIndex;
|
||||
if (idx >= 0 && idx < _savedServers.Count)
|
||||
{
|
||||
SavedServer s = _savedServers[idx];
|
||||
urlBox.Text = s.Url;
|
||||
userBox.Text = s.Username ?? "";
|
||||
rememberMe.IsChecked = s.RememberMe;
|
||||
if (!string.IsNullOrEmpty(s.RefreshToken))
|
||||
{
|
||||
passBox.Text = "";
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (_prefill is not null)
|
||||
{
|
||||
urlBox.Text = _prefill.Url;
|
||||
userBox.Text = _prefill.Username ?? "";
|
||||
int idx = _savedServers.FindIndex(s =>
|
||||
string.Equals(s.Url, _prefill.Url, StringComparison.OrdinalIgnoreCase));
|
||||
if (idx >= 0 && idx < _savedServers.Count && serversList is not null)
|
||||
{
|
||||
serversList.SelectedIndex = idx;
|
||||
}
|
||||
}
|
||||
|
||||
dialog.Content = new ScrollViewer { Content = stack };
|
||||
|
||||
TaskCompletionSource<ConnectDialogResult?> tcs = new TaskCompletionSource<ConnectDialogResult?>();
|
||||
ConnectDialogResult? result = null;
|
||||
|
||||
loginBtn.Click += async (_, _) =>
|
||||
{
|
||||
string url = urlBox.Text?.Trim() ?? "";
|
||||
string user = userBox.Text?.Trim() ?? "";
|
||||
string pass = passBox.Text ?? "";
|
||||
|
||||
if (string.IsNullOrEmpty(url) || string.IsNullOrEmpty(user))
|
||||
{
|
||||
await ShowMessageBox(owner, "Validation", "Server URL and username are required.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for saved session
|
||||
SavedServer? saved = _savedServers.FirstOrDefault(s =>
|
||||
string.Equals(s.Url, url, StringComparison.OrdinalIgnoreCase) &&
|
||||
string.Equals(s.Username, user, StringComparison.OrdinalIgnoreCase) &&
|
||||
!string.IsNullOrEmpty(s.RefreshToken));
|
||||
|
||||
if (string.IsNullOrEmpty(pass) && saved is not null)
|
||||
{
|
||||
result = new ConnectDialogResult
|
||||
{
|
||||
ServerUrl = url,
|
||||
Username = user,
|
||||
IsSavedSession = true,
|
||||
SavedRefreshToken = saved.RefreshToken,
|
||||
RememberMe = saved.RememberMe,
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
if (string.IsNullOrEmpty(pass))
|
||||
{
|
||||
await ShowMessageBox(owner, "Validation", "Password is required.");
|
||||
return;
|
||||
}
|
||||
|
||||
result = new ConnectDialogResult
|
||||
{
|
||||
ServerUrl = url,
|
||||
Username = user,
|
||||
Password = pass,
|
||||
IsRegister = false,
|
||||
RememberMe = rememberMe.IsChecked ?? false,
|
||||
};
|
||||
}
|
||||
|
||||
dialog.Close();
|
||||
_ = tcs.TrySetResult(result);
|
||||
};
|
||||
|
||||
registerBtn.Click += (_, _) =>
|
||||
{
|
||||
string url = urlBox.Text?.Trim() ?? "";
|
||||
string user = userBox.Text?.Trim() ?? "";
|
||||
string pass = passBox.Text ?? "";
|
||||
|
||||
if (string.IsNullOrEmpty(url) || string.IsNullOrEmpty(user) || string.IsNullOrEmpty(pass))
|
||||
{
|
||||
_ = ShowMessageBox(owner, "Validation", "Server URL, username, and password are required.");
|
||||
return;
|
||||
}
|
||||
|
||||
result = new ConnectDialogResult
|
||||
{
|
||||
ServerUrl = url,
|
||||
Username = user,
|
||||
Password = pass,
|
||||
IsRegister = true,
|
||||
RememberMe = rememberMe.IsChecked ?? false,
|
||||
};
|
||||
|
||||
dialog.Close();
|
||||
_ = tcs.TrySetResult(result);
|
||||
};
|
||||
|
||||
cancelBtn.Click += (_, _) =>
|
||||
{
|
||||
dialog.Close();
|
||||
_ = tcs.TrySetResult(null);
|
||||
};
|
||||
|
||||
dialog.Closed += (_, _) => tcs.TrySetResult(result);
|
||||
|
||||
if (owner is not null)
|
||||
{
|
||||
await dialog.ShowDialog(owner);
|
||||
}
|
||||
else
|
||||
{
|
||||
dialog.Show();
|
||||
}
|
||||
|
||||
return await tcs.Task;
|
||||
}
|
||||
|
||||
private static async Task ShowMessageBox(Window owner, 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(owner);
|
||||
await tcs.Task;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<Window xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
mc:Ignorable="d"
|
||||
x:Class="Decho.Views.ConnectDialogWindow"
|
||||
Title="Connect to Server"
|
||||
Width="400"
|
||||
MinWidth="400"
|
||||
MinHeight="300"
|
||||
SizeToContent="Height"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
CanResize="False"
|
||||
Icon="/Assets/avalonia-logo.ico">
|
||||
<Border Padding="15">
|
||||
<StackPanel Spacing="8">
|
||||
<TextBlock Text="Server URL:" FontWeight="SemiBold" />
|
||||
<TextBox x:Name="UrlBox" Watermark="http://localhost:5000" />
|
||||
|
||||
<TextBlock Text="Username:" FontWeight="SemiBold" />
|
||||
<TextBox x:Name="UserBox" Watermark="username" />
|
||||
|
||||
<TextBlock Text="Password:" FontWeight="SemiBold" />
|
||||
<TextBox x:Name="PassBox" Watermark="password" PasswordChar="*" />
|
||||
|
||||
<CheckBox x:Name="RememberCheck" Content="Remember me" IsChecked="True" />
|
||||
|
||||
<StackPanel Orientation="Horizontal"
|
||||
HorizontalAlignment="Center"
|
||||
Spacing="10"
|
||||
Margin="0 4 0 0">
|
||||
<Button Content="Login" Width="90" Click="OnLoginClick" />
|
||||
<Button Content="Register" Width="90" Click="OnRegisterClick" />
|
||||
<Button Content="Cancel" Width="90" Click="OnCancelClick" />
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock x:Name="SavedHeader"
|
||||
Text="--- Saved Servers ---"
|
||||
HorizontalAlignment="Center"
|
||||
IsVisible="False" />
|
||||
<ListBox x:Name="ServersList"
|
||||
Height="120"
|
||||
IsVisible="False" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Window>
|
||||
@@ -0,0 +1,170 @@
|
||||
using Avalonia.Controls;
|
||||
|
||||
using EchoHub.Client.Config;
|
||||
|
||||
using System.Linq;
|
||||
|
||||
namespace Decho.Views;
|
||||
|
||||
public sealed partial class ConnectDialogWindow : Window
|
||||
{
|
||||
private readonly List<SavedServer> _savedServers;
|
||||
|
||||
public ConnectDialogWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
_savedServers = [];
|
||||
}
|
||||
|
||||
public ConnectDialogWindow(List<SavedServer> savedServers, SavedServer? prefill)
|
||||
{
|
||||
InitializeComponent();
|
||||
_savedServers = savedServers;
|
||||
|
||||
if (savedServers.Count > 0)
|
||||
{
|
||||
SavedHeader.IsVisible = true;
|
||||
ServersList.IsVisible = true;
|
||||
ServersList.ItemsSource = savedServers.Select(s =>
|
||||
$"{s.Name} ({s.Url}) - {s.Username ?? "?"}").ToList();
|
||||
|
||||
ServersList.SelectionChanged += (_, _) =>
|
||||
{
|
||||
int idx = ServersList.SelectedIndex;
|
||||
if (idx >= 0 && idx < savedServers.Count)
|
||||
{
|
||||
SavedServer s = savedServers[idx];
|
||||
UrlBox.Text = s.Url;
|
||||
UserBox.Text = s.Username ?? "";
|
||||
RememberCheck.IsChecked = s.RememberMe;
|
||||
if (!string.IsNullOrEmpty(s.RefreshToken))
|
||||
{
|
||||
PassBox.Text = "";
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (prefill is not null)
|
||||
{
|
||||
UrlBox.Text = prefill.Url;
|
||||
UserBox.Text = prefill.Username ?? "";
|
||||
int idx = savedServers.FindIndex(s =>
|
||||
string.Equals(s.Url, prefill.Url, StringComparison.OrdinalIgnoreCase));
|
||||
if (idx >= 0)
|
||||
{
|
||||
ServersList.SelectedIndex = idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnLoginClick(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
|
||||
{
|
||||
string url = UrlBox.Text?.Trim() ?? "";
|
||||
string user = UserBox.Text?.Trim() ?? "";
|
||||
string pass = PassBox.Text ?? "";
|
||||
|
||||
if (string.IsNullOrEmpty(url) || string.IsNullOrEmpty(user))
|
||||
{
|
||||
await ShowMessageBox("Validation", "Server URL and username are required.");
|
||||
return;
|
||||
}
|
||||
|
||||
SavedServer? saved = _savedServers.FirstOrDefault(s =>
|
||||
string.Equals(s.Url, url, StringComparison.OrdinalIgnoreCase) &&
|
||||
string.Equals(s.Username, user, StringComparison.OrdinalIgnoreCase) &&
|
||||
!string.IsNullOrEmpty(s.RefreshToken));
|
||||
|
||||
if (string.IsNullOrEmpty(pass) && saved is not null)
|
||||
{
|
||||
Close(new ConnectDialogResult
|
||||
{
|
||||
ServerUrl = url,
|
||||
Username = user,
|
||||
IsSavedSession = true,
|
||||
SavedRefreshToken = saved.RefreshToken,
|
||||
RememberMe = saved.RememberMe,
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
if (string.IsNullOrEmpty(pass))
|
||||
{
|
||||
await ShowMessageBox("Validation", "Password is required.");
|
||||
return;
|
||||
}
|
||||
|
||||
Close(new ConnectDialogResult
|
||||
{
|
||||
ServerUrl = url,
|
||||
Username = user,
|
||||
Password = pass,
|
||||
IsRegister = false,
|
||||
RememberMe = RememberCheck.IsChecked ?? false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void OnRegisterClick(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
|
||||
{
|
||||
string url = UrlBox.Text?.Trim() ?? "";
|
||||
string user = UserBox.Text?.Trim() ?? "";
|
||||
string pass = PassBox.Text ?? "";
|
||||
|
||||
if (string.IsNullOrEmpty(url) || string.IsNullOrEmpty(user) || string.IsNullOrEmpty(pass))
|
||||
{
|
||||
_ = ShowMessageBox("Validation", "Server URL, username, and password are required.");
|
||||
return;
|
||||
}
|
||||
|
||||
Close(new ConnectDialogResult
|
||||
{
|
||||
ServerUrl = url,
|
||||
Username = user,
|
||||
Password = pass,
|
||||
IsRegister = true,
|
||||
RememberMe = RememberCheck.IsChecked ?? false,
|
||||
});
|
||||
}
|
||||
|
||||
private void OnCancelClick(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
|
||||
{
|
||||
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
|
||||
{
|
||||
public string ServerUrl { get; set; } = string.Empty;
|
||||
public string Username { get; set; } = string.Empty;
|
||||
public string Password { get; set; } = string.Empty;
|
||||
public bool IsRegister { get; set; }
|
||||
public bool RememberMe { get; set; }
|
||||
public bool IsSavedSession { get; set; }
|
||||
public string? SavedRefreshToken { get; set; }
|
||||
}
|
||||
Reference in New Issue
Block a user