add working sampling to chart tile.
MODIFY
WalletWasabi.Fluent/ViewModels/Wallets/Home/Tiles/WalletBalanceChartTileViewModel.cs
WalletWasabi.Fluent/ViewModels/Wallets/Home/Tiles/WalletBalanceChartTileViewModel.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
-using System.Reactive.Linq;
-using DynamicData;
-using DynamicData.Alias;
+using System.Linq;
+using System.Windows.Input;
using DynamicData.Binding;
using NBitcoin;
using ReactiveUI;
@@ -11,36 +10,133 @@ using WalletWasabi.Fluent.ViewModels.Wallets.Home.History;
namespace WalletWasabi.Fluent.ViewModels.Wallets.Home.Tiles
{
+ public static class EnumerableExtensions
+ {
+ public static IEnumerable<(DateTimeOffset timestamp, TResult result)> TimeSampleDataSet<TSource, TResult>(this IEnumerable<TSource> source,
+ Func<TSource, DateTimeOffset> timeSampler, Func<TSource, TResult> sampler,
+ TimeSpan interval, TimeSpan limit)
+ {
+ if (!source.Any())
+ {
+ yield break;
+ }
+
+ var currentTime = timeSampler(source.First());
+ var endTime = currentTime - limit;
+
+ var lastFound = (currentTime, sampler(source.First()));
+
+ yield return lastFound;
+
+ currentTime -= interval;
+
+ while (currentTime >= endTime)
+ {
+ var current = source.FirstOrDefault(x => timeSampler(x) <= currentTime);
+
+ if (current is { })
+ {
+ lastFound = (currentTime, sampler(current));
+
+ yield return lastFound;
+ }
+ else
+ {
+ yield return lastFound;
+ }
+
+ currentTime -= interval;
+ }
+ }
+ }
+
public partial class WalletBalanceChartTileViewModel : TileViewModel
{
private readonly ReadOnlyObservableCollection<HistoryItemViewModel> _history;
- private readonly ReadOnlyObservableCollection<double> _yValues;
- private readonly ReadOnlyObservableCollection<double> _xValues;
+ [AutoNotify] private ObservableCollection<double> _yValues;
+ [AutoNotify] private ObservableCollection<double> _xValues;
+ private TimeSpan _sampleTime;
+ private TimeSpan _sampleLimit;
+
public WalletBalanceChartTileViewModel(ReadOnlyObservableCollection<HistoryItemViewModel> history)
{
+ _sampleTime = TimeSpan.FromDays(1);
+ _sampleLimit = TimeSpan.FromDays(30);
+
_history = history;
+ _yValues = new ObservableCollection<double>();
+ _xValues = new ObservableCollection<double>();
- _history
- .ToObservableChangeSet()
- .Select(x => (double) x.Balance.ToDecimal(MoneyUnit.BTC))
- .Reverse()
- .ObserveOn(RxApp.MainThreadScheduler)
- .Bind(out _yValues)
- .DisposeMany()
- .Subscribe();
+ var filtered = _history.ToObservableChangeSet().Subscribe(_ => UpdateSample ());
- _history
- .ToObservableChangeSet()
- .Select(x => (double) x.Date.ToUnixTimeSeconds())
- .ObserveOn(RxApp.MainThreadScheduler)
- .Bind(out _xValues)
- .DisposeMany()
- .Subscribe();
+ DayCommand = ReactiveCommand.Create(() =>
+ {
+ _sampleTime = TimeSpan.FromHours(0.5);
+ _sampleLimit = TimeSpan.FromDays(1);
+ UpdateSample();
+ });
+
+ WeekCommand = ReactiveCommand.Create(() =>
+ {
+ _sampleTime = TimeSpan.FromHours(12);
+ _sampleLimit = TimeSpan.FromDays(7);
+ UpdateSample();
+ });
+
+ MonthCommand = ReactiveCommand.Create(() =>
+ {
+ _sampleTime = TimeSpan.FromDays(1);
+ _sampleLimit = TimeSpan.FromDays(30);
+ UpdateSample();
+ });
+
+ ThreeMonthCommand = ReactiveCommand.Create(() =>
+ {
+ _sampleTime = TimeSpan.FromDays(2);
+ _sampleLimit = TimeSpan.FromDays(90);
+ UpdateSample();
+ });
+
+ SixMonthCommand = ReactiveCommand.Create(() =>
+ {
+ _sampleTime = TimeSpan.FromDays(3.5);
+ _sampleLimit = TimeSpan.FromDays(182.5);
+ UpdateSample();
+ });
+
+ YearCommand = ReactiveCommand.Create(() =>
+ {
+ _sampleTime = TimeSpan.FromDays(7);
+ _sampleLimit = TimeSpan.FromDays(365);
+ UpdateSample();
+ });
}
- public ReadOnlyObservableCollection<double> YValues => _yValues;
+ private void UpdateSample()
+ {
+ var values = _history.TimeSampleDataSet(x => x.Date, x => x.Balance, _sampleTime, _sampleLimit);
+
+ XValues.Clear();
+ YValues.Clear();
+
+ foreach (var (timestamp, balance) in values.Reverse())
+ {
+ YValues.Add((double) balance.ToDecimal(MoneyUnit.BTC));
+ XValues.Add((double) timestamp.ToUnixTimeMilliseconds());
+ }
+ }
+
+ public ICommand DayCommand { get; }
+
+ public ICommand WeekCommand { get; }
+
+ public ICommand MonthCommand { get; }
+
+ public ICommand ThreeMonthCommand { get; }
+
+ public ICommand SixMonthCommand { get; }
- public ReadOnlyObservableCollection<double> XValues => _xValues;
+ public ICommand YearCommand { get; }
}
}
\ No newline at end of file

