コード例 #1
0
        public void Display(Toggl.TimeEntry item)
        {
            GUID = item.GUID;

            labelDescription.Text = item.Description == "" ? "(no description)" : item.Description;

            var projectColorBrush = getProjectColorBrush(ref item);

            projectColor.Fill = projectColorBrush;
            labelProject.Foreground = projectColorBrush;
            labelProject.Text = (item.ClientLabel.Length > 0) ? "• " + item.ProjectLabel : item.ProjectLabel;
            setOptionalTextBlockText(labelClient, item.ClientLabel);
            setOptionalTextBlockText(labelTask, item.TaskLabel);
            labelDuration.Text = item.Duration;
            showOnlyIf(billabeIcon, item.Billable);
            showOnlyIf(tagsIcon, !string.IsNullOrEmpty(item.Tags));

            showOnlyIf(dayHeader, item.IsHeader);

            if (item.IsHeader)
            {
                labelFormattedDate.Text = item.DateHeader;
                labelDateDuration.Text = item.DateDuration;
            }

            updateToolTips(item);
        }
コード例 #2
0
        public void Display(Toggl.TogglTimeEntryView item)
        {
            this.guid = item.GUID;

            this.labelDescription.Text = item.Description == "" ? "(no description)" : item.Description;

            var projectColorBrush = getProjectColorBrush(ref item);

            this.projectColor.Fill = projectColorBrush;
            this.labelProject.Foreground = projectColorBrush;
            this.labelProject.Text = item.ClientLabel == "" ? item.ProjectLabel : "• " + item.ProjectLabel;
            setOptionalTextBlockText(this.labelClient, item.ClientLabel);
            setOptionalTextBlockText(this.labelTask, item.TaskLabel == "" ? "" : item.TaskLabel + " -");
            this.labelDuration.Text = item.Duration;
            showOnlyIf(this.billabeIcon, item.Billable);
            showOnlyIf(this.tagsIcon, !string.IsNullOrEmpty(item.Tags));

            this.projectRow.Height = item.ProjectLabel == "" ? new GridLength(0) : GridLength.Auto;

            showOnlyIf(this.dayHeader, item.IsHeader);

            if (item.IsHeader)
            {
                this.labelFormattedDate.Text = item.DateHeader;
                this.labelDateDuration.Text = item.DateDuration;
            }

            this.updateToolTips(item);
        }
コード例 #3
0
 public ProjectEntry(Toggl.AutocompleteItem item, Action selectWithClick, string overideText = null)
     : base(selectWithClick)
 {
     this.ProjectColor = getProjectColor(ref item);
     this.ProjectName = overideText ?? item.ProjectLabel;
     this.TaskName = string.IsNullOrEmpty(item.TaskLabel) ? "" : "- " + item.TaskLabel;
     this.InitializeComponent();
 }
コード例 #4
0
        private void updateUI(Toggl.TogglSettingsView settings)
        {
            #region general

            this.idleDetectionCheckBox.IsChecked = settings.UseIdleDetection;
            this.idleDetectionDurationTextBox.Text = settings.IdleMinutes.ToString();

            this.recordTimelineCheckBox.IsChecked = settings.RecordTimeline;
            this.onTopCheckBox.IsChecked = settings.OnTop;

            #endregion

            #region proxy

            this.useNoProxyRadioButton.IsChecked = true;
            this.useSystemProxySettingsCheckBox.IsChecked = settings.AutodetectProxy;
            this.useProxyCheckBox.IsChecked = settings.UseProxy;
            this.proxyHostTextBox.Text = settings.ProxyHost;
            this.proxyPortTextBox.Text = settings.ProxyPort.ToString();
            this.proxyUsernameTextBox.Text = settings.ProxyUsername;
            this.proxyPasswordBox.Password = settings.ProxyPassword;

            #endregion

            #region reminder

            this.remindToTrackCheckBox.IsChecked = settings.Reminder;
            this.remindToTrackIntervalTextBox.Text = settings.ReminderMinutes.ToString();
            this.reminderStartTimeTextBox.Text = settings.RemindStarts;
            this.reminderEndTimeTextBox.Text = settings.RemindEnds;

            this.remindOnMondayTextBox.IsChecked = settings.RemindMon;
            this.remindOnTuesdayTextBox.IsChecked = settings.RemindTue;
            this.remindOnWednesdayTextBox.IsChecked = settings.RemindWed;
            this.remindOnThursdayTextBox.IsChecked = settings.RemindThu;
            this.remindOnFridayTextBox.IsChecked = settings.RemindFri;
            this.remindOnSaturdayTextBox.IsChecked = settings.RemindSat;
            this.remindOnSundayTextBox.IsChecked = settings.RemindSun;

            #endregion

            #region global shortcuts

            trySetHotKey(
                Toggl.GetKeyShow,
                Toggl.GetKeyModifierShow,
                this.showHideShortcutRecorder
                );
            trySetHotKey(
                Toggl.GetKeyStart,
                Toggl.GetKeyModifierStart,
                this.continueStopShortcutRecorder
                );

            #endregion
        }
