private static LogItemViewModel header(
            IThreadSafeTimeEntry[] group,
            LogItemVisualizationIntent visualizationIntent,
            DurationFormat durationFormat)
        {
            var sample = group.First();

            return(new LogItemViewModel(
                       groupId: new GroupId(sample),
                       representedTimeEntriesIds: group.Select(timeEntry => timeEntry.Id).ToArray(),
                       visualizationIntent: visualizationIntent,
                       isBillable: sample.Billable,
                       isActive: sample.Project?.Active ?? true,
                       description: sample.Description,
                       duration: DurationAndFormatToString.Convert(
                           TimeSpan.FromSeconds(group.Sum(timeEntry => timeEntry.Duration ?? 0)),
                           durationFormat),
                       projectName: sample.Project?.Name,
                       projectColor: sample.Project?.Color,
                       clientName: sample.Project?.Client?.Name,
                       taskName: sample.Task?.Name,
                       hasTags: sample.Tags.Any(),
                       needsSync: group.Any(timeEntry => timeEntry.SyncStatus == SyncStatus.SyncNeeded),
                       canSync: group.All(timeEntry => timeEntry.SyncStatus != SyncStatus.SyncFailed),
                       isInaccessible: sample.IsInaccessible,
                       indexInLog: 0,
                       dayInLog: 0,
                       daysInThePast: 0,
                       projectIsPlaceholder: sample.Project?.IsPlaceholder() ?? false,
                       taskIsPlaceholder: sample.Task?.IsPlaceholder() ?? false));
        }
Example #2
0
 public static LogItemViewModel ToViewModel(
     this IThreadSafeTimeEntry timeEntry,
     GroupId groupId,
     LogItemVisualizationIntent visualizationIntent,
     DurationFormat durationFormat,
     int indexInLog,
     int dayInLog,
     int daysInThePast)
 => new LogItemViewModel(
     groupId,
     new[] { timeEntry.Id },
     visualizationIntent,
     timeEntry.Billable,
     timeEntry.Description,
     timeEntry.Duration.HasValue
             ? DurationAndFormatToString.Convert(
         TimeSpan.FromSeconds(timeEntry.Duration.Value), durationFormat)
             : string.Empty,
     timeEntry.Project?.DisplayName(),
     timeEntry.Project?.DisplayColor(),
     timeEntry.Project?.Client?.Name,
     timeEntry.Task?.Name,
     timeEntry.TagIds.Any(),
     timeEntry.SyncStatus == SyncStatus.SyncNeeded,
     timeEntry.SyncStatus != SyncStatus.SyncFailed,
     timeEntry.IsInaccessible,
     indexInLog,
     dayInLog,
     daysInThePast);
            public void ReturnsNonEmptyStringForValidFormats(DurationFormat format)
            {
                var convertedValue = converter.Convert(TimeSpan.Zero, typeof(string), format, CultureInfo.CurrentCulture);

                convertedValue.Should().BeOfType <string>();
                ((string)convertedValue).Length.Should().BeGreaterThan(0);
            }
Example #4
0
        public IEnumerable <MainLogSection> Flatten(IEnumerable <LogGrouping> days, IThreadSafePreferences preferences)
        {
            durationFormat = preferences.DurationFormat;

            return(days.Select(preferences.CollapseTimeEntries
                ? flatten(bySimilarTimeEntries)
                : flatten(withJustSingleTimeEntries)));
        }
                public void FailsForDurationFormatsWhichAreOutOfRange(DurationFormat format)
                {
                    var successful = tryGetValue(TimeSpan.Zero, format, out var convertedValue);

                    successful.Should().BeTrue();
                    convertedValue.Should().BeOfType <string>();
                    ((string)convertedValue).Length.Should().BeGreaterThan(0);
                }
 private static LogItemViewModel groupItem(IThreadSafeTimeEntry timeEntry, DurationFormat durationFormat)
 => timeEntry.ToViewModel(
     new GroupId(timeEntry),
     LogItemVisualizationIntent.GroupItem,
     durationFormat,
     0,
     0,
     0);
Example #7
0
 public static ChartSegment WithDurationFormat(this ChartSegment segment, DurationFormat durationFormat)
 => new ChartSegment(
     segment.ProjectName,
     segment.Percentage,
     (float)segment.TrackedTime.TotalSeconds,
     segment.BillableSeconds,
     segment.Color,
     durationFormat);
Example #8
0
 private void onPreferencesChanged(IThreadSafePreferences preferences)
 {
     if (durationFormat != preferences.DurationFormat)
     {
         durationFormat = preferences.DurationFormat;
         var _ = fetchSectionedTimeEntries();
     }
 }