MODIFY
WalletWasabi.Fluent/Views/Wallets/Home/Tiles/WalletBalanceChartTileView.axaml
WalletWasabi.Fluent/Views/Wallets/Home/Tiles/WalletBalanceChartTileView.axaml
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:c="using:WalletWasabi.Fluent.Controls"
- xmlns:vm="using:WalletWasabi.Fluent.ViewModels.LineChartDemo"
+ xmlns:vm="using:WalletWasabi.Fluent.ViewModels.Wallets.Home.Tiles"
mc:Ignorable="d" d:DesignWidth="620" d:DesignHeight="310"
x:Class="WalletWasabi.Fluent.Views.Wallets.Home.Tiles.WalletBalanceChartTileView">
<UserControl.Styles>
</UserControl.Styles>
<Border ClipToBounds="False" CornerRadius="5" Background="#2b2b2b" Margin="6" Padding="16" BoxShadow="{DynamicResource InfoBoxShadow}">
<DockPanel>
+ <StackPanel Orientation="Horizontal" Spacing="10" DockPanel.Dock="Top">
<TextBlock Text="Balance over time" DockPanel.Dock="Top" />
- <c:LineChart x:Name="GradientLineChart" DockPanel.Dock="Left" Margin="30"
+ <Button Content="1D" Command="{Binding DayCommand}" />
+ <Button Content="1W" Command="{Binding WeekCommand}" />
+ <Button Content="1M" Command="{Binding MonthCommand}" />
+ <Button Content="3M" Command="{Binding ThreeMonthCommand}" />
+ <Button Content="6M" Command="{Binding SixMonthCommand}" />
+ <Button Content="1Y" Command="{Binding YearCommand}" />
+ </StackPanel>
+ <c:LineChart x:CompileBindings="True" x:DataType="vm:WalletBalanceChartTileViewModel" x:Name="GradientLineChart" DockPanel.Dock="Left" Margin="30"
Classes="area border xAxis xAxisLabels yAxis yAxisLabels"
- XAxisLabels="{Binding XAxisLabels}"
XAxisValues="{Binding XValues}"
YAxisValues="{Binding YValues}">
<c:LineChart.AreaFill>

MODIFY
WalletWasabi.Fluent/Views/Wallets/Send/SendView.axaml
WalletWasabi.Fluent/Views/Wallets/Send/SendView.axaml
Value="{Binding XAxisCurrentValueIndex}">
</Slider>
<c:LineChart x:Name="GradientLineChart"
+ XAxisPlotMode="EvenlySpaced"
Margin="18,0,18,0"
Classes="cursor border xAxisLabels yAxis yAxisTitle"
MinHeight="30"

add working sampling to chart tile.