コード例 #5
0
 public ProjectEntry Initialised(Toggl.TogglAutocompleteView item, Action selectWithClick, string overideText = null)
 {
     var colorBrush = new SolidColorBrush(getProjectColor(ref item));
     colorBrush.Freeze();
     this.projectColor.Background = colorBrush;
     this.project.Text = overideText ?? item.ProjectLabel;
     this.task.Text = string.IsNullOrEmpty(item.TaskLabel) ? "" : "- " + item.TaskLabel;
     this.setClickAction(selectWithClick);
     return this;
 }
コード例 #6
0
ファイル: TimerEntry.xaml.cs プロジェクト: Nukil/toggldesktop
        private void setText(Toggl.TogglAutocompleteView item)
        {
            if (string.IsNullOrEmpty(item.ProjectLabel))
            {
                this.project.Visibility = Visibility.Collapsed;
            }
            else
            {
                this.project.Text = "• " + item.ProjectLabel;
                this.project.Foreground = Utils.ProjectColorBrushFromString(item.ProjectColor);
                this.project.Visibility = Visibility.Visible;
            }

            setOptionalTextBlockText(this.description, item.Description);
            setOptionalTextBlockText(this.task, string.IsNullOrEmpty(item.TaskLabel) ? "" : "- " + item.TaskLabel);
            setOptionalTextBlockText(this.client, string.IsNullOrEmpty(item.ClientLabel) ? "" : "- " + item.ClientLabel);
        }
コード例 #7
0
        private void setText(Toggl.AutocompleteItem item)
        {
            if (string.IsNullOrEmpty(item.ProjectLabel))
            {
                this.project.Visibility = Visibility.Collapsed;
            }
            else
            {
                this.project.Text = "• " + item.ProjectLabel;
                this.project.Foreground = getProjectColorBrush(ref item);
                this.project.Visibility = Visibility.Visible;
            }

            setOptionalTextBlockText(this.description, item.Description);
            setOptionalTextBlockText(this.task, item.TaskLabel);
            setOptionalTextBlockText(this.client, item.ClientLabel);
        }
コード例 #8
0
        private void onSettings(bool open, Toggl.TogglSettingsView settings)
        {
            if (this.TryBeginInvoke(this.onSettings, open, settings))
                return;

            if (this.isSaving)
                return;

            using (Performance.Measure("filling settings from OnSettings"))
            {
                this.updateUI(settings);
            }

            if (open)
            {
                this.Show();
                this.Topmost = true;
            }
        }
コード例 #9
0
 public PerformanceToken(string activity)
 {
     Toggl.Debug(string.Format("Starting activity '{0}'", activity));
     this.activity = activity;
     this.timer    = Stopwatch.StartNew();
 }
コード例 #10
0
 public TimerEntryListViewViewModel()
 {
     this.WhenValueChanged(x => SelectedTab)
     .Subscribe(value => Toggl.SetActiveTab(value));
     Toggl.OnDisplayTimelineUI += isEnabled => IsTimelineViewEnabled = isEnabled;
 }
コード例 #11
0
        private void updateToolTips(Toggl.TogglTimeEntryView item)
        {
            setToolTipIfNotEmpty(this.labelDescription, this.descriptionToolTip, item.Description);
            setToolTipIfNotEmpty(this.labelTask, this.taskProjectClientToolTip, item.ProjectAndTaskLabel);
            setToolTipIfNotEmpty(this.labelProject, this.taskProjectClientToolTip, item.ProjectAndTaskLabel);
            setToolTipIfNotEmpty(this.labelClient, this.taskProjectClientToolTip, item.ProjectAndTaskLabel);

            if (item.DurOnly)
            {
                this.labelDuration.ToolTip = null;
            }
            else
            {
                this.labelDuration.ToolTip = this.durationToolTip;
                this.durationToolTip.Content = item.StartTimeString + " - " + item.EndTimeString;
            }

            if (this.tagsIcon.Visibility == Visibility.Visible)
            {
                this.tagsToolTip.Content = item.Tags.Replace(Toggl.TagSeparator, ", ");
            }
        }
コード例 #12
0
ファイル: TimerEntry.xaml.cs プロジェクト: Nukil/toggldesktop
 public TimerEntry Initialised(Toggl.TogglAutocompleteView item, Action selectWithClick)
 {
     this.setText(item);
     this.setClickAction(selectWithClick);
     return this;
 }
コード例 #13
0
 private void AddNewTimeEntry()
 {
     Toggl.CreateEmptyTimeEntry(Started, Ended);
 }
コード例 #14
0
        public void FormatDurationInSecondsHHMMSSReturnsCorrectResult(long durationInSeconds, string expectedResult)
        {
            var formatted = Toggl.FormatDurationInSecondsHHMMSS(durationInSeconds);

            Assert.Equal(expectedResult, formatted);
        }
コード例 #15
0
 public void ChangeStartTime()
 {
     Toggl.SetTimeEntryStartTimeStampWithOption(TimeEntryId,
                                                (long)TimelineUtils.ConvertOffsetToUnixTime(VerticalOffset, DateCreated, _hourHeight), true);
 }
