mirror of
https://github.com/Stone-Red-Code/Decho.git
synced 2026-09-04 00:46:11 +02:00
Add clickable mention and channel links to message content display
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Documents;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Media.Imaging;
|
||||
@@ -10,6 +12,8 @@ using Decho.ViewModels;
|
||||
using EchoHub.Core.DTOs;
|
||||
using EchoHub.Core.Models;
|
||||
|
||||
using Romzetron.Avalonia;
|
||||
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Decho.Views;
|
||||
@@ -17,6 +21,7 @@ namespace Decho.Views;
|
||||
public partial class MessageItemView : UserControl
|
||||
{
|
||||
private static readonly Regex MentionRegex = new(@"@(\w+)", RegexOptions.Compiled);
|
||||
private static readonly Regex ChannelRegex = new(@"(?<!\w)#(\w+)", RegexOptions.Compiled);
|
||||
private CancellationTokenSource? _loadCts;
|
||||
private string? _loadedMessageId;
|
||||
|
||||
@@ -54,19 +59,51 @@ public partial class MessageItemView : UserControl
|
||||
|
||||
tb.Inlines?.Clear();
|
||||
|
||||
var mentionMatches = MentionRegex.Matches(content).Cast<Match>();
|
||||
var channelMatches = ChannelRegex.Matches(content).Cast<Match>();
|
||||
var allMatches = mentionMatches.Concat(channelMatches)
|
||||
.OrderBy(m => m.Index)
|
||||
.ToList();
|
||||
|
||||
int lastIndex = 0;
|
||||
foreach (Match match in MentionRegex.Matches(content))
|
||||
foreach (Match match in allMatches)
|
||||
{
|
||||
if (match.Index > lastIndex)
|
||||
{
|
||||
tb.Inlines?.Add(new Run(content[lastIndex..match.Index]));
|
||||
}
|
||||
|
||||
tb.Inlines?.Add(new Run(match.Value)
|
||||
bool isMention = match.Value[0] == '@';
|
||||
var container = new InlineUIContainer
|
||||
{
|
||||
Foreground = new SolidColorBrush(Color.Parse("#FEE75C")),
|
||||
BaselineAlignment = BaselineAlignment.Center,
|
||||
};
|
||||
var label = new TextBlock
|
||||
{
|
||||
Text = match.Value,
|
||||
FontWeight = FontWeight.Bold,
|
||||
});
|
||||
Cursor = new Cursor(StandardCursorType.Hand),
|
||||
Padding = new Thickness(0),
|
||||
LineHeight = double.NaN,
|
||||
};
|
||||
|
||||
if (isMention)
|
||||
{
|
||||
string username = match.Groups[1].Value;
|
||||
label.Margin = new Thickness(0, 0, 0, -2);
|
||||
label.Foreground = ColorPalette.Yellow05;
|
||||
label.PointerPressed += (_, args) => OnMentionPointerPressed(username, args);
|
||||
}
|
||||
else
|
||||
{
|
||||
string channelName = match.Groups[1].Value;
|
||||
label.Margin = new Thickness(0, 0, 0, -2);
|
||||
label.Foreground = ColorPalette.Blue05;
|
||||
label.PointerPressed += (_, args) => OnChannelPointerPressed(channelName, args);
|
||||
}
|
||||
|
||||
container.Child = label;
|
||||
tb.Inlines?.Add(container);
|
||||
|
||||
lastIndex = match.Index + match.Length;
|
||||
}
|
||||
@@ -77,6 +114,64 @@ public partial class MessageItemView : UserControl
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnMentionPointerPressed(string username, PointerPressedEventArgs e)
|
||||
{
|
||||
if (DataContext is not MessageViewModel msg)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MainWindowViewModel? mainVm = this.GetMainWindowViewModel();
|
||||
if (mainVm is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
string serverUrl = msg.ServerUrl ?? mainVm.Chat.CurrentServerUrl;
|
||||
UserProfileDto? profile = await mainVm.ConnectionService.GetUserProfileAsync(serverUrl, username);
|
||||
if (profile is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ProfileWindow dialog = new ProfileWindow(profile);
|
||||
|
||||
if (TopLevel.GetTopLevel(this) is Window parent)
|
||||
{
|
||||
await dialog.ShowDialog(parent);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnChannelPointerPressed(string channelName, PointerPressedEventArgs e)
|
||||
{
|
||||
if (DataContext is not MessageViewModel msg)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MainWindowViewModel? mainVm = this.GetMainWindowViewModel();
|
||||
if (mainVm is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
string serverUrl = msg.ServerUrl ?? mainVm.Chat.CurrentServerUrl;
|
||||
ServerViewModel? serverVm = mainVm.Sidebar.GetServer(serverUrl);
|
||||
if (serverVm is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ChannelViewModel? channel = serverVm.Channels.FirstOrDefault(c =>
|
||||
string.Equals(c.Name, channelName, StringComparison.OrdinalIgnoreCase));
|
||||
if (channel is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
mainVm.Sidebar.SelectedChannel = channel;
|
||||
}
|
||||
|
||||
private async void OnAttachmentImageLoaded(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is not Image image)
|
||||
|
||||
Reference in New Issue
Block a user