using CommunityToolkit.Mvvm.ComponentModel;
using XFEToolBox.Client.Utilities.Chat;
using XFEToolBox.Core.Chat;
namespace XFEToolBox.Client.Models.Chat;
public enum ChatSection
{
Conversations,
Lobby,
Friends,
Groups
}
public sealed class ChatConversationItem(ChatConversationInfo conversation)
{
public ChatConversationInfo Conversation { get; } = conversation;
public string Id => Conversation.Id;
public string Title => Conversation.Kind == ChatConversationKind.Group
? Conversation.Group?.Name ?? "群聊"
: Conversation.Friend?.NickName ?? "好友";
public string Subtitle => Conversation.LastMessage is null
? "还没有消息"
: ChatMessageItem.DescribeMessage(Conversation.LastMessage);
public string Initials => Title;
public string KindText => Conversation.Kind == ChatConversationKind.Group ? "群聊" : "好友";
public string TimeText => Conversation.LastMessage?.CreatedAtUtc.ToLocalTime().ToString("MM-dd HH:mm") ?? string.Empty;
public string UnreadText => Conversation.UnreadCount > 99 ? "99+" : Conversation.UnreadCount.ToString();
public bool HasUnread => Conversation.UnreadCount > 0;
}
public sealed class ChatNavigationItem
{
public ChatNavigationItem(ChatConversationInfo? conversation, ChatFriendInfo friend)
{
Conversation = conversation;
Friend = friend;
Key = $"friend:{friend.User.Id}";
Title = friend.User.NickName;
Initials = Title;
}
public ChatNavigationItem(ChatConversationInfo? conversation, ChatGroupSummary group)
{
Conversation = conversation;
Group = group;
Key = $"group:{group.Id}";
Title = group.Name;
Initials = Title;
}
public ChatNavigationItem(ChatConversationInfo conversation)
{
Conversation = conversation;
Friend = conversation.Kind == ChatConversationKind.Direct && conversation.Friend is not null
? new ChatFriendInfo
{
User = conversation.Friend,
ConversationId = conversation.Id,
FriendsSinceUtc = conversation.CreatedAtUtc
}
: null;
Group = conversation.Kind == ChatConversationKind.Group ? conversation.Group : null;
Key = conversation.Kind == ChatConversationKind.Group
? $"group:{conversation.Group?.Id ?? conversation.Id}"
: $"friend:{conversation.Friend?.Id ?? conversation.Id}";
Title = conversation.Kind == ChatConversationKind.Group
? conversation.Group?.Name ?? "群聊"
: conversation.Friend?.NickName ?? "好友";
Initials = Title;
}
public string Key { get; }
public ChatConversationInfo? Conversation { get; }
public ChatFriendInfo? Friend { get; }
public ChatGroupSummary? Group { get; }
public string Title { get; }
public string Initials { get; }
public bool IsGroup => Group is not null || Conversation?.Kind == ChatConversationKind.Group;
public bool IsFriend => !IsGroup;
public string Subtitle => Conversation?.LastMessage is null
? "暂无消息"
: ChatMessageItem.DescribeMessage(Conversation.LastMessage);
public DateTimeOffset? LastMessageAtUtc => Conversation?.LastMessage?.CreatedAtUtc;
public string TimeText => LastMessageAtUtc?.ToLocalTime().ToString("MM-dd HH:mm") ?? string.Empty;
public long UnreadCount => Conversation?.UnreadCount ?? 0;
public string UnreadText => UnreadCount > 99 ? "99+" : UnreadCount.ToString();
public bool HasUnread => UnreadCount > 0;
public bool IsMuted => IsGroup && ChatNotificationPreferences.IsGroupMuted(Group?.Id ?? Conversation?.Group?.Id);
public string MutedText => IsMuted ? "免打扰" : string.Empty;
}
public sealed class ChatGroupItem(ChatGroupSummary group)
{
public ChatGroupSummary Group { get; } = group;
public string Id => Group.Id;
public string Name => Group.Name;
public string Description => string.IsNullOrWhiteSpace(Group.Description) ? "群主暂未填写简介" : Group.Description;
public string GroupNumberText => $"群号 {Group.GroupNumber}";
public string MemberText => $"{Group.MemberCount} 位成员";
public string VisibilityText => Group.Visibility == ChatGroupVisibility.Public ? "公开群聊" : "私密群聊";
public bool IsJoined => Group.CurrentUserRole is not null;
public string JoinActionText => IsJoined ? "进入" : "加入";
public bool CanManage => Group.CurrentUserRole is ChatGroupRole.Administrator or ChatGroupRole.Owner;
public bool IsOwner => Group.CurrentUserRole == ChatGroupRole.Owner;
}
public sealed class ChatFriendItem(ChatFriendInfo friend)
{
public ChatFriendInfo Friend { get; } = friend;
public string Id => Friend.User.Id;
public string Name => Friend.User.NickName;
public string AccountText => $"@{Friend.User.UserName}";
public string Bio => string.IsNullOrWhiteSpace(Friend.User.Bio) ? "这位好友还没有填写简介" : Friend.User.Bio;
}
public sealed class ChatUserSearchItem(ChatUserSummary user)
{
public ChatUserSummary User { get; } = user;
public string Name => User.NickName;
public string AccountText => $"@{User.UserName}";
public string Bio => string.IsNullOrWhiteSpace(User.Bio) ? "暂无个人简介" : User.Bio;
}
public sealed class ChatFriendRequestItem(ChatFriendRequestInfo request)
{
public ChatFriendRequestInfo Request { get; } = request;
public ChatUserSummary OtherUser => Request.IsIncoming ? Request.FromUser : Request.ToUser;
public string Name => OtherUser.NickName;
public string AccountText => $"@{OtherUser.UserName}";
public string Message => string.IsNullOrWhiteSpace(Request.Message) ? "希望添加你为好友" : Request.Message;
public bool CanRespond => Request.IsIncoming && Request.Status == ChatFriendRequestStatus.Pending;
public string StatusText => Request.Status switch
{
ChatFriendRequestStatus.Pending when Request.IsIncoming => "等待你处理",
ChatFriendRequestStatus.Pending => "等待对方处理",
ChatFriendRequestStatus.Accepted => "已同意",
ChatFriendRequestStatus.Rejected => "已拒绝",
ChatFriendRequestStatus.Cancelled => "已取消",
_ => "已处理"
};
}
public sealed class ChatInvitationItem(ChatGroupInvitationInfo invitation, string currentUserId)
{
public ChatGroupInvitationInfo Invitation { get; } = invitation;
public string GroupName => Invitation.Group.Name;
public string GroupNumberText => $"群号 {Invitation.Group.GroupNumber}";
public bool IsIncoming => string.Equals(Invitation.InvitedUser.Id, currentUserId, StringComparison.Ordinal);
public string InviterText => IsIncoming
? $"{Invitation.InvitedBy.NickName} 邀请你加入"
: $"已邀请 {Invitation.InvitedUser.NickName} 加入";
public string Message => string.IsNullOrWhiteSpace(Invitation.Message) ? "一起来聊天吧" : Invitation.Message;
public bool CanRespond => Invitation.Status == ChatGroupInvitationStatus.Pending && IsIncoming;
public string StatusText => Invitation.Status switch
{
ChatGroupInvitationStatus.Pending when IsIncoming => "待你处理",
ChatGroupInvitationStatus.Pending => "等待对方处理",
ChatGroupInvitationStatus.Accepted => "已加入",
ChatGroupInvitationStatus.Rejected => "已拒绝",
ChatGroupInvitationStatus.Cancelled => "已取消",
ChatGroupInvitationStatus.Expired => "已过期",
_ => "已处理"
};
}
public sealed class ChatMessageItem(ChatMessageInfo message, string currentUserId)
{
public ChatMessageInfo Message { get; } = message;
public string Id => Message.Id;
public long Sequence => Message.Sequence;
public string SenderName => Message.Sender.NickName;
public bool IsMine => string.Equals(Message.Sender.Id, currentUserId, StringComparison.Ordinal);
public string TimeText => Message.CreatedAtUtc.ToLocalTime().ToString("MM-dd HH:mm");
public string Text => Message.Text;
public bool HasText => !string.IsNullOrWhiteSpace(Message.Text);
public bool HasAttachment => Message.Attachment is not null;
public bool IsGroupInvitation => Message.MessageType == ChatMessageType.GroupInvitation && Message.GroupInvitation is not null;
public ChatAttachmentInfo? Attachment => Message.Attachment;
public string AttachmentTitle => Message.Attachment?.FileName ?? string.Empty;
public string AttachmentKindText => Message.MessageType switch
{
ChatMessageType.Image => "图片",
ChatMessageType.Video => "视频",
_ => "文件"
};
public string AttachmentSizeText => FormatBytes(Message.Attachment?.TotalBytes ?? 0);
public string InvitationTitle => Message.GroupInvitation is null ? string.Empty : $"邀请加入 {Message.GroupInvitation.Group.Name}";
public string InvitationSubtitle => Message.GroupInvitation is null
? string.Empty
: $"群号 {Message.GroupInvitation.Group.GroupNumber} · {Message.GroupInvitation.Group.MemberCount} 位成员";
public string InvitationStatusText => Message.GroupInvitation?.Status switch
{
ChatGroupInvitationStatus.Pending => "等待处理",
ChatGroupInvitationStatus.Accepted => "已加入",
ChatGroupInvitationStatus.Rejected => "已拒绝",
ChatGroupInvitationStatus.Cancelled => "已取消",
ChatGroupInvitationStatus.Expired => "已过期",
_ => string.Empty
};
public bool CanRespondToInvitation => Message.GroupInvitation?.Status == ChatGroupInvitationStatus.Pending &&
string.Equals(Message.GroupInvitation.InvitedUser.Id, currentUserId, StringComparison.Ordinal);
public static string DescribeMessage(ChatMessageInfo message) => message.MessageType switch
{
ChatMessageType.Image => "[图片]",
ChatMessageType.Video => "[视频]",
ChatMessageType.File => $"[文件] {message.Attachment?.FileName}",
ChatMessageType.GroupInvitation => $"[群邀请] {message.GroupInvitation?.Group.Name}",
ChatMessageType.System => message.Text,
_ => message.Text
};
public static string FormatBytes(long bytes)
{
string[] units = ["B", "KB", "MB", "GB"];
var value = Math.Max(0, (double)bytes);
var index = 0;
while (value >= 1024 && index < units.Length - 1)
{
value /= 1024;
index++;
}
return $"{value:0.##} {units[index]}";
}
}
public sealed partial class SelectableFriendItem(ChatFriendInfo friend) : ObservableObject
{
public ChatFriendInfo Friend { get; } = friend;
public string Name => Friend.User.NickName;
public string AccountText => $"@{Friend.User.UserName}";
[ObservableProperty]
private bool isSelected;
}
public sealed class ChatGroupMemberItem(ChatGroupMemberInfo member, string currentUserId)
{
public ChatGroupMemberInfo Member { get; } = member;
public string Name => Member.User.NickName;
public string AccountText => $"@{Member.User.UserName}";
public string RoleText => Member.Role switch
{
ChatGroupRole.Owner => "群主",
ChatGroupRole.Administrator => "管理员",
_ => "成员"
};
public bool IsCurrentUser => string.Equals(Member.User.Id, currentUserId, StringComparison.Ordinal);
public bool IsOwner => Member.Role == ChatGroupRole.Owner;
public bool CanBeManaged => !IsCurrentUser && !IsOwner;
public string RoleActionText => Member.Role == ChatGroupRole.Administrator ? "取消管理" : "设为管理";
}
using CommunityToolkit.Mvvm.ComponentModel;
using XFEToolBox.Client.Utilities.Chat;
using XFEToolBox.Core.Chat;
namespace XFEToolBox.Client.Models.Chat;
public enum ChatSection
{
Conversations,
Lobby,
Friends,
Groups
}
public sealed class ChatConversationItem(ChatConversationInfo conversation)
{
public ChatConversationInfo Conversation { get; } = conversation;
public string Id => Conversation.Id;
public string Title => Conversation.Kind == ChatConversationKind.Group
? Conversation.Group?.Name ?? "群聊"
: Conversation.Friend?.NickName ?? "好友";
public string Subtitle => Conversation.LastMessage is null
? "还没有消息"
: ChatMessageItem.DescribeMessage(Conversation.LastMessage);
public string Initials => Title;
public string KindText => Conversation.Kind == ChatConversationKind.Group ? "群聊" : "好友";
public string TimeText => Conversation.LastMessage?.CreatedAtUtc.ToLocalTime().ToString("MM-dd HH:mm") ?? string.Empty;
public string UnreadText => Conversation.UnreadCount > 99 ? "99+" : Conversation.UnreadCount.ToString();
public bool HasUnread => Conversation.UnreadCount > 0;
}
public sealed class ChatNavigationItem
{
public ChatNavigationItem(ChatConversationInfo? conversation, ChatFriendInfo friend)
{
Conversation = conversation;
Friend = friend;
Key = $"friend:{friend.User.Id}";
Title = friend.User.NickName;
Initials = Title;
}
public ChatNavigationItem(ChatConversationInfo? conversation, ChatGroupSummary group)
{
Conversation = conversation;
Group = group;
Key = $"group:{group.Id}";
Title = group.Name;
Initials = Title;
}
public ChatNavigationItem(ChatConversationInfo conversation)
{
Conversation = conversation;
Friend = conversation.Kind == ChatConversationKind.Direct && conversation.Friend is not null
? new ChatFriendInfo
{
User = conversation.Friend,
ConversationId = conversation.Id,
FriendsSinceUtc = conversation.CreatedAtUtc
}
: null;
Group = conversation.Kind == ChatConversationKind.Group ? conversation.Group : null;
Key = conversation.Kind == ChatConversationKind.Group
? $"group:{conversation.Group?.Id ?? conversation.Id}"
: $"friend:{conversation.Friend?.Id ?? conversation.Id}";
Title = conversation.Kind == ChatConversationKind.Group
? conversation.Group?.Name ?? "群聊"
: conversation.Friend?.NickName ?? "好友";
Initials = Title;
}
public string Key { get; }
public ChatConversationInfo? Conversation { get; }
public ChatFriendInfo? Friend { get; }
public ChatGroupSummary? Group { get; }
public string Title { get; }
public string Initials { get; }
public bool IsGroup => Group is not null || Conversation?.Kind == ChatConversationKind.Group;
public bool IsFriend => !IsGroup;
public string Subtitle => Conversation?.LastMessage is null
? "暂无消息"
: ChatMessageItem.DescribeMessage(Conversation.LastMessage);
public DateTimeOffset? LastMessageAtUtc => Conversation?.LastMessage?.CreatedAtUtc;
public string TimeText => LastMessageAtUtc?.ToLocalTime().ToString("MM-dd HH:mm") ?? string.Empty;
public long UnreadCount => Conversation?.UnreadCount ?? 0;
public string UnreadText => UnreadCount > 99 ? "99+" : UnreadCount.ToString();
public bool HasUnread => UnreadCount > 0;
public bool IsMuted => IsGroup && ChatNotificationPreferences.IsGroupMuted(Group?.Id ?? Conversation?.Group?.Id);
public string MutedText => IsMuted ? "免打扰" : string.Empty;
}
public sealed class ChatGroupItem(ChatGroupSummary group)
{
public ChatGroupSummary Group { get; } = group;
public string Id => Group.Id;
public string Name => Group.Name;
public string Description => string.IsNullOrWhiteSpace(Group.Description) ? "群主暂未填写简介" : Group.Description;
public string GroupNumberText => $"群号 {Group.GroupNumber}";
public string MemberText => $"{Group.MemberCount} 位成员";
public string VisibilityText => Group.Visibility == ChatGroupVisibility.Public ? "公开群聊" : "私密群聊";
public bool IsJoined => Group.CurrentUserRole is not null;
public string JoinActionText => IsJoined ? "进入" : "加入";
public bool CanManage => Group.CurrentUserRole is ChatGroupRole.Administrator or ChatGroupRole.Owner;
public bool IsOwner => Group.CurrentUserRole == ChatGroupRole.Owner;
}
public sealed class ChatFriendItem(ChatFriendInfo friend)
{
public ChatFriendInfo Friend { get; } = friend;
public string Id => Friend.User.Id;
public string Name => Friend.User.NickName;
public string AccountText => $"@{Friend.User.UserName}";
public string Bio => string.IsNullOrWhiteSpace(Friend.User.Bio) ? "这位好友还没有填写简介" : Friend.User.Bio;
}
public sealed class ChatUserSearchItem(ChatUserSummary user)
{
public ChatUserSummary User { get; } = user;
public string Name => User.NickName;
public string AccountText => $"@{User.UserName}";
public string Bio => string.IsNullOrWhiteSpace(User.Bio) ? "暂无个人简介" : User.Bio;
}
public sealed class ChatFriendRequestItem(ChatFriendRequestInfo request)
{
public ChatFriendRequestInfo Request { get; } = request;
public ChatUserSummary OtherUser => Request.IsIncoming ? Request.FromUser : Request.ToUser;
public string Name => OtherUser.NickName;
public string AccountText => $"@{OtherUser.UserName}";
public string Message => string.IsNullOrWhiteSpace(Request.Message) ? "希望添加你为好友" : Request.Message;
public bool CanRespond => Request.IsIncoming && Request.Status == ChatFriendRequestStatus.Pending;
public string StatusText => Request.Status switch
{
ChatFriendRequestStatus.Pending when Request.IsIncoming => "等待你处理",
ChatFriendRequestStatus.Pending => "等待对方处理",
ChatFriendRequestStatus.Accepted => "已同意",
ChatFriendRequestStatus.Rejected => "已拒绝",
ChatFriendRequestStatus.Cancelled => "已取消",
_ => "已处理"
};
}
public sealed class ChatInvitationItem(ChatGroupInvitationInfo invitation, string currentUserId)
{
public ChatGroupInvitationInfo Invitation { get; } = invitation;
public string GroupName => Invitation.Group.Name;
public string GroupNumberText => $"群号 {Invitation.Group.GroupNumber}";
public bool IsIncoming => string.Equals(Invitation.InvitedUser.Id, currentUserId, StringComparison.Ordinal);
public string InviterText => IsIncoming
? $"{Invitation.InvitedBy.NickName} 邀请你加入"
: $"已邀请 {Invitation.InvitedUser.NickName} 加入";
public string Message => string.IsNullOrWhiteSpace(Invitation.Message) ? "一起来聊天吧" : Invitation.Message;
public bool CanRespond => Invitation.Status == ChatGroupInvitationStatus.Pending && IsIncoming;
public string StatusText => Invitation.Status switch
{
ChatGroupInvitationStatus.Pending when IsIncoming => "待你处理",
ChatGroupInvitationStatus.Pending => "等待对方处理",
ChatGroupInvitationStatus.Accepted => "已加入",
ChatGroupInvitationStatus.Rejected => "已拒绝",
ChatGroupInvitationStatus.Cancelled => "已取消",
ChatGroupInvitationStatus.Expired => "已过期",
_ => "已处理"
};
}
public sealed class ChatMessageItem(ChatMessageInfo message, string currentUserId)
{
public ChatMessageInfo Message { get; } = message;
public string Id => Message.Id;
public long Sequence => Message.Sequence;
public string SenderName => Message.Sender.NickName;
public bool IsMine => string.Equals(Message.Sender.Id, currentUserId, StringComparison.Ordinal);
public string TimeText => Message.CreatedAtUtc.ToLocalTime().ToString("MM-dd HH:mm");
public string Text => Message.Text;
public bool HasText => !string.IsNullOrWhiteSpace(Message.Text);
public bool HasAttachment => Message.Attachment is not null;
public bool IsGroupInvitation => Message.MessageType == ChatMessageType.GroupInvitation && Message.GroupInvitation is not null;
public ChatAttachmentInfo? Attachment => Message.Attachment;
public string AttachmentTitle => Message.Attachment?.FileName ?? string.Empty;
public string AttachmentKindText => Message.MessageType switch
{
ChatMessageType.Image => "图片",
ChatMessageType.Video => "视频",
_ => "文件"
};
public string AttachmentSizeText => FormatBytes(Message.Attachment?.TotalBytes ?? 0);
public string InvitationTitle => Message.GroupInvitation is null ? string.Empty : $"邀请加入 {Message.GroupInvitation.Group.Name}";
public string InvitationSubtitle => Message.GroupInvitation is null
? string.Empty
: $"群号 {Message.GroupInvitation.Group.GroupNumber} · {Message.GroupInvitation.Group.MemberCount} 位成员";
public string InvitationStatusText => Message.GroupInvitation?.Status switch
{
ChatGroupInvitationStatus.Pending => "等待处理",
ChatGroupInvitationStatus.Accepted => "已加入",
ChatGroupInvitationStatus.Rejected => "已拒绝",
ChatGroupInvitationStatus.Cancelled => "已取消",
ChatGroupInvitationStatus.Expired => "已过期",
_ => string.Empty
};
public bool CanRespondToInvitation => Message.GroupInvitation?.Status == ChatGroupInvitationStatus.Pending &&
string.Equals(Message.GroupInvitation.InvitedUser.Id, currentUserId, StringComparison.Ordinal);
public static string DescribeMessage(ChatMessageInfo message) => message.MessageType switch
{
ChatMessageType.Image => "[图片]",
ChatMessageType.Video => "[视频]",
ChatMessageType.File => $"[文件] {message.Attachment?.FileName}",
ChatMessageType.GroupInvitation => $"[群邀请] {message.GroupInvitation?.Group.Name}",
ChatMessageType.System => message.Text,
_ => message.Text
};
public static string FormatBytes(long bytes)
{
string[] units = ["B", "KB", "MB", "GB"];
var value = Math.Max(0, (double)bytes);
var index = 0;
while (value >= 1024 && index < units.Length - 1)
{
value /= 1024;
index++;
}
return $"{value:0.##} {units[index]}";
}
}
public sealed partial class SelectableFriendItem(ChatFriendInfo friend) : ObservableObject
{
public ChatFriendInfo Friend { get; } = friend;
public string Name => Friend.User.NickName;
public string AccountText => $"@{Friend.User.UserName}";
[ObservableProperty]
private bool isSelected;
}
public sealed class ChatGroupMemberItem(ChatGroupMemberInfo member, string currentUserId)
{
public ChatGroupMemberInfo Member { get; } = member;
public string Name => Member.User.NickName;
public string AccountText => $"@{Member.User.UserName}";
public string RoleText => Member.Role switch
{
ChatGroupRole.Owner => "群主",
ChatGroupRole.Administrator => "管理员",
_ => "成员"
};
public bool IsCurrentUser => string.Equals(Member.User.Id, currentUserId, StringComparison.Ordinal);
public bool IsOwner => Member.Role == ChatGroupRole.Owner;
public bool CanBeManaged => !IsCurrentUser && !IsOwner;
public string RoleActionText => Member.Role == ChatGroupRole.Administrator ? "取消管理" : "设为管理";
}