Example #9
0
 public static ReportsSummaryData Create(
     IReadOnlyList <ChartSegment> segments,
     bool showEmptyState, TimeSpan totalTime,
     bool totalTimeIsZero,
     float?billablePercentage,
     DurationFormat durationFormat)
 {
     return(new ReportsSummaryData(segments, showEmptyState, totalTime, totalTimeIsZero, billablePercentage ?? 0f, durationFormat));
 }
Example #10
0
            public void StartsWithZero(DurationFormat format, string expectedOutput)
            {
                var observer = TestScheduler.CreateObserver <string>();

                ViewModel.TimeTrackedToday.Subscribe(observer);

                durationFormatSubject.OnNext(format);
                TestScheduler.Start();

                observer.Messages.First().Value.Value.Should().Be(expectedOutput);
            }
        public ISpannable convertReportTimeSpanToDurationString(TimeSpan timeSpan, DurationFormat durationFormat)
        {
            var timeString = timeSpan.ToFormattedString(durationFormat);

            var emphasizedPartLength = durationFormat == DurationFormat.Improved
                ? timeString.Length - 3
                : timeString.Length;

            var isDisabled = timeSpan.Ticks == 0;

            return(selectTimeSpanEnabledStateSpan(timeString, emphasizedPartLength, isDisabled));
        }
Example #12
0
            public void EmitsCorrectlyFormattedTimeBasedOnUsersPreferences(DurationFormat format, string expectedOutput)
            {
                var observer = TestScheduler.CreateObserver <string>();

                ViewModel.TimeTrackedToday.Subscribe(observer);

                durationFormatSubject.OnNext(format);
                trackedTimeSubject.OnNext(duration);
                TestScheduler.Start();

                observer.Messages.Skip(1).First().Value.Value.Should().Be(expectedOutput);
            }
Example #13
0
        public Preferences(TimeFormat timeOfDayFormat, DateFormat dateFormat, DurationFormat durationFormat, bool collapseTimeEntries, SyncStatus syncStatus = default(SyncStatus), string lastSyncErrorMessage = "", bool isDeleted = false)
        {
            Ensure.Argument.IsADefinedEnumValue(syncStatus, nameof(syncStatus));
            Ensure.Argument.IsNotNull(dateFormat.Localized, nameof(dateFormat));
            Ensure.Argument.IsNotNull(timeOfDayFormat.Localized, nameof(timeOfDayFormat));

            TimeOfDayFormat      = timeOfDayFormat;
            DateFormat           = dateFormat;
            DurationFormat       = durationFormat;
            CollapseTimeEntries  = collapseTimeEntries;
            SyncStatus           = syncStatus;
            LastSyncErrorMessage = lastSyncErrorMessage;
            IsDeleted            = isDeleted;
        }
Example #14
0
        private void onPreferencesChanged(IThreadSafePreferences preferences)
        {
            durationFormat = preferences.DurationFormat;

            foreach (var collection in TimeEntries)
            {
                collection.DurationFormat = durationFormat;

                foreach (var timeEntry in collection)
                {
                    timeEntry.DurationFormat = durationFormat;
                }
            }
        }
        /// <summary>
        /// Reads in the settings, and returns a string representation
        /// of the <see cref="TimeSpan"/> object based on the settings.
        /// </summary>
        public static string ToSettingsString(this TimeSpan timespan, DateTimeSettings settings)
        {
            ArgumentNullException.ThrowIfNull(settings, nameof(settings));

            DurationFormat    duration  = settings.DurationFormat;
            DurationSeparator separator = settings.DurationSeparator;

            string formatString;

            if (duration == DurationFormat.HourMinuteSecond)
            {
                if (separator == DurationSeparator.LettersOnly)
                {
                    formatString = @"'H 'mm'M 'ss'S'";
                }
                else if (separator == DurationSeparator.ColonAndLetters)
                {
                    formatString = @"'H'\:mm'M'\:ss'S'";
                }
                else // ColonOnly is the default.
                {
                    formatString = @"\:mm\:ss";
                }
            }
            else // HourMinute (and any others) are the default.
            {
                if (separator == DurationSeparator.LettersOnly)
                {
                    formatString = @"'H 'mm'M'";
                }
                else if (separator == DurationSeparator.ColonAndLetters)
                {
                    formatString = @"'H'\:mm'M'";
                }
                else // ColonOnly is the default.
                {
                    formatString = @"\:mm";
                }
            }

            // For total hours, need to use the TotalHours property instead of using
            // a format string.  Otherwise, if the time is more than a day,
            // it won't report the correct number of hours.
            //
            // Need to Math.Floor it as well, otherwise if we have more than half an hour
            // in the minutes section, it will round up.
            return
                (Math.Floor(timespan.TotalHours).ToString("00") +
                 timespan.ToString(formatString));
        }