コード例 #16
0
 public void SendFeedbackShouldNotFail()
 {
     Assert.True(Toggl.SendFeedback("topic", "details", "filename"));
 }
コード例 #17
0
 public void ViewTimeEntryListShouldContainKnownTimeEntry()
 {
     Toggl.ViewTimeEntryList();
     Assert.Contains(_state.TimeEntries, te => te.ID == (ulong)89818605);
 }
コード例 #18
0
 public void OpenInBrowserShouldNotCrash()
 {
     Toggl.OpenInBrowser();
 }
コード例 #19
0
 public void SetIdleSecondsDoesNotCrash()
 {
     Toggl.SetIdleSeconds(123);
 }
コード例 #20
0
 public void SetWakeDoesNotCrash()
 {
     Toggl.SetWake();
 }
コード例 #21
0
        private void setUIToRunningState(Toggl.TimeEntry item)
        {
            this.resetUIState(true);

            this.descriptionLabel.Text = item.Description == "" ? "(no description)" : item.Description;
            this.projectLabel.Text = string.IsNullOrEmpty(item.ClientLabel) ? item.ProjectLabel : "• " + item.ProjectLabel;
            setOptionalTextBlockText(this.clientLabel, item.ClientLabel);
            setOptionalTextBlockText(this.taskLabel, string.IsNullOrEmpty(item.TaskLabel) ? "" : item.TaskLabel + " -");

            this.projectLabel.Foreground = getProjectColorBrush(ref item);

            showOnlyIf(this.billabeIcon, item.Billable);
            showOnlyIf(this.tagsIcon, !string.IsNullOrEmpty(item.Tags));

            if (!string.IsNullOrEmpty(item.ProjectLabel))
                this.projectGridRow.Height = new GridLength(1, GridUnitType.Star);

            this.invalidate();
        }
コード例 #22
0
 public void ChangeEndTime()
 {
     Toggl.SetTimeEntryEndTimeStamp(TimeEntryId,
                                    (long)TimelineUtils.ConvertOffsetToUnixTime(VerticalOffset + Height, DateCreated, _hourHeight));
 }
コード例 #23
0
 private static SolidColorBrush getProjectColorBrush(ref Toggl.TimeEntry item)
 {
     return getProjectColorBrush(item.Color);
 }
コード例 #24
0
 public void UserEmailReturnsCorrectData()
 {
     Assert.Equal("*****@*****.**", Toggl.UserEmail());
 }
コード例 #25
0
 public void SetSleepDoesNotCrash()
 {
     Toggl.SetSleep();
 }
コード例 #26
0
        private void onTimeEntryEditor(bool open, Toggl.TogglTimeEntryView te, string focusedFieldName)
        {
            if (this.TryBeginInvoke(this.onTimeEntryEditor, open, te, focusedFieldName))
                return;

            if (!this.Owner.IsVisible)
                return;

            this.Show();
            this.EditView.FocusField(focusedFieldName);
        }
コード例 #27
0
ファイル: TimerViewModel.cs プロジェクト: eat7/toggldesktop
        private void AddNewTimeEntry()
        {
            var guid = Toggl.Start("", "0", 0, 0, "", "", isMiniTimer);

            Toggl.Edit(guid, false, Toggl.Duration);
        }
コード例 #28
0
ファイル: TaskEntry.xaml.cs プロジェクト: Nukil/toggldesktop
 public TaskEntry Initialised(Toggl.TogglAutocompleteView item, Action selectWithClick)
 {
     this.task.Text = item.TaskLabel;
     this.setClickAction(selectWithClick);
     return this;
 }
コード例 #29
0
        private void onSettings(bool open, Toggl.Settings settings)
        {
            if (!this.Dispatcher.CheckAccess())
            {
                this.Dispatcher.BeginInvoke(new Action(() => this.onSettings(open, settings)));
                return;
            }

            this.updateUI(settings);

            if (open)
            {
                this.Show();
                this.Topmost = true;
            }
        }
コード例 #30
0
        private void onRunningTimerState(Toggl.TogglTimeEntryView te)
        {
            if (this.TryBeginInvoke(this.onRunningTimerState, te))
                return;

            this.updateTracking(te);
        }
コード例 #31
0
 public void ForgotPasswordShouldNotCrash()
 {
     Toggl.PasswordForgot();
 }
コード例 #32
0
        private void onSettings(bool open, Toggl.TogglSettingsView settings)
        {
            if (this.TryBeginInvoke(this.onSettings, open, settings))
                return;

            this.setGlobalShortcutsFromSettings();
            this.idleDetectionTimer.IsEnabled = settings.UseIdleDetection;
            this.remainOnTop = settings.OnTop;
            this.setWindowOnTop();
        }
コード例 #33
0
 private static Color getProjectColor(ref Toggl.TogglAutocompleteView item)
 {
     var projectColourString = string.IsNullOrEmpty(item.ProjectColor) ? "#999999" : item.ProjectColor;
     var projectColor = (Color)(ColorConverter.ConvertFromString(projectColourString) ?? Color.FromRgb(153, 153, 153));
     return projectColor;
 }
