using OrderSupportTicket.Models.Api;
using OrderSupportTicket.Services;
using System;
using System.Globalization;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using WPFCommon.Models;
namespace OrderSupportTicket.ViewModels;
///
/// 留言气泡中的公开图片附件。
///
public sealed class ChatAttachmentViewModel : BindableBaseEx
{
private bool _isLoading;
private bool _isLoadFailed;
private ImageSource _image;
public ChatAttachmentViewModel(TicketAttachmentDto dto)
{
if (dto == null)
throw new ArgumentNullException(nameof(dto));
Id = dto.Id;
OriginalName = dto.OriginalName;
ContentType = dto.ContentType;
ByteSize = dto.ByteSize;
ReadUrl = dto.ReadUrl;
}
///
/// 附件唯一 ID。
///
public string Id { get; }
///
/// 原始文件名。
///
public string OriginalName { get; }
///
/// 图片 MIME 类型。
///
public string ContentType { get; }
///
/// 图片字节数。
///
public long ByteSize { get; }
///
/// 服务端生成的短时读取地址。
///
public string ReadUrl { get; }
///
/// 已下载并解码的图片;加载完成前为空。
///
public ImageSource Image
{
get => _image;
private set
{
if (SetValue(ref _image, value))
RaisePropertyChanged(nameof(HasImage));
}
}
///
/// 是否已成功显示图片。
///
public bool HasImage => Image != null;
///
/// 图片是否已经确认加载失败。加载完成前保持为 false。
///
public bool IsLoadFailed
{
get => _isLoadFailed;
private set
{
if (SetValue(ref _isLoadFailed, value))
RaisePropertyChanged(nameof(ToolTipText));
}
}
///
/// 附件名称、大小与加载状态提示。
///
public string ToolTipText
{
get
{
var name = string.IsNullOrWhiteSpace(OriginalName) ? "图片" : OriginalName;
var size = FormatSize(ByteSize);
if (string.IsNullOrWhiteSpace(ReadUrl))
return name + "(" + size + ",暂不可用)";
if (_isLoading)
return name + "(" + size + ",加载中…)";
if (IsLoadFailed)
return name + "(" + size + ",加载失败)";
return name + "(" + size + ")";
}
}
///
/// 下载并解码短时读取地址。失败时保留占位提示,不阻断文字留言展示。
///
public async Task LoadAsync()
{
if (Image != null || _isLoading)
return;
if (string.IsNullOrWhiteSpace(ReadUrl))
{
IsLoadFailed = true;
return;
}
IsLoadFailed = false;
_isLoading = true;
RaisePropertyChanged(nameof(ToolTipText));
try
{
var image = await ProductImageLoader.LoadAsync(ReadUrl);
if (image == null)
IsLoadFailed = true;
else
await SetImageAsync(image);
}
catch
{
IsLoadFailed = true;
}
finally
{
_isLoading = false;
RaisePropertyChanged(nameof(ToolTipText));
}
}
private async Task SetImageAsync(ImageSource image)
{
if (image == null)
return;
var dispatcher = Application.Current?.Dispatcher;
if (dispatcher == null || dispatcher.CheckAccess())
{
Image = image;
IsLoadFailed = false;
return;
}
await dispatcher.InvokeAsync(() =>
{
Image = image;
IsLoadFailed = false;
});
}
private static string FormatSize(long byteSize)
{
if (byteSize >= 1024 * 1024)
return (byteSize / 1024d / 1024d).ToString("0.0", CultureInfo.CurrentCulture) + " MB";
if (byteSize >= 1024)
return (byteSize / 1024d).ToString("0.0", CultureInfo.CurrentCulture) + " KB";
return byteSize.ToString(CultureInfo.CurrentCulture) + " B";
}
}