Add privacy reveal after pointer over for n seconds
MODIFY
WalletWasabi.Fluent/Controls/PrivacyContentControl.axaml
WalletWasabi.Fluent/Controls/PrivacyContentControl.axaml
<ControlTemplate>
<Panel Background="Transparent">
<ContentPresenter Name="PART_Content"
- IsVisible="{TemplateBinding IsContentVisible}"
+ IsVisible="{Binding RevealContent^, RelativeSource={RelativeSource Mode=TemplatedParent}}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" />
<Panel Name="PART_PrivacyReplacement"
- IsVisible="{TemplateBinding IsPrivacyContentVisible}">
+ IsVisible="{Binding !RevealContent^, RelativeSource={RelativeSource Mode=TemplatedParent}}">
<Viewbox Name="PART_Icon">
<PathIcon Data="{StaticResource incognito_pathicon}" />
</Viewbox>

MODIFY
WalletWasabi.Fluent/Controls/PrivacyContentControl.axaml.cs
WalletWasabi.Fluent/Controls/PrivacyContentControl.axaml.cs
-using Avalonia;
-using System.Linq;
-using System.Reactive.Disposables;
using System.Reactive.Linq;
+using Avalonia;
using Avalonia.Controls;
using ReactiveUI;
+using WalletWasabi.Fluent.Extensions;
using WalletWasabi.Fluent.Helpers;
-using WalletWasabi.Fluent.ViewModels;
namespace WalletWasabi.Fluent.Controls;
@@ -17,7 +15,7 @@ public enum ReplacementMode
public class PrivacyContentControl : ContentControl
{
- private CompositeDisposable? _disposable;
+ private static readonly TimeSpan RevealDelay = TimeSpan.FromSeconds(1.5);
public static readonly StyledProperty<bool> IsPrivacyContentVisibleProperty =
AvaloniaProperty.Register<PrivacyContentControl, bool>(nameof(IsPrivacyContentVisible));
@@ -37,6 +35,29 @@ public class PrivacyContentControl : ContentControl
public static readonly StyledProperty<bool> ForceShowProperty =
AvaloniaProperty.Register<PrivacyContentControl, bool>(nameof(ForceShow));
+ public PrivacyContentControl()
+ {
+ if (Design.IsDesignMode)
+ {
+ return;
+ }
+
+ var isPrivacyModeEnabled = Services.UiConfig.WhenAnyValue(x => x.PrivacyMode);
+ var isPointerOver = this.WhenAnyValue(x => x.IsPointerOver).DelayTrue(RevealDelay);
+ var isForced = this.WhenAnyValue(x => x.ForceShow);
+
+ var displayContent = isPrivacyModeEnabled.CombineLatest(
+ isPointerOver,
+ isForced,
+ (privacyModeEnabled, pointerOver, forced) => !privacyModeEnabled || pointerOver || forced);
+
+ RevealContent = displayContent
+ .ObserveOn(RxApp.MainThreadScheduler)
+ .Replay(1).RefCount();
+
+ PrivacyText = TextHelpers.GetPrivacyMask((int) NumberOfPrivacyChars);
+ }
+
private bool IsPrivacyContentVisible
{
get => GetValue(IsPrivacyContentVisibleProperty);
@@ -73,38 +94,5 @@ public class PrivacyContentControl : ContentControl
set => SetValue(ForceShowProperty, value);
}
- protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
- {
- if (Design.IsDesignMode)
- {
- return;
- }
-
- base.OnAttachedToVisualTree(e);
-
- _disposable = new CompositeDisposable();
-
- Services.UiConfig
- .WhenAnyValue(x => x.PrivacyMode)
- .Merge(this.WhenAnyValue(x => x.ForceShow))
- .ObserveOn(RxApp.MainThreadScheduler)
- .Subscribe(_ =>
- {
- var value = !Services.UiConfig.PrivacyMode || ForceShow;
-
- IsPrivacyContentVisible = !value;
- IsContentVisible = value;
- })
- .DisposeWith(_disposable);
-
- PrivacyText = TextHelpers.GetPrivacyMask((int)NumberOfPrivacyChars);
- }
-
- protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
- {
- base.OnDetachedFromVisualTree(e);
-
- _disposable?.Dispose();
- _disposable = null;
- }
+ private IObservable<bool> RevealContent { get; }
}

MODIFY
WalletWasabi.Fluent/Extensions/ObservableMixin.cs
WalletWasabi.Fluent/Extensions/ObservableMixin.cs
@@ -4,14 +4,10 @@ namespace WalletWasabi.Fluent.Extensions;
public static class ObservableMixin
{
- public static IObservable<T> DelayWhen<T>(this IObservable<T> observable, Func<T, bool> filter, TimeSpan ts)
+ public static IObservable<bool> DelayTrue(this IObservable<bool> obs, TimeSpan ts)
{
- return observable
- .Select(x => filter(x) ? Observable.Return(x).Delay(ts) : Observable.Return(x)).Concat();
- }
-
- public static IObservable<bool> DelayFalse(this IObservable<bool> observable, TimeSpan ts)
- {
- return DelayWhen(observable, b => !b, ts);
+ return obs
+ .Select(isTrue => isTrue ? Observable.Return(true).Delay(ts) : Observable.Return(false))
+ .Switch();
}
}

Add privacy reveal after pointer over for n seconds