コード例 #34
0
        private void updateTracking(Toggl.TogglTimeEntryView? timeEntry)
        {
            var tracking = timeEntry != null;

            this.isTracking = tracking;

            if (tracking)
            {
                var description = timeEntry.Value.Description;

                if (string.IsNullOrEmpty(description))
                {
                    this.Title = "Toggl Desktop";
                    this.runningMenuText.Text = "Timer is tracking";
                }
                else
                {
                    this.Title = description + " - Toggl Desktop";
                    this.runningMenuText.Text = description;
                }

                if(this.isInManualMode)
                    this.setManualMode(false);
            }
            else
            {
                this.runningMenuText.Text = "Timer is not tracking";
                this.Title = "Toggl Desktop";
            }

            this.updateStatusIcons(true);
            this.SetIconState(tracking);
        }
コード例 #35
0
        public void GetReport()
        {
            var toggl = new Toggl(_config.TogglApikey);

            var reportTimeEntries = toggl.GetTimeEntries(_config.ReportDaysBack);

            var groupedReportTimeEntries = reportTimeEntries
                                           .GroupBy(g => Convert.ToDateTime(g.Start).Date)
                                           .OrderBy(o => o.Key);

            foreach (var entries in groupedReportTimeEntries)
            {
                var minDate = Convert.ToDateTime(entries.Min(m => m.Start)).Date;
                var maxDate = Convert.ToDateTime(entries.Max(m => m.Stop)).Date;

                var totalTime = entries
                                .Select(entry => Convert.ToDateTime(entry.Stop)
                                        .Subtract(Convert.ToDateTime(entry.Start)))
                                .Aggregate(new TimeSpan(), (current, time) => current.Add(time));

                if (minDate == maxDate)
                {
                    Console.WriteLine($"{Environment.NewLine}" +
                                      $"{minDate:dd.MM.yyyy} - {Math.Round(totalTime.TotalHours, 1)} h" +
                                      $"{Environment.NewLine}");

                    ConsoleTableBuilder
                    .From(entries
                          .OrderBy(o => Convert.ToDateTime(o.Start))
                          .Select(s => new List <object>
                    {
                        Convert.ToDateTime(s.Start).ToString("HH:mm"),
                        Convert.ToDateTime(s.Stop).ToString("HH:mm"),
                        Math.Round(Convert.ToDateTime(s.Stop).Subtract(Convert.ToDateTime(s.Start)).TotalHours, 1),
                        s.ClientName,
                        s.ProjectName,
                        s.Description
                    }).ToList())
                    .WithColumn("Start", "End", "Elapsed (in h)", "Client", "Project", "Note")
                    .WithFormat(ConsoleTableBuilderFormat.MarkDown)
                    .WithOptions(new ConsoleTableBuilderOption
                    {
                        Delimiter     = "|",
                        DividerString = "-",
                        TrimColumn    = true
                    })
                    .ExportAndWriteLine();
                }
                else
                {
                    Console.WriteLine($"{Environment.NewLine}" +
                                      $"{minDate:dd.MM.yyyy} - {maxDate:dd.MM.yyyy} - {Math.Round(totalTime.TotalHours, 1)} h" +
                                      $"{Environment.NewLine}");

                    ConsoleTableBuilder
                    .From(entries
                          .OrderBy(o => Convert.ToDateTime(o.Start))
                          .Select(s => new List <object>
                    {
                        Convert.ToDateTime(s.Start).ToString("dd.MM.yyyy"),
                        Convert.ToDateTime(s.Start).ToString("HH:mm"),
                        Convert.ToDateTime(s.Stop).ToString("dd.MM.yyyy"),
                        Convert.ToDateTime(s.Stop).ToString("HH:mm"),
                        Math.Round(Convert.ToDateTime(s.Stop).Subtract(Convert.ToDateTime(s.Start)).TotalHours, 1),
                        s.ClientName,
                        s.ProjectName,
                        s.Description
                    }).ToList())
                    .WithColumn("Start Date", "Time", "Stop Date", "Time", "Elapsed (in h)", "Client", "Project", "Note")
                    .WithFormat(ConsoleTableBuilderFormat.MarkDown)
                    .WithOptions(new ConsoleTableBuilderOption
                    {
                        Delimiter     = "|",
                        DividerString = "-",
                        TrimColumn    = true
                    })
                    .ExportAndWriteLine();
                }
            }
        }
コード例 #36
0
 public void Dispose()
 {
     _runningTimerState.Dispose();
     Toggl.Clear();
 }
コード例 #37
0
        private void onRunningTimerState(Toggl.TimeEntry te)
        {
            if (this.invoke(() => this.onRunningTimerState(te)))
                return;

            this.runningTimeEntry = te;
            this.setUIToRunningState(te);
            this.secondsTimer.IsEnabled = true;
        }
コード例 #38
0
ファイル: LoginViewModel.cs プロジェクト: wadkar/toggldesktop
 public async Task GoogleLoginAsync()
 {
     await GoogleAuth(accessToken => Toggl.GoogleLogin(accessToken), "Login");
 }
