mirror of
https://github.com/Stone-Red-Code/Decho.git
synced 2026-09-04 08:56:14 +02:00
Switch MessageModel to use attachments list and update related UI logic
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
using EchoHub.Core.Models;
|
||||
using EchoHub.Core.DTOs;
|
||||
|
||||
namespace Decho.Models;
|
||||
|
||||
public sealed class MessageModel(string id, UserModel author, DateTimeOffset sentAt, string content, string channelName, string? serverUrl = null, MessageType type = MessageType.Text, string? attachmentUrl = null, string? attachmentFileName = null, long? attachmentFileSize = null)
|
||||
public sealed class MessageModel(string id, UserModel author, DateTimeOffset sentAt, string content, string channelName, string? serverUrl = null, List<AttachmentDto>? attachments = null)
|
||||
{
|
||||
public string Id { get; } = id;
|
||||
|
||||
@@ -16,11 +16,5 @@ public sealed class MessageModel(string id, UserModel author, DateTimeOffset sen
|
||||
|
||||
public string? ServerUrl { get; } = serverUrl;
|
||||
|
||||
public MessageType Type { get; } = type;
|
||||
|
||||
public string? AttachmentUrl { get; } = attachmentUrl;
|
||||
|
||||
public string? AttachmentFileName { get; } = attachmentFileName;
|
||||
|
||||
public long? AttachmentFileSize { get; } = attachmentFileSize;
|
||||
public List<AttachmentDto> Attachments { get; } = attachments ?? [];
|
||||
}
|
||||
@@ -574,25 +574,7 @@ public sealed class ConnectionService : IDisposable
|
||||
dto.SenderUsername,
|
||||
dto.SenderNicknameColor);
|
||||
|
||||
MessageType type = MessageType.Text;
|
||||
string? attachmentUrl = null;
|
||||
string? attachmentFileName = null;
|
||||
long? attachmentFileSize = null;
|
||||
|
||||
if (dto.Attachments is { Count: > 0 })
|
||||
{
|
||||
AttachmentDto first = dto.Attachments[0];
|
||||
type = first.Kind switch
|
||||
{
|
||||
AttachmentKind.Image => MessageType.Image,
|
||||
AttachmentKind.Audio => MessageType.Audio,
|
||||
AttachmentKind.File => MessageType.File,
|
||||
_ => MessageType.File
|
||||
};
|
||||
attachmentUrl = first.Url;
|
||||
attachmentFileName = first.FileName;
|
||||
attachmentFileSize = first.FileSize;
|
||||
}
|
||||
List<AttachmentDto> attachments = dto.Attachments ?? [];
|
||||
|
||||
return new MessageModel(
|
||||
dto.Id.ToString("N"),
|
||||
@@ -601,10 +583,7 @@ public sealed class ConnectionService : IDisposable
|
||||
dto.Content,
|
||||
dto.ChannelName,
|
||||
entry.Server.ServerUrl,
|
||||
type,
|
||||
attachmentUrl,
|
||||
attachmentFileName,
|
||||
attachmentFileSize);
|
||||
attachments);
|
||||
}
|
||||
|
||||
internal ServerConnection? GetConnection(string serverUrl)
|
||||
|
||||
@@ -3,7 +3,7 @@ using Avalonia.Media.Imaging;
|
||||
|
||||
using Decho.Models;
|
||||
|
||||
using EchoHub.Core.Models;
|
||||
using EchoHub.Core.DTOs;
|
||||
|
||||
namespace Decho.ViewModels;
|
||||
|
||||
@@ -11,8 +11,6 @@ public sealed class MessageViewModel(MessageModel model) : ViewModelBase
|
||||
{
|
||||
public MessageModel Model { get; } = model;
|
||||
|
||||
public Bitmap? CachedImage { get; set; }
|
||||
|
||||
public string AuthorName => Model.Author.DisplayName;
|
||||
|
||||
public IBrush? AuthorColor
|
||||
@@ -40,22 +38,14 @@ public sealed class MessageViewModel(MessageModel model) : ViewModelBase
|
||||
|
||||
public string? ServerUrl => Model.ServerUrl;
|
||||
|
||||
public MessageType Type => Model.Type;
|
||||
public Dictionary<string, Bitmap> ImageCache { get; } = [];
|
||||
|
||||
public bool HasAttachment => Model.AttachmentUrl is not null;
|
||||
public IReadOnlyList<AttachmentDto> Attachments => Model.Attachments;
|
||||
|
||||
public string? AttachmentFileName => Model.AttachmentFileName;
|
||||
|
||||
public string? AttachmentUrl => Model.AttachmentUrl;
|
||||
|
||||
public bool IsImage => Type == MessageType.Image;
|
||||
public bool HasAttachments => Attachments.Count > 0;
|
||||
|
||||
public bool ShowContent => !string.IsNullOrEmpty(Content);
|
||||
|
||||
public bool IsAudio => Type == MessageType.Audio;
|
||||
|
||||
public bool IsFile => Type == MessageType.File;
|
||||
|
||||
public string TimeText
|
||||
{
|
||||
get
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:vm="using:Decho.ViewModels"
|
||||
xmlns:dto="using:EchoHub.Core.DTOs"
|
||||
x:Class="Decho.Views.MessageItemView"
|
||||
x:DataType="vm:MessageViewModel">
|
||||
<Grid Margin="5" ColumnDefinitions="Auto, *">
|
||||
@@ -27,22 +28,29 @@
|
||||
VerticalAlignment="Top"
|
||||
TextWrapping="Wrap"
|
||||
IsVisible="{Binding ShowContent}" />
|
||||
<Image x:Name="MessageImage"
|
||||
MaxHeight="300"
|
||||
MaxWidth="400"
|
||||
HorizontalAlignment="Left"
|
||||
IsVisible="{Binding IsImage}"
|
||||
Margin="0 4 0 0" />
|
||||
<StackPanel IsVisible="{Binding HasAttachment}" Margin="0 4 0 0" Spacing="2">
|
||||
<TextBlock Text="{Binding AttachmentFileName}"
|
||||
FontSize="11"
|
||||
Opacity="0.7" />
|
||||
<Button Content="Download"
|
||||
Click="OnDownloadClicked"
|
||||
FontSize="11"
|
||||
Padding="5 1"
|
||||
HorizontalAlignment="Left" />
|
||||
</StackPanel>
|
||||
<ItemsControl ItemsSource="{Binding Attachments}"
|
||||
IsVisible="{Binding HasAttachments}"
|
||||
Margin="0 4 0 0">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate x:DataType="dto:AttachmentDto">
|
||||
<StackPanel Margin="0 2 0 2">
|
||||
<Image Loaded="OnAttachmentImageLoaded"
|
||||
MaxHeight="300"
|
||||
MaxWidth="400"
|
||||
HorizontalAlignment="Left" />
|
||||
<TextBlock Text="{Binding FileName}"
|
||||
FontSize="11"
|
||||
Opacity="0.7" />
|
||||
<Button Content="Download"
|
||||
Click="OnAttachmentDownloadClicked"
|
||||
FontSize="11"
|
||||
Padding="5 1"
|
||||
HorizontalAlignment="Left"
|
||||
Margin="0 2 0 0" />
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
||||
@@ -8,6 +8,7 @@ using Avalonia.Platform.Storage;
|
||||
using Decho.ViewModels;
|
||||
|
||||
using EchoHub.Core.DTOs;
|
||||
using EchoHub.Core.Models;
|
||||
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
@@ -22,7 +23,6 @@ public partial class MessageItemView : UserControl
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContextChanged += OnDataContextChanged;
|
||||
Loaded += OnLoaded;
|
||||
}
|
||||
|
||||
private static readonly Regex MentionRegex = new(@"@(\w+)", RegexOptions.Compiled);
|
||||
@@ -36,11 +36,11 @@ public partial class MessageItemView : UserControl
|
||||
|
||||
_loadCts?.Cancel();
|
||||
_loadCts = new CancellationTokenSource();
|
||||
this.FindControl<Image>("MessageImage")?.ClearValue(Image.SourceProperty);
|
||||
_loadedMessageId = null;
|
||||
|
||||
if (DataContext is MessageViewModel msg)
|
||||
{
|
||||
_loadedMessageId = msg.Model.Id;
|
||||
BuildMessageInlines(msg.Content);
|
||||
}
|
||||
}
|
||||
@@ -78,31 +78,40 @@ public partial class MessageItemView : UserControl
|
||||
}
|
||||
}
|
||||
|
||||
private void OnLoaded(object? sender, RoutedEventArgs e)
|
||||
private async void OnAttachmentImageLoaded(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (DataContext is not MessageViewModel msg || !msg.IsImage || msg.AttachmentUrl is null)
|
||||
if (sender is not Image image)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg.Model.Id == _loadedMessageId)
|
||||
if (image.DataContext is not AttachmentDto att)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_loadedMessageId = msg.Model.Id;
|
||||
|
||||
if (msg.CachedImage is not null)
|
||||
if (att.Kind != AttachmentKind.Image)
|
||||
{
|
||||
this.FindControl<Image>("MessageImage")!.Source = msg.CachedImage;
|
||||
return;
|
||||
}
|
||||
|
||||
_ = LoadImageAsync(msg, _loadCts!.Token);
|
||||
}
|
||||
if (DataContext is not MessageViewModel msg)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CancellationTokenSource? cts = _loadCts;
|
||||
if (cts is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg.ImageCache.TryGetValue(att.Url, out Bitmap? cached))
|
||||
{
|
||||
image.Source = cached;
|
||||
return;
|
||||
}
|
||||
|
||||
private async Task LoadImageAsync(MessageViewModel msg, CancellationToken ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
MainWindowViewModel? mainVm = this.GetMainWindowViewModel();
|
||||
@@ -112,9 +121,9 @@ public partial class MessageItemView : UserControl
|
||||
}
|
||||
|
||||
byte[]? bytes = await mainVm.ConnectionService.DownloadImageBytesAsync(
|
||||
msg.ServerUrl ?? "", msg.AttachmentUrl!);
|
||||
msg.ServerUrl ?? "", att.Url);
|
||||
|
||||
ct.ThrowIfCancellationRequested();
|
||||
cts.Token.ThrowIfCancellationRequested();
|
||||
if (bytes is null || bytes.Length == 0)
|
||||
{
|
||||
return;
|
||||
@@ -122,9 +131,9 @@ public partial class MessageItemView : UserControl
|
||||
|
||||
using MemoryStream stream = new MemoryStream(bytes);
|
||||
Bitmap bitmap = new Bitmap(stream);
|
||||
ct.ThrowIfCancellationRequested();
|
||||
msg.CachedImage = bitmap;
|
||||
this.FindControl<Image>("MessageImage")!.Source = bitmap;
|
||||
cts.Token.ThrowIfCancellationRequested();
|
||||
msg.ImageCache[att.Url] = bitmap;
|
||||
image.Source = bitmap;
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -162,15 +171,19 @@ public partial class MessageItemView : UserControl
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnDownloadClicked(object? sender, RoutedEventArgs e)
|
||||
private async void OnAttachmentDownloadClicked(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
MessageViewModel? msg = this.GetDataContext<MessageViewModel>();
|
||||
if (msg is null)
|
||||
if (sender is not Button button)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg.AttachmentUrl is null)
|
||||
if (button.DataContext is not AttachmentDto att)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (DataContext is not MessageViewModel msg)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -187,7 +200,7 @@ public partial class MessageItemView : UserControl
|
||||
return;
|
||||
}
|
||||
|
||||
string? tempPath = await mainVm.ConnectionService.DownloadAttachmentAsync(msg.ServerUrl ?? "", msg.AttachmentUrl, msg.AttachmentFileName ?? "download");
|
||||
string? tempPath = await mainVm.ConnectionService.DownloadAttachmentAsync(msg.ServerUrl ?? "", att.Url, att.FileName);
|
||||
|
||||
if (tempPath is null)
|
||||
{
|
||||
@@ -196,7 +209,7 @@ public partial class MessageItemView : UserControl
|
||||
|
||||
IStorageFile? file = await topLevel.StorageProvider.SaveFilePickerAsync(new FilePickerSaveOptions
|
||||
{
|
||||
SuggestedFileName = msg.AttachmentFileName ?? "download",
|
||||
SuggestedFileName = att.FileName,
|
||||
});
|
||||
|
||||
if (file?.TryGetLocalPath() is string savePath)
|
||||
|
||||
Reference in New Issue
Block a user