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..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,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/TimelineBlockViewModel.cs b/src/ui/windows/TogglDesktop/TogglDesktop/ui/ViewModels/TimelineBlockViewModel.cs
index 2b683b8757..b54c1d705b 100644
--- a/src/ui/windows/TogglDesktop/TogglDesktop/ui/ViewModels/TimelineBlockViewModel.cs
+++ b/src/ui/windows/TogglDesktop/TogglDesktop/ui/ViewModels/TimelineBlockViewModel.cs
@@ -36,25 +36,19 @@ public GapTimeEntryBlock(Func addNewTimeEntry)
public class TimeEntryBlock : TimelineBlockViewModel
{
- [Reactive]
- public string Color { get; set; }
[Reactive]
public bool ShowDescription { get; set; }
- [Reactive]
- public string Description { get; set; }
- [Reactive]
- public string ProjectName { get; set; }
- [Reactive]
- public string ClientName { get; set; }
- public string TaskName { get; set; }
- [Reactive]
- public bool HasTag { get; set; }
- [Reactive]
- public bool IsBillable { get; set; }
+ public string Color => _timeEntry.Color;
+ public string Description => _timeEntry.Description.IsNullOrEmpty() ? "No Description" : _timeEntry.Description;
+ public string ProjectName => _timeEntry.ProjectLabel;
+ public string ClientName => _timeEntry.ClientLabel;
+ public string TaskName => _timeEntry.TaskLabel;
+ public bool HasTag => !_timeEntry.Tags.IsNullOrEmpty();
+ public bool IsBillable => _timeEntry.Billable;
public string Duration { [ObservableAsProperty]get; }
public string StartEndCaption { [ObservableAsProperty]get; }
public ReactiveCommand OpenEditView { get; }
- public string TimeEntryId { get; }
+ public string TimeEntryId => _timeEntry.GUID;
[Reactive]
public bool IsEditViewOpened { get; set; }
@@ -64,15 +58,19 @@ public class TimeEntryBlock : TimelineBlockViewModel
[Reactive]
public bool IsDragged { get; set; }
- public DateTime DateCreated { get; }
+ public ulong Started => _timeEntry.Started;
+ public ulong Ended => _timeEntry.Ended;
+
+ private DateTime DateCreated { get; }
private readonly double _hourHeight;
+ private readonly Toggl.TogglTimeEntryView _timeEntry;
- public TimeEntryBlock(string timeEntryId, int hourHeight, DateTime date)
+ public TimeEntryBlock(Toggl.TogglTimeEntryView te, int hourHeight, DateTime date)
{
_hourHeight = hourHeight;
DateCreated = date;
- TimeEntryId = timeEntryId;
+ _timeEntry = te;
OpenEditView = ReactiveCommand.Create(() => Toggl.Edit(TimeEntryId, false, Toggl.Description));
var startEndObservable = this.WhenAnyValue(x => x.VerticalOffset, x => x.Height, (offset, height) =>
(Started: TimelineUtils.ConvertOffsetToDateTime(offset, date, _hourHeight), Ended: TimelineUtils.ConvertOffsetToDateTime(offset + height, date, _hourHeight)));
diff --git a/src/ui/windows/TogglDesktop/TogglDesktop/ui/ViewModels/TimelineViewModel.cs b/src/ui/windows/TogglDesktop/TogglDesktop/ui/ViewModels/TimelineViewModel.cs
index 708b8dd28c..814f1d638c 100644
--- a/src/ui/windows/TogglDesktop/TogglDesktop/ui/ViewModels/TimelineViewModel.cs
+++ b/src/ui/windows/TogglDesktop/TogglDesktop/ui/ViewModels/TimelineViewModel.cs
@@ -68,8 +68,12 @@ public TimelineViewModel()
tuple.TimeEntries.Where(b => b.Key != tuple.Running?.GUID)
.ToDictionary(pair => pair.Key, pair => pair.Value))
.ToPropertyEx(this, x => x.TimeEntryBlocks);
- blocksObservable.Select(blocks => GenerateGapTimeEntryBlocks(blocks.Values.ToList(), SelectedScaleMode, SelectedDate))
+ blocksObservable.Select(blocks => GenerateGapTimeEntryBlocks(blocks.Values.ToList()))
.ToPropertyEx(this, x => x.GapTimeEntryBlocks);
+ blocksWithRunningObservable
+ .Select(tuple =>
+ GenerateRunningGapBlock(tuple.TimeEntries.Values, tuple.Running, CurrentTimeOffset, SelectedDate))
+ .ToPropertyEx(this, x => x.RunningGapTimeEntryBlock);
this.WhenAnyValue(x => x.TimeEntryBlocks)
.Where(blocks => blocks != null && blocks.Any())
@@ -88,10 +92,10 @@ 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).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);
@@ -205,18 +209,11 @@ private static Dictionary ConvertTimeEntriesToBlocks(Lis
? TimelineUtils.ConvertOffsetToUnixTime(currentTimeOffset, selectedDate, TimelineConstants.ScaleModes[selectedScaleMode])
: entry.Ended;
var height = ConvertTimeIntervalToHeight(startTime, Toggl.DateTimeFromUnix(ended), selectedScaleMode);
- var block = new TimeEntryBlock(entry.GUID, TimelineConstants.ScaleModes[selectedScaleMode], selectedDate)
+ var block = new TimeEntryBlock(entry, TimelineConstants.ScaleModes[selectedScaleMode], selectedDate)
{
Height = height,
VerticalOffset = ConvertTimeIntervalToHeight(selectedDate, startTime, selectedScaleMode),
- Color = entry.Color,
- Description = entry.Description.IsNullOrEmpty() ? "No Description" : entry.Description,
- ProjectName = entry.ProjectLabel,
- ClientName = entry.ClientLabel,
- TaskName = entry.TaskLabel,
- ShowDescription = true,
- HasTag = !entry.Tags.IsNullOrEmpty(),
- IsBillable = entry.Billable
+ ShowDescription = true
};
if (entry.Started < ended)
{
@@ -239,7 +236,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);
@@ -288,7 +285,7 @@ public static double ConvertTimeIntervalToHeight(DateTime start, DateTime end, i
return timeInterval * TimelineConstants.ScaleModes[scaleMode] / 60;
}
- private static List GenerateGapTimeEntryBlocks(List timeEntries, int selectedScaleMode, DateTime selectedDate)
+ private static List GenerateGapTimeEntryBlocks(List timeEntries)
{
var gaps = new List();
timeEntries.Sort((te1,te2) => te1.VerticalOffset.CompareTo(te2.VerticalOffset));
@@ -297,23 +294,47 @@ private static List GenerateGapTimeEntryBlocks(List lastTimeEntry.Bottom)
{
- var block = new GapTimeEntryBlock((offset, height) => AddNewTimeEntry(offset, height, selectedScaleMode, selectedDate))
+ var gapStart = lastTimeEntry.Ended + 1;
+ var block = new GapTimeEntryBlock((offset, height) => Toggl.CreateEmptyTimeEntry(gapStart, entry.Started))
{
Height = entry.VerticalOffset - lastTimeEntry.Bottom,
VerticalOffset = lastTimeEntry.Bottom,
HorizontalOffset = 0
};
- if (block.Height > 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, Toggl.TogglTimeEntryView? running,
+ double curTimeOffset, DateTime selectedDate)
+ {
+ if (running != null || selectedDate.Date != DateTime.Today) return null;
+
+ var lastTimeEntry = timeEntries.Aggregate(default(TimeEntryBlock),
+ (max, next) => max == null || next.Ended > max.Ended ? next : max);
+ if (lastTimeEntry != null && curTimeOffset >= lastTimeEntry.Bottom + TimelineConstants.MinGapTimeEntryHeight)
+ return new GapTimeEntryBlock(
+ (offset, height) =>
+ {
+ var id = Toggl.Start("", "", 0, 0, "", "");
+ Toggl.SetTimeEntryStartTimeStamp(id, (long)lastTimeEntry.Ended+1);
+ return id;
+ })
+ {
+ Height = curTimeOffset - lastTimeEntry.Bottom,
+ VerticalOffset = lastTimeEntry.Bottom,
+ HorizontalOffset = 0
+ };
+ return null;
+ }
+
public static string AddNewTimeEntry(double offset, double height, int scaleMode, DateTime date)
{
var started = TimelineUtils.ConvertOffsetToUnixTime(offset, date,
@@ -355,6 +376,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..aac1ae6ea1 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"/>
-