コード例 #39
0
 public ProjectInfo(Toggl.AutocompleteItem item)
 {
     this.projectId = item.ProjectID;
     this.taskId = item.TaskID;
 }
コード例 #40
0
 private void AddNewTimeEntry()
 {
     TimeEntryId = Toggl.CreateEmptyTimeEntry(Started, Ended);
     OpenEditView.Execute().Subscribe();
 }
コード例 #41
0
 private static SolidColorBrush getProjectColorBrush(ref Toggl.AutocompleteItem item)
 {
     return getProjectColorBrush(item.ProjectColor);
 }
コード例 #42
0
 public void ChangeEndTime()
 {
     Toggl.SetTimeEntryEndTimeStamp(TimeEntryId,
                                    (long)ConvertOffsetToTime(VerticalOffset + Height, Toggl.DateTimeFromUnix(Ended).Date));
 }
コード例 #43
0
        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);
        }
コード例 #44
0
 public void SyncDoesNotCrash()
 {
     Toggl.Sync();
 }
コード例 #45
0
ファイル: LoginViewModel.cs プロジェクト: wadkar/toggldesktop
 public async Task GoogleSignupAsync()
 {
     await GoogleAuth(accessToken => Toggl.GoogleSignup(accessToken, SelectedCountry?.ID ?? default), "Signup");
 }
コード例 #46
0
        private static Dictionary <string, TimeEntryBlock> ConvertTimeEntriesToBlocks(List <Toggl.TogglTimeEntryView> timeEntries,
                                                                                      Toggl.TogglTimeEntryView?runningEntry,
                                                                                      int selectedScaleMode,
                                                                                      DateTime selectedDate)
        {
            var timeStampsList = new List <(TimeStampType Type, TimeEntryBlock Block)>();
            var blocks         = new Dictionary <string, TimeEntryBlock>();
            //The idea is to place all the starts and ends in sorted order and then assign an offset to each time entry block from the list:
            // - if it's a start time stamp, then pick up the minimum available offset, if none is available assign a new one.
            // - if it's an end time stamp, then release the offset which it occupied.
            IEnumerable <Toggl.TogglTimeEntryView> allEntries = timeEntries;

            if (runningEntry != null && runningEntry.Value.StartTime().Date <= selectedDate.Date && DateTime.Now.Date >= selectedDate.Date)
            {
                allEntries = allEntries.Union(new List <Toggl.TogglTimeEntryView>()
                {
                    runningEntry.Value
                });
            }
            foreach (var entry in allEntries)
            {
                if (blocks.ContainsKey(entry.GUID))
                {
                    continue;
                }

                var startTime = entry.StartTime();
                var ended     = entry.GUID == runningEntry?.GUID
                    ? (ulong)Toggl.UnixFromDateTime(DateTime.Now)
                    : entry.Ended;
                var height = ConvertTimeIntervalToHeight(startTime, Toggl.DateTimeFromUnix(ended), selectedScaleMode);
                var block  = new TimeEntryBlock(entry, TimelineConstants.ScaleModes[selectedScaleMode], selectedDate)
                {
                    Height         = height,
                    VerticalOffset = ConvertTimeIntervalToHeight(selectedDate, startTime, selectedScaleMode),
                    IsOverlapping  = false
                };
                if (entry.Started < ended)
                {
                    timeStampsList.Add((TimeStampType.Start, block));
                    timeStampsList.Add((TimeStampType.End, block));
                }
                else
                {
                    timeStampsList.Add((TimeStampType.Empty, block));
                }
                blocks.Add(entry.GUID, block);
            }
            //There can be a situation that next time entry starts exactly at the same moment, the previous one ended.
            //This situation must not be considered as overlap. So the comparison logic if time stamps are the same:
            // - always place the end time stamps first
            // - prefer empty time stamps to start time stamps
            // (otherwise if we discover a start then an empty, this will be considered as overlap, which we want to avoid)
            timeStampsList.Sort((te1, te2) =>
            {
                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 (res.IsNearEqual(0, TimelineConstants.AcceptableBlocksOverlap))
                {
                    var getPriority = new Func <TimeStampType, int>(t =>
                                                                    t == TimeStampType.End ? 0 : t == TimeStampType.Empty ? 1 : 2);
                    return(getPriority(te1.Type) - getPriority(te2.Type));
                }
                return(res < 0 ? -1 : 1);
            });
            var            offsets          = new HashSet <double>();
            var            curOffset        = 0d;
            var            usedNumOfOffsets = 0;
            TimeEntryBlock prevLayerBlock   = null;

            foreach (var item in timeStampsList)
            {
                if (item.Type == TimeStampType.Start || item.Type == TimeStampType.Empty)
                {
                    if (!offsets.Any())
                    {
                        offsets.Add(curOffset);
                        curOffset += TimelineConstants.TimeEntryBlockWidth + TimelineConstants.GapBetweenOverlappingTEs;
                    }
                    if (usedNumOfOffsets > 0)
                    {
                        item.Block.IsOverlapping = true;
                        if (prevLayerBlock != null)
                        {
                            prevLayerBlock.IsOverlapping = true;
                        }
                    }
                    item.Block.HorizontalOffset = offsets.Min();
                    offsets.Remove(offsets.Min());
                    usedNumOfOffsets++;
                    prevLayerBlock = item.Block;
                }
                if (item.Type == TimeStampType.End || item.Type == TimeStampType.Empty)
                {
                    offsets.Add(item.Block.HorizontalOffset);
                    usedNumOfOffsets--;
                    prevLayerBlock = null;
                }
            }

            return(blocks);
        }
