From e85f49dc8604a39f05b83cf369a6524168ce2aef Mon Sep 17 00:00:00 2001 From: atsvirchkova Date: Tue, 24 Nov 2020 14:35:32 +0100 Subject: [PATCH 1/5] Timeline UI - Gap block starting from last te until current time (win) --- .../ui/Resources/DesignUpdate/Buttons.xaml | 25 +++++++++++-- .../ui/Resources/DesignUpdate/Icons.xaml | 3 ++ .../ui/Resources/TimelineConstants.cs | 1 + .../ui/ViewModels/TimelineViewModel.cs | 36 +++++++++++++++++-- .../TogglDesktop/ui/views/Timeline.xaml | 14 ++++++-- 5 files changed, 72 insertions(+), 7 deletions(-) diff --git a/src/ui/windows/TogglDesktop/TogglDesktop/ui/Resources/DesignUpdate/Buttons.xaml b/src/ui/windows/TogglDesktop/TogglDesktop/ui/Resources/DesignUpdate/Buttons.xaml index 44ad9c7e31..d657a12554 100644 --- a/src/ui/windows/TogglDesktop/TogglDesktop/ui/Resources/DesignUpdate/Buttons.xaml +++ b/src/ui/windows/TogglDesktop/TogglDesktop/ui/Resources/DesignUpdate/Buttons.xaml @@ -358,9 +358,28 @@ RadiusX="15" RadiusY="7"> - - - + + + + + + + + + + \ No newline at end of file diff --git a/src/ui/windows/TogglDesktop/TogglDesktop/ui/Resources/TimelineConstants.cs b/src/ui/windows/TogglDesktop/TogglDesktop/ui/Resources/TimelineConstants.cs index 9e274923e0..f5fc70dbfe 100644 --- a/src/ui/windows/TogglDesktop/TogglDesktop/ui/Resources/TimelineConstants.cs +++ b/src/ui/windows/TogglDesktop/TogglDesktop/ui/Resources/TimelineConstants.cs @@ -13,6 +13,7 @@ public static class TimelineConstants public const double TimeEntryBlockWidth = 20; public const double GapBetweenOverlappingTEs = 5; public const double AcceptableBlocksOverlap = 1e-5; + public const double MinGapTimeEntryHeight = 10; public static IReadOnlyDictionary ScaleModes { get; } = new Dictionary() { diff --git a/src/ui/windows/TogglDesktop/TogglDesktop/ui/ViewModels/TimelineViewModel.cs b/src/ui/windows/TogglDesktop/TogglDesktop/ui/ViewModels/TimelineViewModel.cs index 708b8dd28c..f3cddf2adf 100644 --- a/src/ui/windows/TogglDesktop/TogglDesktop/ui/ViewModels/TimelineViewModel.cs +++ b/src/ui/windows/TogglDesktop/TogglDesktop/ui/ViewModels/TimelineViewModel.cs @@ -5,6 +5,7 @@ using System.Reactive; using System.Reactive.Linq; using System.Threading.Tasks; +using MahApps.Metro.Controls; using ReactiveUI; using ReactiveUI.Fody.Helpers; using TogglDesktop.Resources; @@ -70,6 +71,10 @@ public TimelineViewModel() .ToPropertyEx(this, x => x.TimeEntryBlocks); blocksObservable.Select(blocks => GenerateGapTimeEntryBlocks(blocks.Values.ToList(), SelectedScaleMode, SelectedDate)) .ToPropertyEx(this, x => x.GapTimeEntryBlocks); + blocksWithRunningObservable.Where(tuple => tuple.Running == null && SelectedDate.Date == DateTime.Today) + .Select(tuple => + GenerateRunningGapBlock(tuple.TimeEntries.Values, CurrentTimeOffset, SelectedScaleMode, SelectedDate)) + .ToPropertyEx(this, x => x.RunningGapTimeEntryBlock); this.WhenAnyValue(x => x.TimeEntryBlocks) .Where(blocks => blocks != null && blocks.Any()) @@ -92,6 +97,9 @@ public TimelineViewModel() .Select(off => Math.Max(TimelineConstants.MinTimeEntryBlockHeight, CurrentTimeOffset - RunningTimeEntryBlock.VerticalOffset)) .Subscribe(h => RunningTimeEntryBlock.Height = h); + this.WhenAnyValue(x => x.CurrentTimeOffset).Where(_ => RunningGapTimeEntryBlock != null) + .Select(off => CurrentTimeOffset - RunningGapTimeEntryBlock.VerticalOffset) + .Subscribe(h => RunningGapTimeEntryBlock.Height = h); this.WhenAnyValue(x => x.TimeEntryBlocks, x => x.RunningTimeEntryBlock, x => x.IsTodaySelected, (blocks, running, isToday) => blocks?.Any() == true || (running != null && isToday)) .ToPropertyEx(this, x => x.AnyTimeEntries); @@ -303,17 +311,39 @@ private static List GenerateGapTimeEntryBlocks(List 10) // Don't display to small gaps not to obstruct the view + if (block.Height >= TimelineConstants.MinGapTimeEntryHeight) // Don't display too small gaps not to obstruct the view gaps.Add(block); } lastTimeEntry = lastTimeEntry == null || entry.Bottom > lastTimeEntry.Bottom ? entry : lastTimeEntry; } - + return gaps; } + private static GapTimeEntryBlock GenerateRunningGapBlock(IEnumerable timeEntries, double curTimeOffset, + int selectedScaleMode, DateTime selectedDate) + { + var lastTimeEntryBottom = timeEntries.Any() ? timeEntries.Max(te => te.Bottom) : 0; + if (!lastTimeEntryBottom.IsCloseTo(0) && curTimeOffset >= lastTimeEntryBottom + TimelineConstants.MinGapTimeEntryHeight) + return new GapTimeEntryBlock( + (offset, height) => + { + var id = Toggl.Start("", "", 0, 0, "", ""); + var started = TimelineUtils.ConvertOffsetToUnixTime(offset, selectedDate, + TimelineConstants.ScaleModes[selectedScaleMode]); + Toggl.SetTimeEntryStartTimeStamp(id, (long)started); + return id; + }) + { + Height = curTimeOffset - lastTimeEntryBottom, + VerticalOffset = lastTimeEntryBottom, + HorizontalOffset = 0 + }; + return null; + } + public static string AddNewTimeEntry(double offset, double height, int scaleMode, DateTime date) { var started = TimelineUtils.ConvertOffsetToUnixTime(offset, date, @@ -355,6 +385,8 @@ public static string AddNewTimeEntry(double offset, double height, int scaleMode public List GapTimeEntryBlocks { [ObservableAsProperty] get; } + public GapTimeEntryBlock RunningGapTimeEntryBlock { [ObservableAsProperty] get; } + [Reactive] public string SelectedForEditTEId { get; set; } public ReactiveCommand IncreaseScale { get; } diff --git a/src/ui/windows/TogglDesktop/TogglDesktop/ui/views/Timeline.xaml b/src/ui/windows/TogglDesktop/TogglDesktop/ui/views/Timeline.xaml index 6290fa8709..c64fa72434 100644 --- a/src/ui/windows/TogglDesktop/TogglDesktop/ui/views/Timeline.xaml +++ b/src/ui/windows/TogglDesktop/TogglDesktop/ui/views/Timeline.xaml @@ -151,10 +151,11 @@ MouseDown="OnTimeEntryCanvasMouseDown" MouseMove="OnTimeEntryCanvasMouseMove" MouseUp="OnTimeEntryCanvasMouseUp"/> - + + Canvas.Left="{Binding HorizontalOffset}" + Visibility="{Binding Path=., Converter={StaticResource NullToCollapsedConverter}}"> + Date: Thu, 26 Nov 2020 16:45:28 +0100 Subject: [PATCH 2/5] Timeline UI - fixes for running gap TE --- .../ui/Resources/DesignUpdate/Buttons.xaml | 2 +- .../TogglDesktop/ui/ViewModels/TimelineViewModel.cs | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ui/windows/TogglDesktop/TogglDesktop/ui/Resources/DesignUpdate/Buttons.xaml b/src/ui/windows/TogglDesktop/TogglDesktop/ui/Resources/DesignUpdate/Buttons.xaml index d657a12554..6a8a0ca27b 100644 --- a/src/ui/windows/TogglDesktop/TogglDesktop/ui/Resources/DesignUpdate/Buttons.xaml +++ b/src/ui/windows/TogglDesktop/TogglDesktop/ui/Resources/DesignUpdate/Buttons.xaml @@ -368,7 +368,7 @@ - + diff --git a/src/ui/windows/TogglDesktop/TogglDesktop/ui/ViewModels/TimelineViewModel.cs b/src/ui/windows/TogglDesktop/TogglDesktop/ui/ViewModels/TimelineViewModel.cs index f3cddf2adf..24dd1a2458 100644 --- a/src/ui/windows/TogglDesktop/TogglDesktop/ui/ViewModels/TimelineViewModel.cs +++ b/src/ui/windows/TogglDesktop/TogglDesktop/ui/ViewModels/TimelineViewModel.cs @@ -71,9 +71,9 @@ public TimelineViewModel() .ToPropertyEx(this, x => x.TimeEntryBlocks); blocksObservable.Select(blocks => GenerateGapTimeEntryBlocks(blocks.Values.ToList(), SelectedScaleMode, SelectedDate)) .ToPropertyEx(this, x => x.GapTimeEntryBlocks); - blocksWithRunningObservable.Where(tuple => tuple.Running == null && SelectedDate.Date == DateTime.Today) + blocksWithRunningObservable .Select(tuple => - GenerateRunningGapBlock(tuple.TimeEntries.Values, CurrentTimeOffset, SelectedScaleMode, SelectedDate)) + GenerateRunningGapBlock(tuple.TimeEntries.Values, tuple.Running, CurrentTimeOffset, SelectedScaleMode, SelectedDate)) .ToPropertyEx(this, x => x.RunningGapTimeEntryBlock); this.WhenAnyValue(x => x.TimeEntryBlocks) @@ -322,11 +322,11 @@ private static List GenerateGapTimeEntryBlocks(List timeEntries, double curTimeOffset, - int selectedScaleMode, DateTime selectedDate) + private static GapTimeEntryBlock GenerateRunningGapBlock(IEnumerable timeEntries, Toggl.TogglTimeEntryView? running, + double curTimeOffset, int selectedScaleMode, DateTime selectedDate) { var lastTimeEntryBottom = timeEntries.Any() ? timeEntries.Max(te => te.Bottom) : 0; - if (!lastTimeEntryBottom.IsCloseTo(0) && curTimeOffset >= lastTimeEntryBottom + TimelineConstants.MinGapTimeEntryHeight) + if (running == null && selectedDate.Date == DateTime.Today && !lastTimeEntryBottom.IsCloseTo(0) && curTimeOffset >= lastTimeEntryBottom + TimelineConstants.MinGapTimeEntryHeight) return new GapTimeEntryBlock( (offset, height) => { From 362508566c26f35e4a4cb74b0c4ae7806fb4fcf2 Mon Sep 17 00:00:00 2001 From: atsvirchkova Date: Fri, 27 Nov 2020 17:25:36 +0100 Subject: [PATCH 3/5] Timeline UI - extract common observable (win) --- .../TogglDesktop/ui/ViewModels/TimelineViewModel.cs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/ui/windows/TogglDesktop/TogglDesktop/ui/ViewModels/TimelineViewModel.cs b/src/ui/windows/TogglDesktop/TogglDesktop/ui/ViewModels/TimelineViewModel.cs index 24dd1a2458..6444424df9 100644 --- a/src/ui/windows/TogglDesktop/TogglDesktop/ui/ViewModels/TimelineViewModel.cs +++ b/src/ui/windows/TogglDesktop/TogglDesktop/ui/ViewModels/TimelineViewModel.cs @@ -93,13 +93,12 @@ public TimelineViewModel() Observable.Timer(TimeSpan.Zero,TimeSpan.FromMinutes(1)) .Select(_ => ConvertTimeIntervalToHeight(DateTime.Today, DateTime.Now, SelectedScaleMode)) .Subscribe(h => CurrentTimeOffset = h); - this.WhenAnyValue(x => x.CurrentTimeOffset).Where(_ => RunningTimeEntryBlock != null) - .Select(off => Math.Max(TimelineConstants.MinTimeEntryBlockHeight, - CurrentTimeOffset - RunningTimeEntryBlock.VerticalOffset)) - .Subscribe(h => RunningTimeEntryBlock.Height = h); - this.WhenAnyValue(x => x.CurrentTimeOffset).Where(_ => RunningGapTimeEntryBlock != null) - .Select(off => CurrentTimeOffset - RunningGapTimeEntryBlock.VerticalOffset) - .Subscribe(h => RunningGapTimeEntryBlock.Height = h); + var setCurrentHeightObservable = this.WhenAnyValue(x => x.CurrentTimeOffset).Select>(offset => + block => block.Height = offset - block.VerticalOffset); + setCurrentHeightObservable.Where(_ => RunningTimeEntryBlock != null).Subscribe(next => + next(RunningTimeEntryBlock)); + setCurrentHeightObservable.Where(_ => RunningGapTimeEntryBlock != null).Subscribe(next => + next(RunningGapTimeEntryBlock)); this.WhenAnyValue(x => x.TimeEntryBlocks, x => x.RunningTimeEntryBlock, x => x.IsTodaySelected, (blocks, running, isToday) => blocks?.Any() == true || (running != null && isToday)) .ToPropertyEx(this, x => x.AnyTimeEntries); From 410e910b5fcc67fdd56ee3f367dfaece3238d327 Mon Sep 17 00:00:00 2001 From: atsvirchkova Date: Tue, 1 Dec 2020 11:43:37 +0100 Subject: [PATCH 4/5] Timeline UI - small fixes for running gap (win) --- .../ui/Resources/DesignUpdate/Buttons.xaml | 10 +++++----- .../ui/Resources/DesignUpdate/Icons.xaml | 2 +- .../ui/ViewModels/TimelineViewModel.cs | 19 +++++++++---------- .../TogglDesktop/ui/views/Timeline.xaml | 2 +- .../TogglDesktop/utilities/Utils.cs | 11 ++++++++++- 5 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/ui/windows/TogglDesktop/TogglDesktop/ui/Resources/DesignUpdate/Buttons.xaml b/src/ui/windows/TogglDesktop/TogglDesktop/ui/Resources/DesignUpdate/Buttons.xaml index 6a8a0ca27b..12d1d9d168 100644 --- a/src/ui/windows/TogglDesktop/TogglDesktop/ui/Resources/DesignUpdate/Buttons.xaml +++ b/src/ui/windows/TogglDesktop/TogglDesktop/ui/Resources/DesignUpdate/Buttons.xaml @@ -358,13 +358,13 @@ RadiusX="15" RadiusY="7"> - + - - + \ No newline at end of file diff --git a/src/ui/windows/TogglDesktop/TogglDesktop/ui/ViewModels/TimelineViewModel.cs b/src/ui/windows/TogglDesktop/TogglDesktop/ui/ViewModels/TimelineViewModel.cs index 6444424df9..b971d41f4b 100644 --- a/src/ui/windows/TogglDesktop/TogglDesktop/ui/ViewModels/TimelineViewModel.cs +++ b/src/ui/windows/TogglDesktop/TogglDesktop/ui/ViewModels/TimelineViewModel.cs @@ -5,7 +5,6 @@ using System.Reactive; using System.Reactive.Linq; using System.Threading.Tasks; -using MahApps.Metro.Controls; using ReactiveUI; using ReactiveUI.Fody.Helpers; using TogglDesktop.Resources; @@ -93,12 +92,10 @@ public TimelineViewModel() Observable.Timer(TimeSpan.Zero,TimeSpan.FromMinutes(1)) .Select(_ => ConvertTimeIntervalToHeight(DateTime.Today, DateTime.Now, SelectedScaleMode)) .Subscribe(h => CurrentTimeOffset = h); - var setCurrentHeightObservable = this.WhenAnyValue(x => x.CurrentTimeOffset).Select>(offset => - block => block.Height = offset - block.VerticalOffset); - setCurrentHeightObservable.Where(_ => RunningTimeEntryBlock != null).Subscribe(next => - next(RunningTimeEntryBlock)); - setCurrentHeightObservable.Where(_ => RunningGapTimeEntryBlock != null).Subscribe(next => - next(RunningGapTimeEntryBlock)); + this.WhenAnyValue(x => x.CurrentTimeOffset).Select(offset => (Offset: offset, + Block: RunningTimeEntryBlock as TimelineBlockViewModel ?? RunningGapTimeEntryBlock)) + .Where(tuple => tuple.Block != null) + .Subscribe(tuple => tuple.Block.Height = tuple.Offset - tuple.Block.VerticalOffset); this.WhenAnyValue(x => x.TimeEntryBlocks, x => x.RunningTimeEntryBlock, x => x.IsTodaySelected, (blocks, running, isToday) => blocks?.Any() == true || (running != null && isToday)) .ToPropertyEx(this, x => x.AnyTimeEntries); @@ -246,7 +243,7 @@ private static Dictionary ConvertTimeEntriesToBlocks(Lis var time1 = te1.Type == TimeStampType.End ? te1.Block.Bottom : te1.Block.VerticalOffset; var time2 = te2.Type == TimeStampType.End ? te2.Block.Bottom : te2.Block.VerticalOffset; var res = time1 - time2; - if (Math.Abs(res) < TimelineConstants.AcceptableBlocksOverlap) + if (res.IsNearEqual(0, TimelineConstants.AcceptableBlocksOverlap)) { var getPriority = new Func(t => t == TimeStampType.End ? 0 : t == TimeStampType.Empty ? 1 : 2); @@ -324,8 +321,10 @@ private static List GenerateGapTimeEntryBlocks(List timeEntries, Toggl.TogglTimeEntryView? running, double curTimeOffset, int selectedScaleMode, DateTime selectedDate) { - var lastTimeEntryBottom = timeEntries.Any() ? timeEntries.Max(te => te.Bottom) : 0; - if (running == null && selectedDate.Date == DateTime.Today && !lastTimeEntryBottom.IsCloseTo(0) && curTimeOffset >= lastTimeEntryBottom + TimelineConstants.MinGapTimeEntryHeight) + if (running != null || selectedDate.Date != DateTime.Today) return null; + + var lastTimeEntryBottom = timeEntries.Select(te => te.Bottom).DefaultIfEmpty(0).Max(); + if (!lastTimeEntryBottom.IsNearEqual(0) && curTimeOffset >= lastTimeEntryBottom + TimelineConstants.MinGapTimeEntryHeight) return new GapTimeEntryBlock( (offset, height) => { diff --git a/src/ui/windows/TogglDesktop/TogglDesktop/ui/views/Timeline.xaml b/src/ui/windows/TogglDesktop/TogglDesktop/ui/views/Timeline.xaml index c64fa72434..aac1ae6ea1 100644 --- a/src/ui/windows/TogglDesktop/TogglDesktop/ui/views/Timeline.xaml +++ b/src/ui/windows/TogglDesktop/TogglDesktop/ui/views/Timeline.xaml @@ -167,7 +167,7 @@