Add ClipboardCopyButton
Used in PreviewItem
MODIFY
WalletWasabi.Fluent/App.axaml
WalletWasabi.Fluent/App.axaml
<StyleInclude Source="avares://WalletWasabi.Fluent/Controls/StatusItem.axaml" />
<StyleInclude Source="avares://WalletWasabi.Fluent/Controls/PrivacyContentControl.axaml" />
<StyleInclude Source="avares://WalletWasabi.Fluent/Controls/SuggestionItem.axaml" />
+ <StyleInclude Source="avares://WalletWasabi.Fluent/Controls/ClipboardCopyButton.axaml" />
</Application.Styles>
<NativeMenu.Menu>
<NativeMenu>

ADD
WalletWasabi.Fluent/Controls/ClipboardCopyButton.axaml
+<Styles xmlns="https://github.com/avaloniaui"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:c="using:WalletWasabi.Fluent.Controls">
+ <Design.PreviewWith>
+ <c:ClipboardCopyButton Height="100" Width="200" />
+ </Design.PreviewWith>
+
+ <Style Selector="c|ClipboardCopyButton">
+ <Setter Property="Template">
+ <ControlTemplate>
+ <Panel>
+ <c:AnimatedButton x:Name="CopyButton" Command="{TemplateBinding CopyCommand}"
+ ToolTip.Tip="{Binding ToolTipText}"
+ NormalIcon="{StaticResource copy_regular}"
+ ClickIcon="{StaticResource copy_confirmed}"
+ InitialOpacity="0.6"/>
+ <Popup IsOpen="{TemplateBinding IsPopupOpen}" PlacementTarget="CopyButton" PlacementMode="AnchorAndGravity" PlacementGravity="Top" PlacementAnchor="Top">
+ <Border Margin="6" Padding="10" Background="{StaticResource SystemBaseLowColor}" BorderBrush="{StaticResource TextForegroundColor}" CornerRadius="10" BorderThickness="1">
+ <TextBlock Text="{TemplateBinding CopiedMessage}" />
+ </Border>
+ </Popup>
+ </Panel>
+ </ControlTemplate>
+ </Setter>
+ </Style>
+</Styles>

ADD
WalletWasabi.Fluent/Controls/ClipboardCopyButton.axaml.cs
+using System.Reactive;
+using System.Reactive.Linq;
+using System.Threading.Tasks;
+using Avalonia;
+using Avalonia.Controls.Primitives;
+using ReactiveUI;
+
+namespace WalletWasabi.Fluent.Controls;
+
+public class ClipboardCopyButton : TemplatedControl
+{
+ public static readonly StyledProperty<ReactiveCommand<Unit, Unit>> CopyCommandProperty =
+ AvaloniaProperty.Register<ClipboardCopyButton, ReactiveCommand<Unit, Unit>>(nameof(CopyCommand));
+
+ public static readonly StyledProperty<bool> IsPopupOpenProperty =
+ AvaloniaProperty.Register<ClipboardCopyButton, bool>(nameof(IsPopupOpen));
+
+ public static readonly StyledProperty<string> TextProperty =
+ AvaloniaProperty.Register<ClipboardCopyButton, string>(nameof(Text));
+
+ public static readonly StyledProperty<string> CopiedMessageProperty =
+ AvaloniaProperty.Register<ClipboardCopyButton, string>(nameof(Text), "Copied");
+
+ public ReactiveCommand<Unit, Unit> CopyCommand
+ {
+ get => GetValue(CopyCommandProperty);
+ set => SetValue(CopyCommandProperty, value);
+ }
+
+ public bool IsPopupOpen
+ {
+ get => GetValue(IsPopupOpenProperty);
+ set => SetValue(IsPopupOpenProperty, value);
+ }
+
+ public string Text
+ {
+ get => GetValue(TextProperty);
+ set => SetValue(TextProperty, value);
+ }
+
+ public string CopiedMessage
+ {
+ get => GetValue(CopiedMessageProperty);
+ set => SetValue(CopiedMessageProperty, value);
+ }
+
+ public ClipboardCopyButton()
+ {
+ CopyCommand = ReactiveCommand.CreateFromTask(CopyToClipboard);
+ var obs = CopyCommand.Select(unit => true)
+ .Merge(CopyCommand.Delay(TimeSpan.FromSeconds(2)).Select(_ => false));
+
+ var o = CopyCommand
+ .Select(unit =>
+ Observable.Return(true).Concat(Observable.Timer(HidePopupTime).Select(l => false)))
+ .Switch();
+
+ this.Bind(IsPopupOpenProperty, o);
+ }
+
+ public TimeSpan HidePopupTime { get; set; } = TimeSpan.FromSeconds(2);
+
+ private async Task CopyToClipboard()
+ {
+ if (Application.Current is {Clipboard: { } clipboard})
+ {
+ await clipboard.SetTextAsync(Text);
+ }
+ }
+}
\ No newline at end of file