コード例 #47
0
        private static List <TimeEntryBlock> ConvertTimeEntriesToBlocks(List <Toggl.TogglTimeEntryView> timeEntries, int selectedScaleMode, DateTime selectedDate)
        {
            var timeStampsList = new List <(TimeStampType Type, TimeEntryBlock Block)>();
            var blocks         = new List <TimeEntryBlock>();

            //The idea is to place all the starts and ends in sorted order and then assign an offset to each time entry block from the list:
            // - if it's a start time stamp, then pick up the minimum available offset, if none is available assign a new one.
            // - if it's an end time stamp, then release the offset which it occupied.
            foreach (var entry in timeEntries)
            {
                var startTime = Toggl.DateTimeFromUnix(entry.Started);
                var height    = ConvertTimeIntervalToHeight(startTime, Toggl.DateTimeFromUnix(entry.Ended), selectedScaleMode);
                var block     = new TimeEntryBlock(entry.GUID, TimelineConstants.ScaleModes[selectedScaleMode])
                {
                    Started         = entry.Started,
                    Ended           = entry.Ended,
                    Height          = Math.Max(height, TimelineConstants.MinTimeEntryBlockHeight),
                    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,
                    IsResizable     = height >= TimelineConstants.MinResizableTimeEntryBlockHeight
                };
                if (entry.Started != entry.Ended)
                {
                    timeStampsList.Add((TimeStampType.Start, block));
                    timeStampsList.Add((TimeStampType.End, block));
                }
                else
                {
                    timeStampsList.Add((TimeStampType.Empty, block));
                }
                blocks.Add(block);
            }
            //There can be a situation that next time entry starts exactly at the same moment, the previous one ended.
            //This situation must not be considered as overlap. So the comparison logic if time stamps are the same:
            // - always place the end time stamps first
            // - prefer empty time stamps to start time stamps
            // (otherwise if we discover a start then an empty, this will be considered as overlap, which we want to avoid)
            timeStampsList.Sort((te1, te2) =>
            {
                var time1 = te1.Type == TimeStampType.End ? te1.Block.Ended : te1.Block.Started;
                var time2 = te2.Type == TimeStampType.End ? te2.Block.Ended : te2.Block.Started;
                var res   = time1.CompareTo(time2);
                if (res == 0)
                {
                    var getPriority = new Func <TimeStampType, int>(t =>
                                                                    t == TimeStampType.End ? 0 : t == TimeStampType.Empty ? 1 : 2);
                    return(getPriority(te1.Type) - getPriority(te2.Type));
                }
                return(res);
            });
            var            offsets          = new HashSet <double>();
            var            curOffset        = 0d;
            var            usedNumOfOffsets = 0;
            TimeEntryBlock prevLayerBlock   = null;

            foreach (var item in timeStampsList)
            {
                if (item.Type == TimeStampType.Start || item.Type == TimeStampType.Empty)
                {
                    if (!offsets.Any())
                    {
                        offsets.Add(curOffset);
                        curOffset += TimelineConstants.TimeEntryBlockWidth + TimelineConstants.GapBetweenOverlappingTEs;
                    }
                    if (usedNumOfOffsets > 0 || item.Block.Height < TimelineConstants.MinShowTEDescriptionHeight)
                    {
                        item.Block.ShowDescription = false;
                        if (prevLayerBlock != null)
                        {
                            prevLayerBlock.ShowDescription = false;
                        }
                    }
                    item.Block.HorizontalOffset = offsets.Min();
                    offsets.Remove(offsets.Min());
                    usedNumOfOffsets++;
                    prevLayerBlock = item.Block;
                }
                if (item.Type == TimeStampType.End || item.Type == TimeStampType.Empty)
                {
                    offsets.Add(item.Block.HorizontalOffset);
                    usedNumOfOffsets--;
                    prevLayerBlock = null;
                }
            }

            return(blocks);
        }
コード例 #48
0
 public ModelEntry Initialised(Toggl.TogglGenericView item, Action selectWithClick, string overrideText = null)
 {
     this.text.Text = overrideText ?? item.Name;
     this.setClickAction(selectWithClick);
     return this;
 }
コード例 #49
0
 public void ChangeStartTime()
 {
     Toggl.SetTimeEntryStartTimeStamp(TimeEntryId,
                                      (long)ConvertOffsetToTime(VerticalOffset, Toggl.DateTimeFromUnix(Started).Date));
 }