Example #16
0
 public ChartSegment(
     string projectName,
     float percentage,
     float trackedSeconds,
     float billableSeconds,
     string color,
     DurationFormat durationFormat = DurationFormat.Improved)
 {
     ProjectName     = projectName;
     Color           = color;
     Percentage      = percentage;
     TrackedTime     = TimeSpan.FromSeconds(trackedSeconds);
     BillableSeconds = billableSeconds;
     DurationFormat  = durationFormat;
 }
Example #17
0
 private ReportsSummaryData(
     IReadOnlyList <ChartSegment> segments,
     bool showEmptyState,
     TimeSpan totalTime,
     bool totalTimeIsZero,
     float billablePercentage,
     DurationFormat durationFormat)
 {
     Segments           = segments;
     ShowEmptyState     = showEmptyState;
     TotalTime          = totalTime;
     TotalTimeIsZero    = totalTimeIsZero;
     BillablePercentage = billablePercentage;
     DurationFormat     = durationFormat;
 }
Example #18
0
 public static string ToFormattedString(this TimeSpan duration, DurationFormat format)
 {
     switch (format)
     {
         case DurationFormat.Classic:
             return convertToClassicFormat(duration);
         case DurationFormat.Improved:
             return convertToImprovedFormat(duration);
         case DurationFormat.Decimal:
             return convertToDecimalFormat(duration);
         default:
             throw new ArgumentOutOfRangeException(
                 $"The duration converter parameter '{format}' is not of the supported formats.");
     }
 }
Example #19
0
        public static DurationFormat GetDistance(BgTaxi.Models.Models.Location location1, BgTaxi.Models.Models.Location location2)
        {
            WebRequest request = WebRequest.Create("https://maps.googleapis.com/maps/api/distancematrix/json?origins=" + location1.Latitude.ToString("0.0000000", System.Globalization.CultureInfo.InvariantCulture) + ", " + location1.Longitude.ToString("0.0000000", System.Globalization.CultureInfo.InvariantCulture) +
                                                   "&destinations=" + location2.Latitude.ToString("0.0000000", System.Globalization.CultureInfo.InvariantCulture) + ", " + location2.Longitude.ToString("0.0000000", System.Globalization.CultureInfo.InvariantCulture) + "&key=AIzaSyCqFT1vjwghgVYc9Y_jbuD-ux10qQD9H0s&language=bg");
            WebResponse response   = request.GetResponse();
            Stream      dataStream = response.GetResponseStream();
            // Open the stream using a StreamReader for easy access.
            StreamReader reader = new StreamReader(dataStream);
            // Read the content.
            string responseFromServer = reader.ReadToEnd();
            // Display the content.
            DurationFormat flight = Newtonsoft.Json.JsonConvert.DeserializeObject <DurationFormat>(responseFromServer);

            return(flight);
        }
Example #20
0
            public async Task ChangesDurationFormat(DurationFormat format)
            {
                var(togglClient, user) = await SetupTestUser();

                var oldPreferences = await togglClient.Preferences.Get();

                var newPreferences = new Preferences(oldPreferences);

                newPreferences.DurationFormat = format;
                await togglClient.Preferences.Update(newPreferences);

                var updatedPreferences = await togglClient.Preferences.Get();

                updatedPreferences.DurationFormat.Should().Be(newPreferences.DurationFormat);
            }
Example #21
0
        public TimeEntryViewModelCollection(DateTime date, IEnumerable <TimeEntryViewModel> items, DurationFormat durationFormat)
        {
            Ensure.Argument.IsNotNull(items, nameof(items));

            if (date.Kind != DateTimeKind.Local)
            {
                throw new ArgumentException($"{nameof(date)} must have kind DateTimeKind.Local");
            }

            this.AddRange(items);

            Date           = new DateTimeOffset(date);
            TotalTime      = calculateTotalTime();
            DurationFormat = durationFormat;
        }
        public IEnumerable <MainLogSection> Flatten(IEnumerable <LogGrouping> days, IThreadSafePreferences preferences)
        {
            durationFormat = preferences.DurationFormat;
            indexInLog     = 0;

            return(days.Select((day, dayInLog) =>
            {
                var today = timeService.CurrentDateTime.Date;
                var sample = day.First().Start.Date;
                var daysInThePast = (today - sample).Days;

                var strategy = preferences.CollapseTimeEntries
                    ? (Func <IEnumerable <IThreadSafeTimeEntry>, IEnumerable <IThreadSafeTimeEntry[]> >)bySimilarTimeEntries
                    : (Func <IEnumerable <IThreadSafeTimeEntry>, IEnumerable <IThreadSafeTimeEntry[]> >)withJustSingleTimeEntries;
                return flatten(strategy, dayInLog, daysInThePast)(day);
            }));
        }
