public TimelineViewModel() { this.WhenAnyValue(x => x.RecordActivity).ObserveOn(RxApp.TaskpoolScheduler) .Subscribe(value => Toggl.SetTimelineRecordingEnabled(value)); OpenTogglHelpUri = ReactiveCommand.Create(() => Toggl.OpenInBrowser("https://support.toggl.com/en/articles/3836325-toggl-desktop-for-windows")); Toggl.TimelineSelectedDate.Subscribe(date => SelectedDate = date); this.WhenAnyValue(x => x.SelectedDate) .Where(date => date != Toggl.TimelineSelectedDate.Value) .ObserveOn(RxApp.TaskpoolScheduler) .Subscribe(date => Toggl.SetViewTimelineDay(Toggl.UnixFromDateTime(date))); this.WhenAnyValue(x => x.SelectedDate) .ObserveOn(RxApp.TaskpoolScheduler) .Subscribe(LoadMoreIfNeeded); this.WhenAnyValue(x => x.SelectedDate) .ObserveOn(RxApp.TaskpoolScheduler) .Subscribe(_ => HideEditViewIfNeeded()); Toggl.TimelineSelectedDate .Select(dateTime => dateTime.Date == DateTime.Today.Date) .ToPropertyEx(this, x => x.IsTodaySelected); SelectPreviousDay = ReactiveCommand.Create(Toggl.ViewTimelinePreviousDay); SelectNextDay = ReactiveCommand.Create(Toggl.ViewTimelineNextDay); IncreaseScale = ReactiveCommand.Create(() => SelectedScaleMode = ChangeScaleMode(-1)); DecreaseScale = ReactiveCommand.Create(() => SelectedScaleMode = ChangeScaleMode(1)); var scaleModeObservable = this.WhenAnyValue(x => x.SelectedScaleMode); scaleModeObservable.Subscribe(_ => HourHeightView = TimelineConstants.ScaleModes[SelectedScaleMode] * GetHoursInLine(SelectedScaleMode)); scaleModeObservable.Select(GetHoursListFromScale).ToPropertyEx(this, x => x.HourViews); scaleModeObservable.Select(mode => ConvertTimeIntervalToHeight(DateTime.Today, DateTime.Now, mode)) .Subscribe(h => CurrentTimeOffset = h); Toggl.TimelineChunks.CombineLatest(scaleModeObservable, (items, mode) => ConvertChunksToActivityBlocks(items, mode, SelectedDate)) .ToPropertyEx(this, x => x.ActivityBlocks); Toggl.TimelineTimeEntries.CombineLatest(scaleModeObservable, (items, mode) => ConvertTimeEntriesToBlocks(items, mode, SelectedDate)) .ToPropertyEx(this, x => x.TimeEntryBlocks); Toggl.TimelineTimeEntries.CombineLatest(scaleModeObservable, GenerateGapTimeEntryBlocks) .ToPropertyEx(this, x => x.GapTimeEntryBlocks); this.WhenAnyValue(x => x.TimeEntryBlocks) .Where(blocks => blocks != null && blocks.Any()) .Select(blocks => blocks.Min(te => te.VerticalOffset)) .ToPropertyEx(this, x => x.FirstTimeEntryOffset); Toggl.OnTimeEntryList += HandleTimeEntryListChanged; Toggl.OnTimeEntryEditor += (open, te, field) => SelectedForEditTEId = open ? te.GUID : SelectedForEditTEId; this.WhenAnyValue(x => x.SelectedForEditTEId, x => x.TimeEntryBlocks) .ObserveOn(RxApp.TaskpoolScheduler).Subscribe(_ => TimeEntryBlocks?.ForEach(te => te.IsEditViewOpened = SelectedForEditTEId == te.TimeEntryId)); Observable.Timer(TimeSpan.Zero, TimeSpan.FromMinutes(1)) .Select(_ => ConvertTimeIntervalToHeight(DateTime.Today, DateTime.Now, SelectedScaleMode)) .Subscribe(h => CurrentTimeOffset = h); }
public TimelineViewModel() { this.WhenAnyValue(x => x.RecordActivity).ObserveOn(RxApp.TaskpoolScheduler) .Subscribe(value => Toggl.SetTimelineRecordingEnabled(value)); OpenTogglHelpUri = ReactiveCommand.Create(() => Toggl.OpenInBrowser("https://support.toggl.com/en/articles/3836325-toggl-desktop-for-windows")); this.WhenAnyValue(x => x.SelectedDate).Subscribe(HandleSelectedDateChanged); SelectPreviousDay = ReactiveCommand.Create(Toggl.ViewTimelinePreviousDay); SelectNextDay = ReactiveCommand.Create(Toggl.ViewTimelineNextDay); IncreaseScale = ReactiveCommand.Create(() => SelectedScaleMode = ChangeScaleMode(-1)); DecreaseScale = ReactiveCommand.Create(() => SelectedScaleMode = ChangeScaleMode(1)); var scaleModeObservable = this.WhenAnyValue(x => x.SelectedScaleMode); scaleModeObservable.Subscribe(_ => HourHeightView = ScaleModes[SelectedScaleMode] * GetHoursInLine(SelectedScaleMode)); scaleModeObservable.Where(_ => _timelineChunks != null) .Subscribe(_ => ConvertChunksToActivityBlocks(_timelineChunks)); scaleModeObservable.Where(_ => _timeEntries != null) .Subscribe(_ => ConvertTimeEntriesToBlocks(_timeEntries)); scaleModeObservable.Select(GetHoursListFromScale).ToPropertyEx(this, x => x.HourViews); scaleModeObservable.Select(mode => ConvertTimeIntervalToHeight(DateTime.Today, DateTime.Now, mode)) .Subscribe(h => CurrentTimeOffset = h); Toggl.OnTimeline += HandleDisplayTimeline; Toggl.OnTimeEntryList += HandleTimeEntryListChanged; Toggl.OnTimeEntryEditor += (open, te, field) => SelectedForEditTEId = open ? te.GUID : SelectedForEditTEId; this.WhenAnyValue(x => x.SelectedForEditTEId, x => x.TimeEntryBlocks) .ObserveOn(RxApp.TaskpoolScheduler).Subscribe(_ => TimeEntryBlocks?.ForEach(te => te.IsEditViewOpened = SelectedForEditTEId == te.TimeEntryId)); HourViews = GetHoursListFromScale(SelectedScaleMode); Observable.Timer(TimeSpan.Zero, TimeSpan.FromMinutes(1)) .Select(_ => ConvertTimeIntervalToHeight(DateTime.Today, DateTime.Now, SelectedScaleMode)) .Subscribe(h => CurrentTimeOffset = h); this.WhenAnyValue(x => x.SelectedDate) .Select(dateTime => dateTime.Date == DateTime.Today.Date) .ToPropertyEx(this, x => x.IsTodaySelected); }
public TimelineViewModel() { this.WhenAnyValue(x => x.RecordActivity).ObserveOn(RxApp.TaskpoolScheduler) .Subscribe(value => Toggl.SetTimelineRecordingEnabled(value)); OpenTogglHelpUri = ReactiveCommand.Create(() => Toggl.OpenInBrowser("https://support.toggl.com/en/articles/3836325-toggl-desktop-for-windows")); Toggl.TimelineSelectedDate.Subscribe(date => SelectedDate = date); this.WhenAnyValue(x => x.SelectedDate) .Where(date => date != Toggl.TimelineSelectedDate.Value) .ObserveOn(RxApp.TaskpoolScheduler) .Subscribe(date => Toggl.SetViewTimelineDay(Toggl.UnixFromDateTime(date))); this.WhenAnyValue(x => x.SelectedDate) .ObserveOn(RxApp.TaskpoolScheduler) .Subscribe(LoadMoreIfNeeded); this.WhenAnyValue(x => x.SelectedDate) .ObserveOn(RxApp.TaskpoolScheduler) .Subscribe(_ => HideEditViewIfNeeded()); Toggl.TimelineSelectedDate .Select(dateTime => dateTime.Date == DateTime.Today.Date) .ToPropertyEx(this, x => x.IsTodaySelected); SelectPreviousDay = ReactiveCommand.Create(Toggl.ViewTimelinePreviousDay); SelectNextDay = ReactiveCommand.Create(Toggl.ViewTimelineNextDay); IncreaseScale = ReactiveCommand.Create(() => SelectedScaleMode = ChangeScaleMode(-1)); DecreaseScale = ReactiveCommand.Create(() => SelectedScaleMode = ChangeScaleMode(1)); var activeBlockObservable = this.WhenAnyValue(x => x.ActiveTimeEntryBlock); var isNotRunningObservable = activeBlockObservable.Select(next => next != null && next.DurationInSeconds >= 0); ContinueEntry = ReactiveCommand.Create(() => Toggl.Continue(ActiveTimeEntryBlock.TimeEntryId), isNotRunningObservable); CreateFromEnd = ReactiveCommand.Create(() => TimelineUtils.CreateAndEditTimeEntry(ActiveTimeEntryBlock.Ended, ActiveTimeEntryBlock.Ended + TimelineConstants.DefaultTimeEntryLengthInSeconds), isNotRunningObservable); StartFromEnd = ReactiveCommand.Create(() => TimelineUtils.CreateAndEditRunningTimeEntryFrom(ActiveTimeEntryBlock.Ended), isNotRunningObservable); Delete = ReactiveCommand.Create(() => ActiveTimeEntryBlock.DeleteTimeEntry(), activeBlockObservable.Select(next => next != null)); var isOverlapping = activeBlockObservable.Select(next => next != null && next.IsOverlapping); ChangeFirstTimeEntryStopCommand = ReactiveCommand.Create(() => ChangeFirstEntryStop(ActiveTimeEntryBlock, SortedTimeEntryBlocks), isOverlapping); ChangeLastTimeEntryStartCommand = ReactiveCommand.Create(() => ChangeLastEntryStart(ActiveTimeEntryBlock, SortedTimeEntryBlocks), isOverlapping); var scaleModeObservable = this.WhenAnyValue(x => x.SelectedScaleMode); scaleModeObservable.Subscribe(_ => HourHeightView = TimelineConstants.ScaleModes[SelectedScaleMode] * GetHoursInLine(SelectedScaleMode)); scaleModeObservable.Select(GetHoursListFromScale).ToPropertyEx(this, x => x.HourViews); scaleModeObservable.Select(mode => ConvertTimeIntervalToHeight(DateTime.Today, DateTime.Now, mode)) .Subscribe(h => CurrentTimeOffset = h); Toggl.TimelineChunks.CombineLatest(scaleModeObservable, (items, mode) => ConvertChunksToActivityBlocks(items, mode, SelectedDate)) .ToPropertyEx(this, x => x.ActivityBlocks); var blocksObservable = Toggl.TimelineTimeEntries .CombineLatest(Toggl.RunningTimeEntry, scaleModeObservable, (list, running, mode) => ConvertTimeEntriesToBlocks(list, running, mode, SelectedDate)); var blocksWithRunningObservable = blocksObservable.CombineLatest(Toggl.RunningTimeEntry, (list, te) => (TimeEntries: list, Running: te)) .Where(_ => (TimeEntryBlocks == null || !TimeEntryBlocks.Any(item => item.Value.IsDragged)) && (RunningTimeEntryBlock == null || !RunningTimeEntryBlock.IsDragged)); blocksWithRunningObservable.Select(tuple => tuple.Running.HasValue ? tuple.TimeEntries.GetValueOrDefault(tuple.Running.Value.GUID) : null) .ToPropertyEx(this, x => x.RunningTimeEntryBlock); blocksWithRunningObservable.Select(tuple => tuple.TimeEntries.Where(b => b.Key != tuple.Running?.GUID) .ToDictionary(pair => pair.Key, pair => pair.Value)) .ToPropertyEx(this, x => x.TimeEntryBlocks); var sortedTimeEntriesObservable = blocksObservable.Select(blocks => { var timeEntries = blocks.Values.ToList(); timeEntries.Sort((te1, te2) => te1.VerticalOffset.CompareTo(te2.VerticalOffset)); return(timeEntries); }); sortedTimeEntriesObservable.ToPropertyEx(this, x => x.SortedTimeEntryBlocks); sortedTimeEntriesObservable.Select(GenerateGapTimeEntryBlocks) .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()) .Select(blocks => blocks.Min(te => te.Value.VerticalOffset)) .ToPropertyEx(this, x => x.FirstTimeEntryOffset); Toggl.OnTimeEntryList += HandleTimeEntryListChanged; Toggl.OnTimeEntryEditor += (open, te, field) => SelectedForEditTEId = open ? te.GUID : SelectedForEditTEId; this.WhenAnyValue(x => x.SelectedForEditTEId, x => x.TimeEntryBlocks) .ObserveOn(RxApp.TaskpoolScheduler).Subscribe(_ => TimeEntryBlocks?.ForEach(te => te.Value.IsEditViewOpened = SelectedForEditTEId == te.Key)); this.WhenAnyValue(x => x.SelectedForEditTEId, x => x.RunningTimeEntryBlock) .Where(pair => pair.Item2 != null) .Subscribe(pair => pair.Item2.IsEditViewOpened = pair.Item1 == pair.Item2.TimeEntryId); var curOffsetObservable = Observable.Timer(TimeSpan.Zero, TimeSpan.FromSeconds(1)) .Select(_ => ConvertTimeIntervalToHeight(DateTime.Today, DateTime.Now, SelectedScaleMode)); curOffsetObservable.Subscribe(h => CurrentTimeOffset = h); curOffsetObservable.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); }