コード例 #50
0
        private void onTimeEntryEditor(bool open, Toggl.TogglTimeEntryView timeEntry, string focusedFieldName)
        {
            if (this.TryBeginInvoke(this.onTimeEntryEditor, open, timeEntry, focusedFieldName))
                return;

            using (Performance.Measure("filling edit view from OnTimeEntryEditor"))
            {
                var keepNewProjectModeOpen =
                    !open
                    && this.isInNewProjectMode
                    && this.hasTimeEntry()
                    && this.timeEntry.GUID == timeEntry.GUID
                    && this.timeEntry.PID == timeEntry.PID
                    && this.timeEntry.WID == timeEntry.WID
                    && timeEntry.CanAddProjects;

                if (!keepNewProjectModeOpen && this.hasTimeEntry() && this.isInNewProjectMode)
                {
                    this.confirmNewProject();
                }

                this.timeEntry = timeEntry;

                var isCurrentlyRunning = timeEntry.DurationInSeconds < 0;

                this.endTimeTextBox.IsEnabled = !isCurrentlyRunning;

                this.setText(this.descriptionTextBox, timeEntry.Description, open);
                setTime(this.durationTextBox, timeEntry.Duration, open);
                setTime(this.startTimeTextBox, timeEntry.StartTimeString, open);
                setTime(this.endTimeTextBox, timeEntry.EndTimeString, open);
                this.startDatePicker.SelectedDate = Toggl.DateTimeFromUnix(timeEntry.Started);

                if (isCurrentlyRunning)
                {
                    this.endTimeTextBox.Text = "";
                }

                this.billableCheckBox.ShowOnlyIf(timeEntry.CanSeeBillable);
                this.billableCheckBox.IsChecked = timeEntry.Billable;

                if (timeEntry.UpdatedAt > 0)
                {
                    var updatedAt = Toggl.DateTimeFromUnix(timeEntry.UpdatedAt);
                    this.lastUpdatedText.Text = "Last update " + updatedAt.ToShortDateString() + " at " +
                                                updatedAt.ToLongTimeString();
                    this.lastUpdatedText.Visibility = Visibility.Visible;
                }
                else
                {
                    this.lastUpdatedText.Visibility = Visibility.Collapsed;
                }

                if (open || !this.tagList.IsKeyboardFocusWithin)
                {
                    this.tagList.Clear(open);
                    if (timeEntry.Tags != null)
                        this.tagList.AddTags(timeEntry.Tags.Split(new[] {Toggl.TagSeparator},
                            StringSplitOptions.RemoveEmptyEntries));
                    this.updateTagListEmptyText();
                }

                if (!keepNewProjectModeOpen)
                {
                    if (this.isInNewProjectMode)
                        this.disableNewProjectMode();

                    this.projectColorCircle.Background = new SolidColorBrush(getProjectColor(timeEntry.Color));
                    this.setText(this.projectTextBox, timeEntry.ProjectLabel, open);
                    this.setText(this.clientTextBox, timeEntry.ClientLabel, open);

                    this.selectedWorkspaceId = timeEntry.WID;
                    this.selectedWorkspaceName = timeEntry.WorkspaceName;

                    if (timeEntry.CanAddProjects)
                    {
                        this.newProjectButton.Visibility = Visibility.Visible;
                        this.projectAddButtonColumn.Width = GridLength.Auto;
                        this.projectAddButtonColumn.SharedSizeGroup = "AddButtons";
                    }
                    else
                    {
                        this.newProjectButton.Visibility = Visibility.Hidden;
                        this.projectAddButtonColumn.Width = new GridLength(0);
                        this.projectAddButtonColumn.SharedSizeGroup = null;
                    }
                }
            }
        }
