-
Notifications
You must be signed in to change notification settings - Fork 12
Add shuffle sorting feature with hourly, daily, weekly, and monthly intervals #169
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
e0b8d96
97b7284
0b2afe4
613a8b8
02c9eeb
3172874
bb66611
9a1f0cb
6efc0f3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -26,42 +26,45 @@ type AlbumEvent struct { | |
|
|
||
| func LayoutAlbumEvent(layout Layout, rect render.Rect, event *AlbumEvent, scene *render.Scene, source *image.Source) render.Rect { | ||
|
|
||
| if event.FirstOnDay { | ||
| dateFormat := "Monday, Jan 2" | ||
| if event.First { | ||
| dateFormat = "Monday, Jan 2, 2006" | ||
| // Skip date/time headers when shuffle sort is active (dates are meaningless) | ||
| if !IsShuffleOrder(layout.Order) { | ||
| if event.FirstOnDay { | ||
| dateFormat := "Monday, Jan 2" | ||
| if event.First { | ||
| dateFormat = "Monday, Jan 2, 2006" | ||
| } | ||
| text := render.NewTextFromRect( | ||
| render.Rect{ | ||
| X: rect.X, | ||
| Y: rect.Y, | ||
| W: rect.W, | ||
| H: 40, | ||
| }, | ||
| &scene.Fonts.Header, | ||
| event.StartTime.Format(dateFormat), | ||
| ) | ||
| text.VAlign = canvas.Bottom | ||
| scene.Texts = append(scene.Texts, text) | ||
| rect.Y += text.Sprite.Rect.H | ||
| } | ||
|
|
||
| font := scene.Fonts.Main.Face(50, canvas.Black, canvas.FontRegular, canvas.FontNormal) | ||
| time := event.StartTime.Format("15:00") | ||
|
||
| text := render.NewTextFromRect( | ||
| render.Rect{ | ||
| X: rect.X, | ||
| Y: rect.Y, | ||
| W: rect.W, | ||
| H: 40, | ||
| }, | ||
| &scene.Fonts.Header, | ||
| event.StartTime.Format(dateFormat), | ||
| &font, | ||
| time, | ||
| ) | ||
| text.VAlign = canvas.Bottom | ||
| scene.Texts = append(scene.Texts, text) | ||
| rect.Y += text.Sprite.Rect.H | ||
| } | ||
|
|
||
| font := scene.Fonts.Main.Face(50, canvas.Black, canvas.FontRegular, canvas.FontNormal) | ||
| time := event.StartTime.Format("15:00") | ||
| text := render.NewTextFromRect( | ||
| render.Rect{ | ||
| X: rect.X, | ||
| Y: rect.Y, | ||
| W: rect.W, | ||
| H: 40, | ||
| }, | ||
| &font, | ||
| time, | ||
| ) | ||
| text.VAlign = canvas.Bottom | ||
| scene.Texts = append(scene.Texts, text) | ||
| rect.Y += text.Sprite.Rect.H | ||
|
|
||
| newBounds := addSectionToScene(&event.Section, scene, rect, layout, source) | ||
|
|
||
| rect.Y = newBounds.Y + newBounds.H | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| package layout | ||
|
|
||
| import ( | ||
| "photofield/internal/layout/shuffle" | ||
| "testing" | ||
| ) | ||
|
|
||
| // TestShuffleConstantsMatchRender verifies that layout.Order shuffle constants | ||
| // match the corresponding shuffle package constants | ||
| func TestShuffleConstantsMatchRender(t *testing.T) { | ||
| tests := []struct { | ||
| name string | ||
| layoutConst Order | ||
| shuffleConst shuffle.Order | ||
| }{ | ||
| {"ShuffleHourly", ShuffleHourly, shuffle.Hourly}, | ||
| {"ShuffleDaily", ShuffleDaily, shuffle.Daily}, | ||
| {"ShuffleWeekly", ShuffleWeekly, shuffle.Weekly}, | ||
| {"ShuffleMonthly", ShuffleMonthly, shuffle.Monthly}, | ||
| } | ||
|
|
||
| for _, tt := range tests { | ||
| t.Run(tt.name, func(t *testing.T) { | ||
| if int(tt.layoutConst) != int(tt.shuffleConst) { | ||
| t.Errorf("%s mismatch: layout=%d, shuffle=%d", | ||
| tt.name, int(tt.layoutConst), int(tt.shuffleConst)) | ||
| } | ||
| }) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| package shuffle | ||
|
|
||
| import "time" | ||
|
|
||
| // Order represents a shuffle interval type | ||
| type Order int | ||
|
|
||
| // Order constants for shuffle intervals | ||
| // These match the layout.Order enum values | ||
| const ( | ||
| Hourly Order = 3 | ||
| Daily Order = 4 | ||
| Weekly Order = 5 | ||
| Monthly Order = 6 | ||
| ) | ||
|
Comment on lines
+10
to
+15
|
||
|
|
||
| // TruncateTime truncates the given time based on the shuffle order type. | ||
| // Returns the truncated time for hourly, daily, weekly, or monthly intervals. | ||
| // | ||
| // The order parameter should be one of the shuffle order constants (Hourly, Daily, Weekly, Monthly). | ||
| // For invalid order values, returns zero time. | ||
| func TruncateTime(order Order, t time.Time) time.Time { | ||
| switch order { | ||
| case Hourly: | ||
| return t.Truncate(time.Hour) | ||
| case Daily: | ||
| y, m, day := t.Date() | ||
| loc := t.Location() | ||
| return time.Date(y, m, day, 0, 0, 0, 0, loc) | ||
| case Weekly: | ||
| // Truncate to Monday at midnight local time | ||
| y, m, day := t.Date() | ||
| loc := t.Location() | ||
| weekday := t.Weekday() | ||
| daysFromMonday := int(weekday) - 1 | ||
| if daysFromMonday < 0 { | ||
| daysFromMonday = 6 // Sunday | ||
| } | ||
| mondayDate := time.Date(y, m, day-daysFromMonday, 0, 0, 0, 0, loc) | ||
| return mondayDate | ||
| case Monthly: | ||
| y, m, _ := t.Date() | ||
| loc := t.Location() | ||
| return time.Date(y, m, 1, 0, 0, 0, 0, loc) | ||
| default: | ||
| return time.Time{} | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The MakeValid function adds a "+" prefix to the sort string if it doesn't start with "+" or "-", but it doesn't validate whether the sort value is actually valid (e.g., checking if it matches one of: date, shuffle-hourly, shuffle-daily, shuffle-weekly, shuffle-monthly). Invalid sort values will be silently prefixed and only fail later when OrderFromSort returns None.
Consider adding validation here to ensure the sort value is valid and provide early feedback to users with invalid configuration.