mirror of
https://github.com/Stone-Red-Code/Decho.git
synced 2026-09-04 00:46:11 +02:00
Make messages selectable
This commit is contained in:
@@ -202,6 +202,11 @@ public sealed class MessageComposerViewModel : ViewModelBase
|
|||||||
ReplyTarget = null;
|
ReplyTarget = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void UpdateAutocomplete(string text, int caretIndex)
|
||||||
|
{
|
||||||
|
Autocomplete.Update(text, caretIndex);
|
||||||
|
}
|
||||||
|
|
||||||
internal void Send()
|
internal void Send()
|
||||||
{
|
{
|
||||||
string text = Draft.Trim();
|
string text = Draft.Trim();
|
||||||
@@ -230,9 +235,4 @@ public sealed class MessageComposerViewModel : ViewModelBase
|
|||||||
? $"{StagedFiles.Count} file(s) staged"
|
? $"{StagedFiles.Count} file(s) staged"
|
||||||
: string.Empty;
|
: string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateAutocomplete(string text, int caretIndex)
|
|
||||||
{
|
|
||||||
Autocomplete.Update(text, caretIndex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -50,10 +50,10 @@
|
|||||||
Opacity="0.5"
|
Opacity="0.5"
|
||||||
IsVisible="{Binding HasReply}"
|
IsVisible="{Binding HasReply}"
|
||||||
PointerPressed="OnReplyQuotePointerPressed" />
|
PointerPressed="OnReplyQuotePointerPressed" />
|
||||||
<TextBlock x:Name="MessageContent"
|
<SelectableTextBlock x:Name="MessageContent"
|
||||||
VerticalAlignment="Top"
|
VerticalAlignment="Top"
|
||||||
TextWrapping="Wrap"
|
TextWrapping="Wrap"
|
||||||
IsVisible="{Binding ShowContent}" />
|
IsVisible="{Binding ShowContent}" />
|
||||||
<ItemsControl ItemsSource="{Binding Attachments}"
|
<ItemsControl ItemsSource="{Binding Attachments}"
|
||||||
IsVisible="{Binding HasAttachments}"
|
IsVisible="{Binding HasAttachments}"
|
||||||
Margin="0 4 0 0">
|
Margin="0 4 0 0">
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ public partial class MessageItemView : UserControl
|
|||||||
|
|
||||||
private void BuildMessageInlines(string content)
|
private void BuildMessageInlines(string content)
|
||||||
{
|
{
|
||||||
TextBlock? tb = MessageContent;
|
SelectableTextBlock? tb = MessageContent;
|
||||||
if (tb is null)
|
if (tb is null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -17,12 +17,72 @@ public partial class MessageListView : UserControl
|
|||||||
private bool _loadingMore;
|
private bool _loadingMore;
|
||||||
private double _loadingMoreExtent;
|
private double _loadingMoreExtent;
|
||||||
|
|
||||||
|
private MessageViewModel? _highlightedMessage;
|
||||||
|
|
||||||
|
private CancellationTokenSource? _highlightCts;
|
||||||
|
|
||||||
public MessageListView()
|
public MessageListView()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
DataContextChanged += OnDataContextChanged;
|
DataContextChanged += OnDataContextChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ScrollToMessage(string messageId)
|
||||||
|
{
|
||||||
|
if (_chat is null) return;
|
||||||
|
|
||||||
|
MessageViewModel? target = _chat.Messages.FirstOrDefault(m => m.Model.Id == messageId);
|
||||||
|
if (target is null) return;
|
||||||
|
|
||||||
|
ScrollViewer? scroll = this.FindControl<ScrollViewer>("MessageScrollViewer");
|
||||||
|
if (scroll is null) return;
|
||||||
|
|
||||||
|
ClearHighlight();
|
||||||
|
target.IsHighlighted = true;
|
||||||
|
_highlightedMessage = target;
|
||||||
|
_highlightCts = new CancellationTokenSource();
|
||||||
|
CancellationToken ct = _highlightCts.Token;
|
||||||
|
|
||||||
|
Dispatcher.UIThread.Post(() =>
|
||||||
|
{
|
||||||
|
double? targetY = FindItemY(scroll, target);
|
||||||
|
if (targetY is not null)
|
||||||
|
scroll.Offset = new Vector(scroll.Offset.X, targetY.Value);
|
||||||
|
}, DispatcherPriority.Render);
|
||||||
|
|
||||||
|
_ = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await Task.Delay(2000, ct);
|
||||||
|
Dispatcher.UIThread.Post(() =>
|
||||||
|
{
|
||||||
|
target.IsHighlighted = false;
|
||||||
|
if (_highlightedMessage == target)
|
||||||
|
_highlightedMessage = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double? FindItemY(Visual parent, MessageViewModel target)
|
||||||
|
{
|
||||||
|
foreach (Visual child in parent.GetVisualChildren())
|
||||||
|
{
|
||||||
|
if (child.DataContext == target)
|
||||||
|
return child.Bounds.Y;
|
||||||
|
|
||||||
|
double? result = FindItemY(child, target);
|
||||||
|
if (result.HasValue)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private void OnDataContextChanged(object? sender, EventArgs args)
|
private void OnDataContextChanged(object? sender, EventArgs args)
|
||||||
{
|
{
|
||||||
if (_chat is not null)
|
if (_chat is not null)
|
||||||
@@ -142,65 +202,6 @@ public partial class MessageListView : UserControl
|
|||||||
Dispatcher.UIThread.Post(scroll.ScrollToEnd, DispatcherPriority.Background);
|
Dispatcher.UIThread.Post(scroll.ScrollToEnd, DispatcherPriority.Background);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ScrollToMessage(string messageId)
|
|
||||||
{
|
|
||||||
if (_chat is null) return;
|
|
||||||
|
|
||||||
MessageViewModel? target = _chat.Messages.FirstOrDefault(m => m.Model.Id == messageId);
|
|
||||||
if (target is null) return;
|
|
||||||
|
|
||||||
ScrollViewer? scroll = this.FindControl<ScrollViewer>("MessageScrollViewer");
|
|
||||||
if (scroll is null) return;
|
|
||||||
|
|
||||||
ClearHighlight();
|
|
||||||
target.IsHighlighted = true;
|
|
||||||
_highlightedMessage = target;
|
|
||||||
_highlightCts = new CancellationTokenSource();
|
|
||||||
CancellationToken ct = _highlightCts.Token;
|
|
||||||
|
|
||||||
Dispatcher.UIThread.Post(() =>
|
|
||||||
{
|
|
||||||
double? targetY = FindItemY(scroll, target);
|
|
||||||
if (targetY is not null)
|
|
||||||
scroll.Offset = new Vector(scroll.Offset.X, targetY.Value);
|
|
||||||
}, DispatcherPriority.Render);
|
|
||||||
|
|
||||||
_ = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await Task.Delay(2000, ct);
|
|
||||||
Dispatcher.UIThread.Post(() =>
|
|
||||||
{
|
|
||||||
target.IsHighlighted = false;
|
|
||||||
if (_highlightedMessage == target)
|
|
||||||
_highlightedMessage = null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
catch (OperationCanceledException)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private static double? FindItemY(Visual parent, MessageViewModel target)
|
|
||||||
{
|
|
||||||
foreach (Visual child in parent.GetVisualChildren())
|
|
||||||
{
|
|
||||||
if (child.DataContext == target)
|
|
||||||
return child.Bounds.Y;
|
|
||||||
|
|
||||||
double? result = FindItemY(child, target);
|
|
||||||
if (result.HasValue)
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private MessageViewModel? _highlightedMessage;
|
|
||||||
private CancellationTokenSource? _highlightCts;
|
|
||||||
|
|
||||||
private void ClearHighlight()
|
private void ClearHighlight()
|
||||||
{
|
{
|
||||||
_highlightCts?.Cancel();
|
_highlightCts?.Cancel();
|
||||||
|
|||||||
Reference in New Issue
Block a user