コード例 #51
0
        private void ConvertTimeEntriesToBlocks(List <Toggl.TogglTimeEntryView> timeEntries)
        {
            var timeStampsList = new List <(TimeStampType Type, TimeEntryBlock Block)>();
            var blocks         = new List <TimeEntryBlock>();

            //The idea is to place all the starts and ends in sorted order and then assign an offset to each time entry block from the list:
            // - if it's a start time stamp, then pick up the minimum available offset, if none is available assign a new one.
            // - if it's an end time stamp, then release the offset which it occupied.
            foreach (var entry in timeEntries)
            {
                var startTime = Toggl.DateTimeFromUnix(entry.Started);
                var height    = ConvertTimeIntervalToHeight(startTime, Toggl.DateTimeFromUnix(entry.Ended));
                var block     = new TimeEntryBlock()
                {
                    Height          = height < 2 ? 2 : height,
                    VerticalOffset  = ConvertTimeIntervalToHeight(new DateTime(startTime.Year, startTime.Month, startTime.Day), startTime),
                    Color           = entry.Color,
                    Description     = entry.Description,
                    ProjectName     = entry.ProjectLabel,
                    ClientName      = entry.ClientLabel,
                    ShowDescription = true,
                    Started         = entry.Started,
                    Ended           = entry.Ended
                };
                if (entry.Started != entry.Ended)
                {
                    timeStampsList.Add((TimeStampType.Start, block));
                    timeStampsList.Add((TimeStampType.End, block));
                }
                else
                {
                    timeStampsList.Add((TimeStampType.Empty, block));
                }
                blocks.Add(block);
            }
            //There can be a situation that next time entry starts exactly at the same moment, the previous one ended.
            //This situation must not be considered as overlap. So the comparison logic if time stamps are the same:
            // - always place the end time stamps first
            // - prefer empty time stamps to start time stamps
            // (otherwise if we discover a start then an empty, this will be considered as overlap, which we want to avoid)
            timeStampsList.Sort((te1, te2) =>
            {
                var time1 = te1.Type == TimeStampType.End ? te1.Block.Ended : te1.Block.Started;
                var time2 = te2.Type == TimeStampType.End ? te2.Block.Ended : te2.Block.Started;
                var res   = time1.CompareTo(time2);
                if (res == 0)
                {
                    var getPriority = new Func <TimeStampType, int>(t =>
                                                                    t == TimeStampType.End ? 0 : t == TimeStampType.Empty ? 1 : 2);
                    return(getPriority(te1.Type) - getPriority(te2.Type));
                }
                return(res);
            });
            var offsets          = new HashSet <double>();
            var curOffset        = 0;
            var usedNumOfOffsets = 0;

            foreach (var item in timeStampsList)
            {
                if (item.Type == TimeStampType.Start || item.Type == TimeStampType.Empty)
                {
                    if (!offsets.Any())
                    {
                        offsets.Add(curOffset);
                        curOffset += 25;
                    }
                    if (usedNumOfOffsets > 0 || item.Block.Height < 20)
                    {
                        item.Block.ShowDescription = false;
                    }
                    item.Block.HorizontalOffset = offsets.Min();
                    offsets.Remove(offsets.Min());
                    usedNumOfOffsets++;
                }
                if (item.Type == TimeStampType.End || item.Type == TimeStampType.Empty)
                {
                    offsets.Add(item.Block.HorizontalOffset);
                    if (usedNumOfOffsets > 1 || item.Block.Height < 20)
                    {
                        item.Block.ShowDescription = false;
                    }
                    usedNumOfOffsets--;
                }
            }
            TimeEntryBlocks = null;
            TimeEntryBlocks = blocks;

            GenerateGapTimeEntryBlocks(timeEntries);
        }
コード例 #52
0
        private void selectClient(Toggl.TogglGenericView item)
        {
            this.selectedClientGUID = item.GUID;
            this.selectedClientName = item.Name;
            this.clientTextBox.SetText(item.Name);

            if (item.WID != 0)
            {
                this.selectedWorkspaceId = item.WID;
                this.selectedWorkspaceName = this.workspaces.First(ws => ws.ID == item.WID).Name;
                this.workspaceTextBox.SetText(this.selectedWorkspaceName);
            }
        }
コード例 #53
0
 private void HandleDisplayTimeline(bool open, string date, List <Toggl.TimelineChunkView> first, List <Toggl.TogglTimeEntryView> firstTimeEntry, ulong startDay, ulong endDay)
 {
     SelectedDate = Toggl.DateTimeFromUnix(startDay);
     ConvertChunksToActivityBlocks(first);
     ConvertTimeEntriesToBlocks(firstTimeEntry);
 }
コード例 #54
0
        private void selectWorkspace(Toggl.TogglGenericView item)
        {
            if (this.selectedWorkspaceId != item.ID && !this.isInNewClientMode)
            {
                this.selectClient(new Toggl.TogglGenericView());
            }

            this.selectedWorkspaceId = item.ID;
            this.selectedWorkspaceName = item.Name;
            this.workspaceTextBox.SetText(item.Name);
        }
コード例 #55
0
 private static SolidColorBrush getProjectColorBrush(ref Toggl.TogglTimeEntryView item)
 {
     var colourString = string.IsNullOrEmpty(item.Color) ? "#999999" : item.Color;
     var color = (Color)(ColorConverter.ConvertFromString(colourString) ?? Color.FromRgb(153, 153, 153));
     return new SolidColorBrush(color);
 }
コード例 #56
0
        private void onRunningTimerState(Toggl.TimeEntry te)
        {
            if (!this.Dispatcher.CheckAccess())
            {
                this.Dispatcher.BeginInvoke(new Action(() => onRunningTimerState(te)));
                return;
            }

            this.runningTimeEntry = te;
            this.setUIToRunningState(te);
            this.secondsTimer.IsEnabled = true;
        }
コード例 #57
0
 public void Dispose()
 {
     Toggl.Clear();
 }
コード例 #58
0
 private void HandleDisplayLoginSSO(string ssoUrl)
 {
     Toggl.OpenInBrowser(ssoUrl);
 }
コード例 #59
0
 private void onRunningTimerState(Toggl.TogglTimeEntryView te)
 {
     this.activateScreen<BasicTutorialScreen4>();
 }
コード例 #60
0
 private static SolidColorBrush getProjectColorBrush(ref Toggl.TimeEntry item)
 {
     var projectColourString = item.Color != "" ? item.Color : "#999999";
     var projectColor = (Color)ColorConverter.ConvertFromString(projectColourString);
     var projectColorBrush = new SolidColorBrush(projectColor);
     return projectColorBrush;
 }