Example #23
0
        public static string ToFormattedString(this DurationFormat durationFormat)
        {
            switch (durationFormat)
            {
            case DurationFormat.Classic:
                return(Resources.DurationFormatClassic);

            case DurationFormat.Improved:
                return(Resources.DurationFormatImproved);

            case DurationFormat.Decimal:
                return(Resources.DurationFormatDecimal);

            default:
                throw new ArgumentException(
                          $"Duration format must be either: {nameof(DurationFormat.Classic)}, {nameof(DurationFormat.Improved)} or {nameof(DurationFormat.Decimal)}"
                          );
            }
        }
Example #24
0
        public TimeEntryViewModel(IThreadSafeTimeEntry timeEntry, DurationFormat durationFormat)
        {
            Ensure.Argument.IsNotNull(timeEntry, nameof(timeEntry));

            if (timeEntry.IsRunning())
            {
                throw new InvalidOperationException("It is not possible to show a running time entry in the log.");
            }

            DurationFormat = durationFormat;

            Id             = timeEntry.Id;
            WorkspaceId    = timeEntry.WorkspaceId;
            StartTime      = timeEntry.Start;
            IsBillable     = timeEntry.Billable;
            TagIds         = timeEntry.TagIds.ToArray();
            HasTags        = TagIds.Count() > 0;
            Description    = timeEntry.Description;
            HasProject     = timeEntry.Project != null;
            Duration       = TimeSpan.FromSeconds(timeEntry.Duration.Value);
            HasDescription = !string.IsNullOrEmpty(timeEntry.Description);

            CanSync   = timeEntry.SyncStatus != SyncStatus.SyncFailed;
            NeedsSync = timeEntry.SyncStatus == SyncStatus.SyncNeeded;

            IsGhost = timeEntry.IsGhost;

            if (!HasProject)
            {
                return;
            }

            ProjectId    = timeEntry.Project.Id;
            ProjectName  = timeEntry.Project.DisplayName();
            ProjectColor = timeEntry.Project.DisplayColor();

            TaskId   = timeEntry.TaskId;
            TaskName = timeEntry.Task?.Name ?? "";

            ClientName = timeEntry.Project.Client?.Name ?? "";
        }
        public void TransformsTimeEntriesIntoACorrectTree(
            DurationFormat durationFormat,
            IEnumerable <IGrouping <DateTime, IThreadSafeTimeEntry> > log,
            HashSet <GroupId> expandedGroups,
            params AnimatableSectionModel <DaySummaryViewModel, LogItemViewModel, IMainLogKey>[] expectedTree)
        {
            var preferences =
                new MockPreferences
            {
                CollapseTimeEntries = true,
                DateFormat          = DateFormat.FromLocalizedDateFormat("YYYY-MM-DD"),
                DurationFormat      = durationFormat
            };

            var collapsingStrategy = new TimeEntriesGroupsFlattening(timeService);

            expandedGroups.ForEach(collapsingStrategy.ToggleGroupExpansion);

            var actualTree = collapsingStrategy.Flatten(log, preferences);

            actualTree.Should().BeEquivalentTo(expectedTree);
        }
        public static string ToLabelString(
            this DurationFormat format,
            DateTimeSettings currentSettings,
            TimeSpan sampleTime
            )
        {
            string label;

            if (format == DurationFormat.HourMinuteSecond)
            {
                label = "Hour Minute Second";
            }
            else // Hour Minute is the default.
            {
                label = "Hour Minute";
            }

            DateTimeSettings settings = currentSettings with {
                DurationFormat = format
            };

            return($"{label} ({sampleTime.ToSettingsString( settings )})");
        }
 private string toFormattedString(TimeSpan timeSpan, DurationFormat format)
 {
     return(timeSpan.ToFormattedString(format));
 }
        private static IEnumerable <LogItemViewModel> expanded(IThreadSafeTimeEntry[] group, DurationFormat durationFormat)
        {
            yield return(header(group, LogItemVisualizationIntent.ExpandedGroupHeader, durationFormat));

            foreach (var timeEntry in group)
            {
                yield return(groupItem(timeEntry, durationFormat));
            }
        }
 private static IEnumerable <LogItemViewModel> collapsed(IThreadSafeTimeEntry[] group, DurationFormat durationFormat)
 {
     yield return(header(group, LogItemVisualizationIntent.CollapsedGroupHeader, durationFormat));
 }
 private static IEnumerable <LogItemViewModel> single(IThreadSafeTimeEntry timeEntry, DurationFormat durationFormat)
 {
     yield return(timeEntry.ToViewModel(
                      new GroupId(timeEntry),
                      LogItemVisualizationIntent.SingleItem,
                      durationFormat,
                      0,
                      0,
                      0));
 }