From b0d918b93ead8a0066e38fc885b8abbce2d62406 Mon Sep 17 00:00:00 2001 From: zacaj Date: Tue, 11 Nov 2025 00:03:34 +0000 Subject: [PATCH] (partial) Fix #742: add Date Added column --- .../jellyfin/jellyfinmediaprovider.go | 2 ++ backend/mediaprovider/model.go | 1 + .../subsonic/subsonicmediaprovider.go | 1 + res/translations/en.json | 5 ++-- ui/dialogs/trackinfodialog.go | 5 ++++ ui/util/util.go | 17 ++++++++++++ ui/widgets/tracklist.go | 2 ++ ui/widgets/tracklistrow.go | 26 ++++++++++++++----- 8 files changed, 49 insertions(+), 10 deletions(-) diff --git a/backend/mediaprovider/jellyfin/jellyfinmediaprovider.go b/backend/mediaprovider/jellyfin/jellyfinmediaprovider.go index 69eb2f1..f9d99d0 100644 --- a/backend/mediaprovider/jellyfin/jellyfinmediaprovider.go +++ b/backend/mediaprovider/jellyfin/jellyfinmediaprovider.go @@ -435,6 +435,7 @@ func toTrack(ch *jellyfin.Song) *mediaprovider.Track { } lastPlayed, _ := time.Parse(time.RFC3339Nano, ch.UserData.LastPlayedDate) + dateAdded, _ := time.Parse(time.RFC3339Nano, ch.DateCreated) t := &mediaprovider.Track{ ID: ch.Id, @@ -454,6 +455,7 @@ func toTrack(ch *jellyfin.Song) *mediaprovider.Track { Favorite: ch.UserData.IsFavorite, PlayCount: ch.UserData.PlayCount, LastPlayed: lastPlayed, + DateAdded: dateAdded, } if len(ch.MediaSources) > 0 { t.FilePath = ch.MediaSources[0].Path diff --git a/backend/mediaprovider/model.go b/backend/mediaprovider/model.go index 809e9ec..45cbacb 100644 --- a/backend/mediaprovider/model.go +++ b/backend/mediaprovider/model.go @@ -152,6 +152,7 @@ type Track struct { SampleRate int BitDepth int Channels int + DateAdded time.Time } type ReplayGainInfo struct { diff --git a/backend/mediaprovider/subsonic/subsonicmediaprovider.go b/backend/mediaprovider/subsonic/subsonicmediaprovider.go index 074ae5b..049bb68 100644 --- a/backend/mediaprovider/subsonic/subsonicmediaprovider.go +++ b/backend/mediaprovider/subsonic/subsonicmediaprovider.go @@ -589,6 +589,7 @@ func toTrack(ch *subsonic.Child) *mediaprovider.Track { Favorite: !ch.Starred.IsZero(), PlayCount: int(ch.PlayCount), LastPlayed: ch.Played, + DateAdded: ch.Created, FilePath: ch.Path, Size: ch.Size, BitRate: ch.BitRate, diff --git a/res/translations/en.json b/res/translations/en.json index a3ded54..48cf7da 100644 --- a/res/translations/en.json +++ b/res/translations/en.json @@ -62,6 +62,7 @@ "Content type": "Content type", "Could not reach server": "Could not reach server", "Create new playlist": "Create new playlist", + "Date added": "Date added", "day": "day", "days": "days", "Delete Playlist": "Delete Playlist", @@ -290,12 +291,10 @@ "Oct": "Oct", "Nov": "Nov", "Dec": "Dec", - "playlist.addedtracks": { "one": "Added one track to playlist", "other": "Added {{.trackCount}} tracks to playlist" }, - "x_minutes_ago": { "one": "a minute ago", "other": "{{.minutes}} minutes ago" @@ -316,4 +315,4 @@ "one": "a year ago", "other": "{{.years}} years ago" } -} +} \ No newline at end of file diff --git a/ui/dialogs/trackinfodialog.go b/ui/dialogs/trackinfodialog.go index 3002522..8600f60 100644 --- a/ui/dialogs/trackinfodialog.go +++ b/ui/dialogs/trackinfodialog.go @@ -115,6 +115,11 @@ func (t *TrackInfoDialog) CreateRenderer() fyne.WidgetRenderer { addFormRow(c, lang.L("Channels"), strconv.Itoa(t.track.Channels)) } addFormRow(c, lang.L("File size"), util.BytesToSizeString(t.track.Size)) + + if !t.track.DateAdded.IsZero() { + addFormRow(c, lang.L("Date added"), t.track.DateAdded.Format(time.RFC1123)) + } + addFormRow(c, lang.L("Play count"), strconv.Itoa(t.track.PlayCount)) if !t.track.LastPlayed.IsZero() { diff --git a/ui/util/util.go b/ui/util/util.go index a77f915..2824c34 100644 --- a/ui/util/util.go +++ b/ui/util/util.go @@ -100,6 +100,23 @@ func FormatItemDate(date mediaprovider.ItemDate) string { return sb.String() } +func FormatDate(t time.Time) string { + if t.IsZero() { + return "" + } + + df := dateFormatForLocale(fyne.CurrentDevice().Locale().String()) + switch df { + case DateFormatDMY: + return t.Format("2 Jan 2006") + case DateFormatMDY: + return t.Format("Jan 2 2006") + case DateFormatYMD: + return t.Format("2006 Jan 2") + } + return "" +} + func LastPlayedDisplayString(t time.Time) string { if t.IsZero() { return lang.L("never") diff --git a/ui/widgets/tracklist.go b/ui/widgets/tracklist.go index f792e3b..b8bae4b 100644 --- a/ui/widgets/tracklist.go +++ b/ui/widgets/tracklist.go @@ -461,6 +461,8 @@ func (t *Tracklist) doSortTracks() { } return 0 }) + case ColumnDateAdded: + t.intSort(func(tr *util.TrackListModel) int64 { return tr.Track().DateAdded.Unix() }) } } diff --git a/ui/widgets/tracklistrow.go b/ui/widgets/tracklistrow.go index bf58318..f64eba8 100644 --- a/ui/widgets/tracklistrow.go +++ b/ui/widgets/tracklistrow.go @@ -66,6 +66,7 @@ const ( ColumnBPM = "BPM" ColumnBitrate = "Bitrate" ColumnSize = "Size" + ColumnDateAdded = "DateAdded" ColumnPath = "Path" ) @@ -93,6 +94,7 @@ var ( bpm := lang.L("BPM") bitrate := lang.L("Bit rate") size := lang.L("Size") + dateAdded := lang.L("Date added") filepath := lang.L("File path") CompactTracklistRowColumns = []TracklistColumn{ @@ -111,6 +113,7 @@ var ( {Name: ColumnBPM, Col: ListColumn{Text: bpm, Alignment: fyne.TextAlignTrailing, CanToggleVisible: true}}, {Name: ColumnBitrate, Col: ListColumn{Text: bitrate, Alignment: fyne.TextAlignTrailing, CanToggleVisible: true}}, {Name: ColumnSize, Col: ListColumn{Text: size, Alignment: fyne.TextAlignTrailing, CanToggleVisible: true}}, + {Name: ColumnDateAdded, Col: ListColumn{Text: dateAdded, Alignment: fyne.TextAlignLeading, CanToggleVisible: true}}, {Name: ColumnPath, Col: ListColumn{Text: filepath, Alignment: fyne.TextAlignLeading, CanToggleVisible: true}}, } @@ -129,6 +132,7 @@ var ( {Name: ColumnBPM, Col: ListColumn{Text: bpm, Alignment: fyne.TextAlignTrailing, CanToggleVisible: true}}, {Name: ColumnBitrate, Col: ListColumn{Text: bitrate, Alignment: fyne.TextAlignTrailing, CanToggleVisible: true}}, {Name: ColumnSize, Col: ListColumn{Text: size, Alignment: fyne.TextAlignTrailing, CanToggleVisible: true}}, + {Name: ColumnDateAdded, Col: ListColumn{Text: dateAdded, Alignment: fyne.TextAlignLeading, CanToggleVisible: true}}, {Name: ColumnPath, Col: ListColumn{Text: filepath, Alignment: fyne.TextAlignLeading, CanToggleVisible: true}}, } @@ -152,6 +156,10 @@ var ( widget.NewLabel(lang.LocalizePluralKey("x_minutes_ago", "59 minutes ago", 59, map[string]string{"minutes": "59"})).MinSize().Width, widget.NewLabel(lastPlayed).MinSize().Width+sortIconWidth, ) + dateAddedColWidth := fyne.Max( + widget.NewLabel("2006 Jan 30").MinSize().Width, + widget.NewLabel(dateAdded).MinSize().Width+sortIconWidth, + ) bpmColWidth := fyne.Max( widget.NewLabel(bpm+" ").MinSize().Width, widget.NewLabel("9999").MinSize().Width) @@ -162,10 +170,10 @@ var ( widget.NewLabel("99.9 MB").MinSize().Width, widget.NewLabel(size).MinSize().Width+sortIconWidth) - // #, Title, Artist, Album, Composer, Time, Year, Favorite, Rating, Plays, LastPlayed, Comment, BPM, Bitrate, Size, Path - CompactTracklistRowColumnWidths = []float32{numColWidth, -1, -1, -1, -1, timeColWidth, yearColWidth, favColWidth, ratingColWidth, playsColWidth, lastPlayedColWidth, -1, bpmColWidth, bitrateColWidth, sizeColWidth, -1} - // #, Title/Artist, Album, Composer, Time, Year, Favorite, Rating, Plays, LastPlayed, Comment, BPM, Bitrate, Size, Path - ExpandedTracklistRowColumnWidths = []float32{numColWidth, -1, -1, -1, timeColWidth, yearColWidth, favColWidth, ratingColWidth, playsColWidth, lastPlayedColWidth, -1, bpmColWidth, bitrateColWidth, sizeColWidth, -1} + // #, Title, Artist, Album, Composer, Time, Year, Favorite, Rating, Plays, LastPlayed, Comment, BPM, Bitrate, Size, DateAdded, Path + CompactTracklistRowColumnWidths = []float32{numColWidth, -1, -1, -1, -1, timeColWidth, yearColWidth, favColWidth, ratingColWidth, playsColWidth, lastPlayedColWidth, -1, bpmColWidth, bitrateColWidth, sizeColWidth, dateAddedColWidth, -1} + // #, Title/Artist, Album, Composer, Time, Year, Favorite, Rating, Plays, LastPlayed, Comment, BPM, Bitrate, Size, DateAdded, Path + ExpandedTracklistRowColumnWidths = []float32{numColWidth, -1, -1, -1, timeColWidth, yearColWidth, favColWidth, ratingColWidth, playsColWidth, lastPlayedColWidth, -1, bpmColWidth, bitrateColWidth, sizeColWidth, dateAddedColWidth, -1} }) ) @@ -208,6 +216,7 @@ type tracklistRowBase struct { comment *ttwidget.Label bpm *widget.Label size *widget.Label + dateAdded *widget.Label path *ttwidget.Label // must be injected by extending widget @@ -262,7 +271,7 @@ func NewExpandedTracklistRow(tracklist *Tracklist, im *backend.ImageManager, pla v := makeVerticallyCentered // func alias container := container.New(tracklist.colLayout, - v(t.num), titleArtistImg, v(t.album), v(t.composer), v(t.dur), v(t.year), v(t.favorite), v(t.rating), v(t.plays), v(t.lastPlayed), v(t.comment), v(t.bpm), v(t.bitrate), v(t.size), v(t.path)) + v(t.num), titleArtistImg, v(t.album), v(t.composer), v(t.dur), v(t.year), v(t.favorite), v(t.rating), v(t.plays), v(t.lastPlayed), v(t.comment), v(t.bpm), v(t.bitrate), v(t.size), v(t.dateAdded), v(t.path)) t.Content = container t.setColVisibility = func(colNum int, vis bool) bool { c := container.Objects[colNum].(*fyne.Container) @@ -290,7 +299,7 @@ func NewCompactTracklistRow(tracklist *Tracklist, playingIcon fyne.CanvasObject) t.playingIcon = playingIcon t.Content = container.New(tracklist.colLayout, - t.num, t.name, t.artist, t.album, t.composer, t.dur, t.year, t.favorite, t.rating, t.plays, t.lastPlayed, t.comment, t.bpm, t.bitrate, t.size, t.path) + t.num, t.name, t.artist, t.album, t.composer, t.dur, t.year, t.favorite, t.rating, t.plays, t.lastPlayed, t.comment, t.bpm, t.bitrate, t.size, t.dateAdded, t.path) colHiddenPtrMap := map[int]*bool{ 2: &t.artist.Hidden, @@ -306,7 +315,8 @@ func NewCompactTracklistRow(tracklist *Tracklist, playingIcon fyne.CanvasObject) 12: &t.bpm.Hidden, 13: &t.bitrate.Hidden, 14: &t.size.Hidden, - 15: &t.path.Hidden, + 15: &t.dateAdded.Hidden, + 16: &t.path.Hidden, } t.setColVisibility = func(colNum int, vis bool) bool { ptr, ok := colHiddenPtrMap[colNum] @@ -355,6 +365,7 @@ func (t *tracklistRowBase) create(tracklist *Tracklist) { t.bpm = util.NewTrailingAlignLabel() t.bitrate = util.NewTrailingAlignLabel() t.size = util.NewTrailingAlignLabel() + t.dateAdded = util.NewTruncatingLabel() t.path = util.NewTruncatingTooltipLabel() t.path.OnMouseIn = t.MouseIn t.path.OnMouseOut = t.MouseOut @@ -422,6 +433,7 @@ func (t *tracklistRowBase) doUpdate(tm *util.TrackListModel, rowNum int) { t.bpm.Text = strconv.Itoa(tr.BPM) t.bitrate.Text = strconv.Itoa(tr.BitRate) t.size.Text = util.BytesToSizeString(tr.Size) + t.dateAdded.Text = util.FormatDate(tr.DateAdded) t.path.Text = tr.FilePath t.path.SetToolTip(tr.FilePath) changed = true