diff --git a/DesktopClock.Tests/DateTimeTests.cs b/DesktopClock.Tests/DateTimeTests.cs index 8600319..d90d244 100644 --- a/DesktopClock.Tests/DateTimeTests.cs +++ b/DesktopClock.Tests/DateTimeTests.cs @@ -1,6 +1,4 @@ using System; -using System.Globalization; -using System.Linq; namespace DesktopClock.Tests; @@ -143,77 +141,4 @@ public void IsOnInterval_CountdownReached_ShouldReturnTrue() Assert.True(result); } - [Theory] - [InlineData("dddd, MMMM dd", "Monday, January 01")] - [InlineData("yyyy-MM-dd", "2024-01-01")] - [InlineData("HH:mm:ss", "00:00:00")] - [InlineData("MMMM dd, yyyy", "January 01, 2024")] - public void FromFormat_CreatesCorrectExample(string format, string expected) - { - // Arrange - var dateTimeOffset = new DateTime(2024, 01, 01); - - // Act - var dateFormatExample = DateFormatExample.FromFormat(format, dateTimeOffset, CultureInfo.InvariantCulture); - - // Assert - Assert.Equal(format, dateFormatExample.Format); - Assert.Equal(expected, dateFormatExample.Example); - } - - [Fact] - public void FromFormat_WithTokenizedFormat_ShouldWork() - { - // Arrange - var dateTimeOffset = new DateTimeOffset(2024, 3, 15, 14, 30, 0, TimeSpan.Zero); - var format = "{ddd}, {MMM dd}, {HH:mm}"; - - // Act - var dateFormatExample = DateFormatExample.FromFormat(format, dateTimeOffset, CultureInfo.InvariantCulture); - - // Assert - Assert.Equal(format, dateFormatExample.Format); - Assert.Equal("Fri, Mar 15, 14:30", dateFormatExample.Example); - } - - [Fact] - public void DefaultExamples_ShouldNotBeEmpty() - { - // Assert - Assert.NotEmpty(DateFormatExample.DefaultExamples); - } - - [Fact] - public void DefaultExamples_AllShouldHaveFormatAndExample() - { - // Assert - foreach (var example in DateFormatExample.DefaultExamples) - { - Assert.NotNull(example.Format); - Assert.NotEmpty(example.Format); - Assert.NotNull(example.Example); - Assert.NotEmpty(example.Example); - } - } - - [Fact] - public void DefaultExamples_ShouldContainCustomFormats() - { - // Assert - check for some expected custom formats - var formats = DateFormatExample.DefaultExamples.Select(e => e.Format).ToList(); - - Assert.Contains(formats, f => f.Contains("{ddd}")); - Assert.Contains(formats, f => f.Contains("{HH:mm}") || f.Contains("{h:mm tt}")); - } - - [Fact] - public void DefaultExamples_ShouldContainStandardFormats() - { - // Assert - check for some expected standard formats - var formats = DateFormatExample.DefaultExamples.Select(e => e.Format).ToList(); - - Assert.Contains("D", formats); // Long date pattern - Assert.Contains("T", formats); // Long time pattern - Assert.Contains("t", formats); // Short time pattern - } } diff --git a/DesktopClock/Data/DateFormatExample.cs b/DesktopClock/Data/DateFormatExample.cs deleted file mode 100644 index 1a9cf0f..0000000 --- a/DesktopClock/Data/DateFormatExample.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; - -namespace DesktopClock; - -public record DateFormatExample -{ - private DateFormatExample(string format, string example) - { - Format = format; - Example = example; - } - - /// - /// The actual format (dddd, MMMM dd). - /// - public string Format { get; } - - /// - /// An example of the format in action (Monday, July 15). - /// - public string Example { get; } - - /// - /// Creates a for the given format. - /// - public static DateFormatExample FromFormat(string format, DateTimeOffset dateTimeOffset, IFormatProvider formatProvider) - { - var example = Tokenizer.FormatWithTokenizerOrFallBack(dateTimeOffset, format, formatProvider); - return new(format, example); - } - - /// - /// Common date time formatting strings and an example string for each. - /// - /// - /// Standard date and time format strings - ///
- /// Custom date and time format strings - ///
- public static IReadOnlyCollection DefaultExamples { get; } = new[] - { - // Custom formats - "{ddd}, {MMM dd}, {HH:mm}", // Custom format: "Mon, Apr 10, 14:30" - "{ddd}, {MMM dd}, {h:mm tt}", // Custom format: "Mon, Apr 10, 2:30 PM" - "{ddd}, {MMM dd}, {HH:mm:ss}", // Custom format: "Mon, Apr 10, 14:30:45" - "{ddd}, {MMM dd}, {h:mm:ss tt}", // Custom format: "Mon, Apr 10, 2:30:45 PM" - "{ddd}, {MMM dd}, {HH:mm K}", // Custom format: "Mon, Apr 10, 14:30 +02:00" - "{ddd}, {MMM dd}, {h:mm tt K}", // Custom format: "Mon, Apr 10, 2:30 PM +02:00" - "{ddd}, {MMM dd}, {yyyy} {HH:mm}", // Custom format: "Mon, Apr 10, 2023 14:30" - "{ddd}, {MMM dd}, {yyyy} {h:mm tt}", // Custom format: "Mon, Apr 10, 2023 14:30" - "{dddd}, {MMMM dd}", // Custom format: "Monday, April 10" - "{dddd}, {MMMM dd}, {HH:mm}", // Custom format: "Monday, April 10, 14:30" - "{dddd}, {MMMM dd}, {h:mm tt}", // Custom format: "Monday, April 10, 2:30 PM" - "{dddd}, {MMM dd}, {HH:mm}", // Custom format: "Monday, Apr 10, 14:30" - "{dddd}, {MMM dd}, {h:mm tt}", // Custom format: "Monday, Apr 10, 2:30 PM" - "{dddd}, {MMM dd}, {HH:mm:ss}", // Custom format: "Monday, Apr 10, 14:30:45" - "{dddd}, {MMM dd}, {h:mm:ss tt}", // Custom format: "Monday, Apr 10, 2:30:45 PM" - - // Standard formats - "D", // Long date pattern: Monday, June 15, 2009 (en-US) - "f", // Full date/time pattern (short time): Monday, June 15, 2009 1:45 PM (en-US) - "F", // Full date/time pattern (long time): Monday, June 15, 2009 1:45:30 PM (en-US) - "R", // RFC1123 pattern: Mon, 15 Jun 2009 20:45:30 GMT (DateTimeOffset) - "M", // Month/day pattern: June 15 (en-US) - "Y", // Year month pattern: June 2009 (en-US) - "t", // Short time pattern: 1:45 PM (en-US) - "T", // Long time pattern: 1:45:30 PM (en-US) - "d", // Short date pattern: 6/15/2009 (en-US) - "g", // General date/time pattern (short time): 6/15/2009 1:45 PM (en-US) - "G", // General date/time pattern (long time): 6/15/2009 1:45:30 PM (en-US) - "u", // Universal sortable date/time pattern: 2009-06-15 13:45:30Z (DateTime) - //"U", // Universal full date/time pattern: Monday, June 15, 2009 8:45:30 PM (en-US) // Not available for DateTimeOffset. - "s", // Sortable date/time pattern: 2009-06-15T13:45:30 - //"O", // Round-trip date/time pattern: 2009-06-15T13:45:30.0000000-07:00 (DateTimeOffset) // Too precise with milliseconds. - }.Select(f => FromFormat(f, DateTimeOffset.Now, CultureInfo.DefaultThreadCurrentCulture)).ToList(); -} diff --git a/DesktopClock/Properties/Settings.cs b/DesktopClock/Properties/Settings.cs index 6cbde02..8361e39 100644 --- a/DesktopClock/Properties/Settings.cs +++ b/DesktopClock/Properties/Settings.cs @@ -348,25 +348,25 @@ private Settings() /// Persisted width of the settings window. /// /// - /// This remembers how wide you last made the settings window so it feels familiar the next time you open it. + /// This helps the settings experience reopen at a comfortable size instead of snapping back to a fixed default. /// - public double SettingsWindowWidth { get; set; } = 720; + public double SettingsWindowWidth { get; set; } = 1120; /// /// Persisted height of the settings window. /// /// - /// This remembers how tall you last made the settings window so you do not have to resize it every time. + /// This helps the settings experience reopen at a comfortable size instead of snapping back to a fixed default. /// - public double SettingsWindowHeight { get; set; } = 600; + public double SettingsWindowHeight { get; set; } = 860; /// - /// Persisted vertical scroll offset of the settings window. + /// Persisted vertical scroll position of the settings window. /// /// - /// This helps reopen the settings window near the same section you were working in before. + /// This lets the scrollable settings experience reopen near the last section the user was editing. /// - public double SettingsScrollPosition { get; set; } = 0; + public double SettingsScrollPosition { get; set; } /// /// Bit flags describing which one-time teaching tips have already been shown. diff --git a/DesktopClock/SettingsWindow.xaml b/DesktopClock/SettingsWindow.xaml index 09b9ae9..6fbc06c 100644 --- a/DesktopClock/SettingsWindow.xaml +++ b/DesktopClock/SettingsWindow.xaml @@ -1,678 +1,1308 @@ - + Background="Transparent" + UseLayoutRounding="True" + SnapsToDevicePixels="True"> + + + + - - - - + + - - - - - - - + + - - - - - - - - - - - - - - - - - - - Learn more - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -