mirror of
https://github.com/Stone-Red-Code/Decho.git
synced 2026-09-04 08:56:14 +02:00
Add user profile dialog
This commit is contained in:
@@ -347,6 +347,16 @@ public sealed class ConnectionService : IDisposable
|
|||||||
_ = await entry.ApiClient.UpdateProfileAsync(new UpdateProfileRequest(displayName, bio, nickColor));
|
_ = await entry.ApiClient.UpdateProfileAsync(new UpdateProfileRequest(displayName, bio, nickColor));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<UserProfileDto?> GetUserProfileAsync(string serverUrl, string username)
|
||||||
|
{
|
||||||
|
if (!_connections.TryGetValue(serverUrl, out ServerConnection? entry))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return await entry.ApiClient.GetUserProfileAsync(username);
|
||||||
|
}
|
||||||
|
|
||||||
public async Task SetAvatarAsync(string serverUrl, string target)
|
public async Task SetAvatarAsync(string serverUrl, string target)
|
||||||
{
|
{
|
||||||
if (!_connections.TryGetValue(serverUrl, out ServerConnection? entry))
|
if (!_connections.TryGetValue(serverUrl, out ServerConnection? entry))
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ using Avalonia.Controls;
|
|||||||
|
|
||||||
using Decho.Models;
|
using Decho.Models;
|
||||||
using Decho.Services;
|
using Decho.Services;
|
||||||
|
using Decho.Views;
|
||||||
|
|
||||||
using EchoHub.Client.Commands;
|
using EchoHub.Client.Commands;
|
||||||
using EchoHub.Client.Config;
|
using EchoHub.Client.Config;
|
||||||
@@ -333,7 +334,43 @@ public sealed class MainWindowViewModel : ViewModelBase
|
|||||||
|
|
||||||
_commandHandler.OnOpenProfile += async username =>
|
_commandHandler.OnOpenProfile += async username =>
|
||||||
{
|
{
|
||||||
StatusText = $"Profile: {username ?? "self"}";
|
string serverUrl = GetCurrentServerUrl();
|
||||||
|
if (string.IsNullOrEmpty(serverUrl))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string target = username ?? ConnectionService.GetCurrentUsername(serverUrl) ?? string.Empty;
|
||||||
|
if (string.IsNullOrEmpty(target))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
UserProfileDto? profile = await ConnectionService.GetUserProfileAsync(serverUrl, target);
|
||||||
|
Avalonia.Threading.Dispatcher.UIThread.Post(() =>
|
||||||
|
{
|
||||||
|
if (profile is null)
|
||||||
|
{
|
||||||
|
StatusText = "User not found";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProfileWindow dialog = new ProfileWindow(profile);
|
||||||
|
if (_mainWindow is not null)
|
||||||
|
{
|
||||||
|
_ = dialog.ShowDialog(_mainWindow);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Avalonia.Threading.Dispatcher.UIThread.Post(() =>
|
||||||
|
{
|
||||||
|
StatusText = $"Failed to load profile: {ex.Message}";
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
_commandHandler.OnOpenServers += () =>
|
_commandHandler.OnOpenServers += () =>
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
<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.ProfileWindow"
|
||||||
|
Title="Profile"
|
||||||
|
Width="380"
|
||||||
|
MinWidth="380"
|
||||||
|
MinHeight="280"
|
||||||
|
SizeToContent="Height"
|
||||||
|
WindowStartupLocation="CenterOwner"
|
||||||
|
Icon="/Assets/avalonia-logo.ico">
|
||||||
|
<Border Padding="15">
|
||||||
|
<DockPanel>
|
||||||
|
<Button DockPanel.Dock="Bottom"
|
||||||
|
Content="Close"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
Width="80"
|
||||||
|
Margin="0 8 0 0"
|
||||||
|
Click="OnCloseClick" />
|
||||||
|
<StackPanel Spacing="8">
|
||||||
|
<TextBlock x:Name="UsernameText" FontSize="20" FontWeight="Bold" />
|
||||||
|
|
||||||
|
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||||
|
<Ellipse x:Name="StatusDot" Width="10" Height="10" VerticalAlignment="Center" />
|
||||||
|
<TextBlock x:Name="StatusText" VerticalAlignment="Center" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<TextBlock x:Name="StatusMessageText"
|
||||||
|
FontSize="12"
|
||||||
|
Opacity="0.7"
|
||||||
|
TextWrapping="Wrap"
|
||||||
|
IsVisible="False" />
|
||||||
|
|
||||||
|
<Separator Margin="0 4" />
|
||||||
|
|
||||||
|
<Grid ColumnDefinitions="85, *">
|
||||||
|
<TextBlock Text="Display Name:" FontWeight="SemiBold" />
|
||||||
|
<TextBlock x:Name="DisplayNameText" Grid.Column="1" />
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid ColumnDefinitions="85, Auto, 10, *">
|
||||||
|
<TextBlock Text="Color:" FontWeight="SemiBold" />
|
||||||
|
<Border x:Name="ColorSwatch" Grid.Column="1"
|
||||||
|
Width="16" Height="16" CornerRadius="3"
|
||||||
|
BorderThickness="1" BorderBrush="{DynamicResource UiTheme08}" />
|
||||||
|
<TextBlock x:Name="ColorText" Grid.Column="3" VerticalAlignment="Center" />
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid ColumnDefinitions="85, *">
|
||||||
|
<TextBlock Text="Role:" FontWeight="SemiBold" />
|
||||||
|
<TextBlock x:Name="RoleText" Grid.Column="1" />
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<TextBlock Text="Bio:" FontWeight="SemiBold" />
|
||||||
|
<Border Background="{DynamicResource UiTheme00}" CornerRadius="4" Padding="8">
|
||||||
|
<TextBlock x:Name="BioText" TextWrapping="Wrap" />
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<Grid ColumnDefinitions="85, *">
|
||||||
|
<TextBlock Text="Joined:" FontWeight="SemiBold" />
|
||||||
|
<TextBlock x:Name="JoinedText" Grid.Column="1" />
|
||||||
|
</Grid>
|
||||||
|
<Grid ColumnDefinitions="85, *">
|
||||||
|
<TextBlock Text="Last seen:" FontWeight="SemiBold" />
|
||||||
|
<TextBlock x:Name="LastSeenText" Grid.Column="1" />
|
||||||
|
</Grid>
|
||||||
|
</StackPanel>
|
||||||
|
</DockPanel>
|
||||||
|
</Border>
|
||||||
|
</Window>
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Media;
|
||||||
|
|
||||||
|
using EchoHub.Core.DTOs;
|
||||||
|
using EchoHub.Core.Models;
|
||||||
|
|
||||||
|
namespace Decho.Views;
|
||||||
|
|
||||||
|
public sealed partial class ProfileWindow : Window
|
||||||
|
{
|
||||||
|
public ProfileWindow()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProfileWindow(UserProfileDto profile)
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
Title = $"Profile - {profile.Username}";
|
||||||
|
|
||||||
|
UsernameText.Text = profile.Username;
|
||||||
|
|
||||||
|
StatusText.Text = FormatStatus(profile.Status);
|
||||||
|
StatusDot.Fill = GetStatusBrush(profile.Status);
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(profile.StatusMessage))
|
||||||
|
{
|
||||||
|
StatusMessageText.Text = profile.StatusMessage;
|
||||||
|
StatusMessageText.IsVisible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
DisplayNameText.Text = profile.DisplayName ?? profile.Username;
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(profile.NicknameColor)
|
||||||
|
&& Color.TryParse(profile.NicknameColor, out Color parsedColor))
|
||||||
|
{
|
||||||
|
ColorText.Text = profile.NicknameColor;
|
||||||
|
ColorSwatch.Background = new SolidColorBrush(parsedColor);
|
||||||
|
ColorSwatch.IsVisible = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ColorText.Text = "-";
|
||||||
|
ColorSwatch.IsVisible = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
RoleText.Text = FormatRole(profile.Role);
|
||||||
|
BioText.Text = profile.Bio ?? "-";
|
||||||
|
JoinedText.Text = profile.CreatedAt.ToString("g");
|
||||||
|
LastSeenText.Text = profile.LastSeenAt.ToString("g");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnCloseClick(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string FormatStatus(UserStatus status) => status switch
|
||||||
|
{
|
||||||
|
UserStatus.Online => "Online",
|
||||||
|
UserStatus.Away => "Away",
|
||||||
|
UserStatus.DoNotDisturb => "Do Not Disturb",
|
||||||
|
UserStatus.Invisible => "Invisible",
|
||||||
|
_ => "Unknown",
|
||||||
|
};
|
||||||
|
|
||||||
|
private static IBrush GetStatusBrush(UserStatus status) => status switch
|
||||||
|
{
|
||||||
|
UserStatus.Online => new SolidColorBrush(Colors.LimeGreen),
|
||||||
|
UserStatus.Away => new SolidColorBrush(Colors.Goldenrod),
|
||||||
|
UserStatus.DoNotDisturb => new SolidColorBrush(Colors.IndianRed),
|
||||||
|
UserStatus.Invisible => new SolidColorBrush(Colors.Gray),
|
||||||
|
_ => new SolidColorBrush(Colors.White),
|
||||||
|
};
|
||||||
|
|
||||||
|
private static string FormatRole(ServerRole role) => role switch
|
||||||
|
{
|
||||||
|
ServerRole.Admin => "Admin",
|
||||||
|
ServerRole.Mod => "Mod",
|
||||||
|
ServerRole.Member => "Member",
|
||||||
|
_ => role.ToString(),
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user