MODIFY
WalletWasabi.Fluent/Controls/PreviewItem.axaml
WalletWasabi.Fluent/Controls/PreviewItem.axaml
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="using:WalletWasabi.Fluent.Controls">
+ <Design.PreviewWith>
+ <c:PreviewItem Text="Text to preview"></c:PreviewItem>
+ </Design.PreviewWith>
+
<Style Selector="c|PreviewItem">
<Setter Property="Template">
<ControlTemplate>
<DockPanel DockPanel.Dock="Right" Margin="30 0 0 0">
<TextBlock Name="PART_Text" Text="{TemplateBinding Text}" DockPanel.Dock="Top" Margin="0 0 0 5" Opacity="0.6" />
<DockPanel HorizontalAlignment="Left" DockPanel.Dock="Bottom">
- <Panel DockPanel.Dock="Right"
- Width="30">
- <c:AnimatedButton Command="{TemplateBinding CopyCommand}"
- CommandParameter="{TemplateBinding CopyParameter}"
- ToolTip.Tip="Copy"
- NormalIcon="{StaticResource copy_regular}"
- ClickIcon="{StaticResource copy_confirmed}"
- InitialOpacity="0.6"
- IsVisible="{TemplateBinding CopyButtonVisibility}" />
- </Panel>
+ <c:ClipboardCopyButton DockPanel.Dock="Right" Width="30" Text="{TemplateBinding Text}" IsVisible="{TemplateBinding CopyButtonVisibility}" />
<Panel>
<ContentPresenter Name="PART_ContentPresenter" Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"

MODIFY
WalletWasabi.Fluent/Controls/PreviewItem.axaml.cs
WalletWasabi.Fluent/Controls/PreviewItem.axaml.cs
-using System.Diagnostics;
-using System.Threading.Tasks;
using System.Windows.Input;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Media;
using ReactiveUI;
-using WalletWasabi.Fluent.Extensions;
namespace WalletWasabi.Fluent.Controls;
@@ -35,49 +32,9 @@ public class PreviewItem : ContentControl
public static readonly StyledProperty<bool> PrivacyModeEnabledProperty =
AvaloniaProperty.Register<PreviewItem, bool>(nameof(PrivacyModeEnabled));
- private Stopwatch? _copyButtonPressedStopwatch;
-
public PreviewItem()
{
- CopyCommand = ReactiveCommand.CreateFromTask<object>(async obj =>
- {
- if (obj.ToString() is { } text)
- {
- _copyButtonPressedStopwatch = Stopwatch.StartNew();
-
- if (Application.Current is { Clipboard: { } clipboard })
- {
- await clipboard.SetTextAsync(text);
- }
- }
- });
-
- this.WhenAnyValue(x => x.Icon)
- .Subscribe(x => IsIconVisible = x is not null);
-
- this.WhenAnyValue(
- x => x.CopyParameter,
- x => x.IsPointerOver,
- x => x.PrivacyModeEnabled,
- (copyParameter, isPointerOver, privacyModeEnabled) => !string.IsNullOrEmpty(copyParameter?.ToString()) && isPointerOver && !privacyModeEnabled)
- .SubscribeAsync(async value =>
- {
- if (_copyButtonPressedStopwatch is { } sw)
- {
- var elapsedMilliseconds = sw.ElapsedMilliseconds;
-
- var millisecondsToWait = 1050 - (int)elapsedMilliseconds;
-
- if (millisecondsToWait > 0)
- {
- await Task.Delay(millisecondsToWait);
- }
-
- _copyButtonPressedStopwatch = null;
- }
-
- CopyButtonVisibility = value;
- });
+ this.Bind(CopyButtonVisibilityProperty, this.WhenAnyValue(item => item.IsPointerOver));
}
public string Text

Add ClipboardCopyButton

Used in PreviewItem