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); }
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); }
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(); }
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 }
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; }
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); }
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); }
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; } }
public PerformanceToken(string activity) { Toggl.Debug(string.Format("Starting activity '{0}'", activity)); this.activity = activity; this.timer = Stopwatch.StartNew(); }
public TimerEntryListViewViewModel() { this.WhenValueChanged(x => SelectedTab) .Subscribe(value => Toggl.SetActiveTab(value)); Toggl.OnDisplayTimelineUI += isEnabled => IsTimelineViewEnabled = isEnabled; }
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, ", "); } }
public TimerEntry Initialised(Toggl.TogglAutocompleteView item, Action selectWithClick) { this.setText(item); this.setClickAction(selectWithClick); return this; }
private void AddNewTimeEntry() { Toggl.CreateEmptyTimeEntry(Started, Ended); }
public void FormatDurationInSecondsHHMMSSReturnsCorrectResult(long durationInSeconds, string expectedResult) { var formatted = Toggl.FormatDurationInSecondsHHMMSS(durationInSeconds); Assert.Equal(expectedResult, formatted); }
public void ChangeStartTime() { Toggl.SetTimeEntryStartTimeStampWithOption(TimeEntryId, (long)TimelineUtils.ConvertOffsetToUnixTime(VerticalOffset, DateCreated, _hourHeight), true); }
public void SendFeedbackShouldNotFail() { Assert.True(Toggl.SendFeedback("topic", "details", "filename")); }
public void ViewTimeEntryListShouldContainKnownTimeEntry() { Toggl.ViewTimeEntryList(); Assert.Contains(_state.TimeEntries, te => te.ID == (ulong)89818605); }
public void OpenInBrowserShouldNotCrash() { Toggl.OpenInBrowser(); }
public void SetIdleSecondsDoesNotCrash() { Toggl.SetIdleSeconds(123); }
public void SetWakeDoesNotCrash() { Toggl.SetWake(); }
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(); }
public void ChangeEndTime() { Toggl.SetTimeEntryEndTimeStamp(TimeEntryId, (long)TimelineUtils.ConvertOffsetToUnixTime(VerticalOffset + Height, DateCreated, _hourHeight)); }
private static SolidColorBrush getProjectColorBrush(ref Toggl.TimeEntry item) { return getProjectColorBrush(item.Color); }
public void UserEmailReturnsCorrectData() { Assert.Equal("*****@*****.**", Toggl.UserEmail()); }
public void SetSleepDoesNotCrash() { Toggl.SetSleep(); }
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); }
private void AddNewTimeEntry() { var guid = Toggl.Start("", "0", 0, 0, "", "", isMiniTimer); Toggl.Edit(guid, false, Toggl.Duration); }
public TaskEntry Initialised(Toggl.TogglAutocompleteView item, Action selectWithClick) { this.task.Text = item.TaskLabel; this.setClickAction(selectWithClick); return this; }
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; } }
private void onRunningTimerState(Toggl.TogglTimeEntryView te) { if (this.TryBeginInvoke(this.onRunningTimerState, te)) return; this.updateTracking(te); }
public void ForgotPasswordShouldNotCrash() { Toggl.PasswordForgot(); }
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(); }
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; }
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); }
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(); } } }
public void Dispose() { _runningTimerState.Dispose(); Toggl.Clear(); }
private void onRunningTimerState(Toggl.TimeEntry te) { if (this.invoke(() => this.onRunningTimerState(te))) return; this.runningTimeEntry = te; this.setUIToRunningState(te); this.secondsTimer.IsEnabled = true; }
public async Task GoogleLoginAsync() { await GoogleAuth(accessToken => Toggl.GoogleLogin(accessToken), "Login"); }
public ProjectInfo(Toggl.AutocompleteItem item) { this.projectId = item.ProjectID; this.taskId = item.TaskID; }
private void AddNewTimeEntry() { TimeEntryId = Toggl.CreateEmptyTimeEntry(Started, Ended); OpenEditView.Execute().Subscribe(); }
private static SolidColorBrush getProjectColorBrush(ref Toggl.AutocompleteItem item) { return getProjectColorBrush(item.ProjectColor); }
public void ChangeEndTime() { Toggl.SetTimeEntryEndTimeStamp(TimeEntryId, (long)ConvertOffsetToTime(VerticalOffset + Height, Toggl.DateTimeFromUnix(Ended).Date)); }
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); }
public void SyncDoesNotCrash() { Toggl.Sync(); }
public async Task GoogleSignupAsync() { await GoogleAuth(accessToken => Toggl.GoogleSignup(accessToken, SelectedCountry?.ID ?? default), "Signup"); }
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); }
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); }
public ModelEntry Initialised(Toggl.TogglGenericView item, Action selectWithClick, string overrideText = null) { this.text.Text = overrideText ?? item.Name; this.setClickAction(selectWithClick); return this; }
public void ChangeStartTime() { Toggl.SetTimeEntryStartTimeStamp(TimeEntryId, (long)ConvertOffsetToTime(VerticalOffset, Toggl.DateTimeFromUnix(Started).Date)); }
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; } } } }
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); }
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); } }
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); }
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); }
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); }
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; }
public void Dispose() { Toggl.Clear(); }
private void HandleDisplayLoginSSO(string ssoUrl) { Toggl.OpenInBrowser(ssoUrl); }
private void onRunningTimerState(Toggl.TogglTimeEntryView te) { this.activateScreen<BasicTutorialScreen4>(); }
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; }