mirror of
https://github.com/Stone-Red-Code/Decho.git
synced 2026-09-08 23:39:26 +02:00
Refactor connection logic and add ViewExtensions for cleaner data context access
This commit is contained in:
@@ -35,61 +35,10 @@ public sealed class ConnectionService : IDisposable
|
|||||||
private readonly Dictionary<string, ServerConnection> _connections = new(StringComparer.OrdinalIgnoreCase);
|
private readonly Dictionary<string, ServerConnection> _connections = new(StringComparer.OrdinalIgnoreCase);
|
||||||
internal IReadOnlyDictionary<string, ServerConnection> Connections => _connections;
|
internal IReadOnlyDictionary<string, ServerConnection> Connections => _connections;
|
||||||
|
|
||||||
public async Task<ServerModel> ConnectAsync(string serverUrl, string username, string password, bool isRegister, bool rememberMe)
|
private async Task<ServerModel> ConnectCoreAsync(ConnectDialogResult dialogResult)
|
||||||
{
|
{
|
||||||
ConnectionManager conn = new ConnectionManager();
|
ConnectionManager conn = new ConnectionManager();
|
||||||
|
|
||||||
ConnectDialogResult dialogResult = new EchoHub.Client.UI.Dialogs.ConnectDialogResult(
|
|
||||||
serverUrl, username, password, isRegister, rememberMe, null);
|
|
||||||
|
|
||||||
ConnectResult result;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
result = await conn.ConnectAsync(dialogResult, _ => { });
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
await conn.DisposeAsync();
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
LoginResponse login = result.Login;
|
|
||||||
UserModel userModel = new UserModel(login.Username, login.DisplayName ?? login.Username,
|
|
||||||
login.NicknameColor);
|
|
||||||
|
|
||||||
ObservableCollection<ChannelModel> channels = [];
|
|
||||||
ServerModel serverModel = new ServerModel(
|
|
||||||
Guid.NewGuid().ToString("N"),
|
|
||||||
new Uri(serverUrl).Host,
|
|
||||||
channels,
|
|
||||||
serverUrl,
|
|
||||||
isConnected: true,
|
|
||||||
connectedUser: login.Username);
|
|
||||||
|
|
||||||
ServerConnection serverEntry = new ServerConnection(conn, conn.Api!, serverModel, userModel);
|
|
||||||
|
|
||||||
foreach (ChannelDto ch in result.Channels)
|
|
||||||
{
|
|
||||||
ChannelModel channelModel = ChannelModelFromDto(ch);
|
|
||||||
channels.Add(channelModel);
|
|
||||||
}
|
|
||||||
|
|
||||||
WireConnectionEvents(serverEntry, conn);
|
|
||||||
|
|
||||||
_connections[serverUrl] = serverEntry;
|
|
||||||
SaveRefreshToken(serverUrl, rememberMe);
|
|
||||||
ServerAdded?.Invoke(serverModel);
|
|
||||||
|
|
||||||
return serverModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task ConnectWithSavedTokenAsync(string serverUrl, string username, string refreshToken, bool rememberMe)
|
|
||||||
{
|
|
||||||
ConnectionManager conn = new ConnectionManager();
|
|
||||||
|
|
||||||
ConnectDialogResult dialogResult = new EchoHub.Client.UI.Dialogs.ConnectDialogResult(
|
|
||||||
serverUrl, username, "", false, rememberMe, refreshToken);
|
|
||||||
|
|
||||||
ConnectResult result;
|
ConnectResult result;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -107,9 +56,9 @@ public sealed class ConnectionService : IDisposable
|
|||||||
ObservableCollection<ChannelModel> channels = [];
|
ObservableCollection<ChannelModel> channels = [];
|
||||||
ServerModel serverModel = new ServerModel(
|
ServerModel serverModel = new ServerModel(
|
||||||
Guid.NewGuid().ToString("N"),
|
Guid.NewGuid().ToString("N"),
|
||||||
new Uri(serverUrl).Host,
|
new Uri(dialogResult.ServerUrl).Host,
|
||||||
channels,
|
channels,
|
||||||
serverUrl,
|
dialogResult.ServerUrl,
|
||||||
isConnected: true,
|
isConnected: true,
|
||||||
connectedUser: login.Username);
|
connectedUser: login.Username);
|
||||||
|
|
||||||
@@ -123,16 +72,32 @@ public sealed class ConnectionService : IDisposable
|
|||||||
|
|
||||||
WireConnectionEvents(serverEntry, conn);
|
WireConnectionEvents(serverEntry, conn);
|
||||||
|
|
||||||
_connections[serverUrl] = serverEntry;
|
_connections[dialogResult.ServerUrl] = serverEntry;
|
||||||
SaveRefreshToken(serverUrl, rememberMe);
|
SaveRefreshToken(dialogResult.ServerUrl, dialogResult.RememberMe);
|
||||||
ServerAdded?.Invoke(serverModel);
|
ServerAdded?.Invoke(serverModel);
|
||||||
|
|
||||||
|
return serverModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DisconnectAsync(string serverUrl)
|
public async Task<ServerModel> ConnectAsync(string serverUrl, string username, string password, bool isRegister, bool rememberMe)
|
||||||
|
{
|
||||||
|
ConnectDialogResult dialogResult = new ConnectDialogResult(
|
||||||
|
serverUrl, username, password, isRegister, rememberMe, null);
|
||||||
|
return await ConnectCoreAsync(dialogResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task ConnectWithSavedTokenAsync(string serverUrl, string username, string refreshToken, bool rememberMe)
|
||||||
|
{
|
||||||
|
ConnectDialogResult dialogResult = new ConnectDialogResult(
|
||||||
|
serverUrl, username, "", false, rememberMe, refreshToken);
|
||||||
|
await ConnectCoreAsync(dialogResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<ServerConnection?> CleanupConnectionAsync(string serverUrl)
|
||||||
{
|
{
|
||||||
if (!_connections.TryGetValue(serverUrl, out ServerConnection? entry))
|
if (!_connections.TryGetValue(serverUrl, out ServerConnection? entry))
|
||||||
{
|
{
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
entry.Server.IsConnected = false;
|
entry.Server.IsConnected = false;
|
||||||
@@ -143,37 +108,43 @@ public sealed class ConnectionService : IDisposable
|
|||||||
await entry.Manager.DisposeAsync();
|
await entry.Manager.DisposeAsync();
|
||||||
|
|
||||||
_ = _connections.Remove(serverUrl);
|
_ = _connections.Remove(serverUrl);
|
||||||
ServerStateChanged?.Invoke(entry.Server);
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task DisconnectAsync(string serverUrl)
|
||||||
|
{
|
||||||
|
ServerConnection? entry = await CleanupConnectionAsync(serverUrl);
|
||||||
|
if (entry is not null)
|
||||||
|
{
|
||||||
|
ServerStateChanged?.Invoke(entry.Server);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task RemoveServerAsync(string serverUrl)
|
public async Task RemoveServerAsync(string serverUrl)
|
||||||
{
|
{
|
||||||
if (_connections.TryGetValue(serverUrl, out ServerConnection? entry))
|
await CleanupConnectionAsync(serverUrl);
|
||||||
{
|
|
||||||
entry.Server.IsConnected = false;
|
|
||||||
entry.Server.IsConnecting = false;
|
|
||||||
|
|
||||||
await entry.Manager.CleanupAsync();
|
|
||||||
entry.ApiClient.Dispose();
|
|
||||||
await entry.Manager.DisposeAsync();
|
|
||||||
|
|
||||||
_ = _connections.Remove(serverUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
RemoveServerFromConfig(serverUrl);
|
RemoveServerFromConfig(serverUrl);
|
||||||
ServerRemoved?.Invoke(serverUrl);
|
ServerRemoved?.Invoke(serverUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void RemoveServerFromConfig(string serverUrl)
|
private static void ModifyConfig(string serverUrl, Action<ClientConfig, SavedServer?> action)
|
||||||
{
|
{
|
||||||
ClientConfig config = ConfigManager.Load();
|
ClientConfig config = ConfigManager.Load();
|
||||||
SavedServer? saved = config.SavedServers.FirstOrDefault(s =>
|
SavedServer? saved = config.SavedServers.FirstOrDefault(s =>
|
||||||
string.Equals(s.Url, serverUrl, StringComparison.OrdinalIgnoreCase));
|
string.Equals(s.Url, serverUrl, StringComparison.OrdinalIgnoreCase));
|
||||||
if (saved is not null)
|
action(config, saved);
|
||||||
|
ConfigManager.Save(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void RemoveServerFromConfig(string serverUrl)
|
||||||
|
{
|
||||||
|
ModifyConfig(serverUrl, (config, saved) =>
|
||||||
{
|
{
|
||||||
_ = config.SavedServers.Remove(saved);
|
if (saved is not null)
|
||||||
ConfigManager.Save(config);
|
{
|
||||||
}
|
_ = config.SavedServers.Remove(saved);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task SendMessageAsync(string serverUrl, string channelName, string content)
|
public async Task SendMessageAsync(string serverUrl, string channelName, string content)
|
||||||
@@ -554,25 +525,24 @@ public sealed class ConnectionService : IDisposable
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientConfig config = ConfigManager.Load();
|
ModifyConfig(serverUrl, (config, saved) =>
|
||||||
SavedServer? saved = config.SavedServers.FirstOrDefault(s =>
|
|
||||||
string.Equals(s.Url, serverUrl, StringComparison.OrdinalIgnoreCase));
|
|
||||||
if (saved is null)
|
|
||||||
{
|
{
|
||||||
saved = new SavedServer
|
if (saved is null)
|
||||||
{
|
{
|
||||||
Name = new Uri(serverUrl).Host,
|
saved = new SavedServer
|
||||||
Url = serverUrl,
|
{
|
||||||
Username = entry.User.Id,
|
Name = new Uri(serverUrl).Host,
|
||||||
RememberMe = true,
|
Url = serverUrl,
|
||||||
LastConnected = DateTimeOffset.Now,
|
Username = entry.User.Id,
|
||||||
};
|
RememberMe = true,
|
||||||
config.SavedServers.Add(saved);
|
LastConnected = DateTimeOffset.Now,
|
||||||
}
|
};
|
||||||
|
config.SavedServers.Add(saved);
|
||||||
|
}
|
||||||
|
|
||||||
saved.RefreshToken = token;
|
saved.RefreshToken = token;
|
||||||
saved.LastConnected = DateTimeOffset.Now;
|
saved.LastConnected = DateTimeOffset.Now;
|
||||||
ConfigManager.Save(config);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WireConnectionEvents(ServerConnection entry, ConnectionManager conn)
|
private void WireConnectionEvents(ServerConnection entry, ConnectionManager conn)
|
||||||
|
|||||||
@@ -74,14 +74,7 @@ public sealed class MainWindowViewModel : ViewModelBase
|
|||||||
|
|
||||||
private async void AddServer()
|
private async void AddServer()
|
||||||
{
|
{
|
||||||
if (_mainWindow is null)
|
ConnectDialogResult? result = await ShowConnectDialogAsync(null);
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ClientConfig config = ConfigManager.Load();
|
|
||||||
ConnectDialogWindow dialog = new ConnectDialogWindow(config.SavedServers);
|
|
||||||
ConnectDialogResult? result = await dialog.ShowDialog<ConnectDialogResult?>(_mainWindow);
|
|
||||||
if (result is null)
|
if (result is null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -129,6 +122,20 @@ public sealed class MainWindowViewModel : ViewModelBase
|
|||||||
ConfigManager.SaveServer(savedServer);
|
ConfigManager.SaveServer(savedServer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<ConnectDialogResult?> ShowConnectDialogAsync(SavedServer? prefill)
|
||||||
|
{
|
||||||
|
if (_mainWindow is null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientConfig config = ConfigManager.Load();
|
||||||
|
ConnectDialogWindow dialog = prefill is null
|
||||||
|
? new ConnectDialogWindow(config.SavedServers)
|
||||||
|
: new ConnectDialogWindow(config.SavedServers, prefill);
|
||||||
|
return await dialog.ShowDialog<ConnectDialogResult?>(_mainWindow);
|
||||||
|
}
|
||||||
|
|
||||||
private void WireCommandHandlerEvents()
|
private void WireCommandHandlerEvents()
|
||||||
{
|
{
|
||||||
_commandHandler.OnSetStatus += async (status, message) =>
|
_commandHandler.OnSetStatus += async (status, message) =>
|
||||||
@@ -670,16 +677,9 @@ public sealed class MainWindowViewModel : ViewModelBase
|
|||||||
|
|
||||||
private async Task HandleServerConnectRequested(ServerViewModel serverVm)
|
private async Task HandleServerConnectRequested(ServerViewModel serverVm)
|
||||||
{
|
{
|
||||||
if (_mainWindow is null)
|
SavedServer? prefill = ConfigManager.Load().SavedServers.FirstOrDefault(s =>
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ClientConfig config = ConfigManager.Load();
|
|
||||||
SavedServer? prefill = config.SavedServers.FirstOrDefault(s =>
|
|
||||||
string.Equals(s.Url, serverVm.ServerUrl, StringComparison.OrdinalIgnoreCase));
|
string.Equals(s.Url, serverVm.ServerUrl, StringComparison.OrdinalIgnoreCase));
|
||||||
ConnectDialogWindow dialog = new ConnectDialogWindow(config.SavedServers, prefill);
|
ConnectDialogResult? result = await ShowConnectDialogAsync(prefill);
|
||||||
ConnectDialogResult? result = await dialog.ShowDialog<ConnectDialogResult?>(_mainWindow);
|
|
||||||
if (result is null)
|
if (result is null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -19,7 +19,8 @@ public partial class MessageComposerView : UserControl
|
|||||||
|
|
||||||
private async void OnFileUploadClicked(object? sender, RoutedEventArgs e)
|
private async void OnFileUploadClicked(object? sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
if (DataContext is not MessageComposerViewModel vm)
|
MessageComposerViewModel? vm = this.GetDataContext<MessageComposerViewModel>();
|
||||||
|
if (vm is null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -55,7 +56,8 @@ public partial class MessageComposerView : UserControl
|
|||||||
|
|
||||||
private void OnDrop(object? sender, DragEventArgs e)
|
private void OnDrop(object? sender, DragEventArgs e)
|
||||||
{
|
{
|
||||||
if (DataContext is not MessageComposerViewModel vm)
|
MessageComposerViewModel? vm = this.GetDataContext<MessageComposerViewModel>();
|
||||||
|
if (vm is null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,8 +44,8 @@ public partial class MessageItemView : UserControl
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
TopLevel? topLevel = TopLevel.GetTopLevel(this);
|
MainWindowViewModel? mainVm = this.GetMainWindowViewModel();
|
||||||
if (topLevel?.DataContext is not MainWindowViewModel mainVm)
|
if (mainVm is null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -73,13 +73,14 @@ public partial class MessageItemView : UserControl
|
|||||||
|
|
||||||
private async void OnAuthorNamePointerPressed(object? sender, Avalonia.Input.PointerPressedEventArgs e)
|
private async void OnAuthorNamePointerPressed(object? sender, Avalonia.Input.PointerPressedEventArgs e)
|
||||||
{
|
{
|
||||||
if (DataContext is not MessageViewModel msg)
|
MessageViewModel? msg = this.GetDataContext<MessageViewModel>();
|
||||||
|
if (msg is null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TopLevel? topLevel = TopLevel.GetTopLevel(this);
|
MainWindowViewModel? mainVm = this.GetMainWindowViewModel();
|
||||||
if (topLevel?.DataContext is not MainWindowViewModel mainVm)
|
if (mainVm is null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -94,7 +95,7 @@ public partial class MessageItemView : UserControl
|
|||||||
|
|
||||||
ProfileWindow dialog = new ProfileWindow(profile);
|
ProfileWindow dialog = new ProfileWindow(profile);
|
||||||
|
|
||||||
if (topLevel is Window parent)
|
if (TopLevel.GetTopLevel(this) is Window parent)
|
||||||
{
|
{
|
||||||
await dialog.ShowDialog(parent);
|
await dialog.ShowDialog(parent);
|
||||||
}
|
}
|
||||||
@@ -102,7 +103,8 @@ public partial class MessageItemView : UserControl
|
|||||||
|
|
||||||
private async void OnDownloadClicked(object? sender, RoutedEventArgs e)
|
private async void OnDownloadClicked(object? sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
if (DataContext is not MessageViewModel msg)
|
MessageViewModel? msg = this.GetDataContext<MessageViewModel>();
|
||||||
|
if (msg is null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -118,7 +120,8 @@ public partial class MessageItemView : UserControl
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (topLevel.DataContext is not MainWindowViewModel mainVm)
|
MainWindowViewModel? mainVm = this.GetMainWindowViewModel();
|
||||||
|
if (mainVm is null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
|
||||||
|
using Decho.ViewModels;
|
||||||
|
|
||||||
|
namespace Decho.Views;
|
||||||
|
|
||||||
|
internal static class ViewExtensions
|
||||||
|
{
|
||||||
|
public static T? GetDataContext<T>(this Control control) where T : class
|
||||||
|
=> control.DataContext as T;
|
||||||
|
|
||||||
|
public static MainWindowViewModel? GetMainWindowViewModel(this Control control)
|
||||||
|
=> TopLevel.GetTopLevel(control)?.DataContext as MainWindowViewModel;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user