Trakt lists: right-align the numbers
The grey number of every entry ("1.2k watching", "on 18k lists") stood
right after its title, so they did not line up. The rows are now padded
to the list's width on every draw where it changed, putting the numbers
against the right edge; a title too long for that keeps the number right
after it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+2
-1
@@ -4,7 +4,8 @@
|
|||||||
|
|
||||||
- **Trending, most watched and anticipated** movies and series from Trakt: with an empty search
|
- **Trending, most watched and anticipated** movies and series from Trakt: with an empty search
|
||||||
box, Movies and Series show trending now, most watched this week, anticipated, popular and (movies)
|
box, Movies and Series show trending now, most watched this week, anticipated, popular and (movies)
|
||||||
the US box office; `[` `]` switch lists, `r` reloads. Titles in the library are ticked, the others
|
the US box office, each title with its number ("1.2k watching", "on 18k lists", "$48M last
|
||||||
|
weekend") right-aligned in grey; `[` `]` switch lists, `r` reloads. Titles in the library are ticked, the others
|
||||||
can be added and searched like search results. Needs a free Trakt client ID, set in the new Trakt
|
can be added and searched like search results. Needs a free Trakt client ID, set in the new Trakt
|
||||||
section of the Config view (`trakt.client_id`, `ARR_TUI_TRAKT_CLIENT_ID`).
|
section of the Config view (`trakt.client_id`, `ARR_TUI_TRAKT_CLIENT_ID`).
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 69 KiB |
@@ -8,6 +8,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gdamore/tcell/v2"
|
"github.com/gdamore/tcell/v2"
|
||||||
|
|
||||||
|
"git.stinnesbeck.com/nils/arr-tui/internal/radarr"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestTraktListsInTheSearchView(t *testing.T) {
|
func TestTraktListsInTheSearchView(t *testing.T) {
|
||||||
@@ -86,3 +88,43 @@ func TestTraktListsInTheSearchView(t *testing.T) {
|
|||||||
t.Errorf("search row %q", main)
|
t.Errorf("search row %q", main)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestListNumbersAreRightAligned(t *testing.T) {
|
||||||
|
sim := tcell.NewSimulationScreen("")
|
||||||
|
if err := sim.Init(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer sim.Fini()
|
||||||
|
sim.SetSize(60, 6)
|
||||||
|
|
||||||
|
a := newTestApp(t)
|
||||||
|
v := a.searches[0]
|
||||||
|
a.trakt.Reconfigure("id")
|
||||||
|
v.discover[0] = &discovered{at: time.Now(),
|
||||||
|
results: []result{movieResult{Movie: radarr.Movie{Title: "Dune", Year: 2021}}, movieResult{Movie: radarr.Movie{Title: "A Much Longer Title", Year: 2024}}},
|
||||||
|
notes: []string{"1.2k watching", "5 watching"}}
|
||||||
|
v.showList()
|
||||||
|
|
||||||
|
ends := func(width int) []int {
|
||||||
|
sim.Clear()
|
||||||
|
l := notesList{v.list, v}
|
||||||
|
l.SetRect(0, 0, width, 6)
|
||||||
|
l.Draw(sim)
|
||||||
|
var out []int
|
||||||
|
for y := 1; y <= 2; y++ {
|
||||||
|
row := strings.TrimRight(rowText(sim, y, 0, width), " │")
|
||||||
|
out = append(out, len([]rune(row)))
|
||||||
|
if !strings.HasSuffix(row, "watching") {
|
||||||
|
t.Errorf("row %d does not end with its number: %q", y, row)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
if e := ends(60); e[0] != e[1] {
|
||||||
|
t.Errorf("numbers end in columns %v, want the same", e)
|
||||||
|
}
|
||||||
|
// After a resize they line up at the new edge.
|
||||||
|
if e := ends(44); e[0] != e[1] || e[0] > 44 {
|
||||||
|
t.Errorf("after resize: numbers end in columns %v", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+41
-7
@@ -36,6 +36,7 @@ type searchView struct {
|
|||||||
results []result
|
results []result
|
||||||
notes []string // per result, a Trakt list's number ("1.2k watching"); nil for searches
|
notes []string // per result, a Trakt list's number ("1.2k watching"); nil for searches
|
||||||
placeholder string // shown when there are no results
|
placeholder string // shown when there are no results
|
||||||
|
notesWidth int // list width the rows were laid out for
|
||||||
timer *time.Timer
|
timer *time.Timer
|
||||||
cancel context.CancelFunc
|
cancel context.CancelFunc
|
||||||
gen int
|
gen int
|
||||||
@@ -71,7 +72,7 @@ func newSearchView(app *App, be backend) *searchView {
|
|||||||
|
|
||||||
left := tview.NewFlex().SetDirection(tview.FlexRow).
|
left := tview.NewFlex().SetDirection(tview.FlexRow).
|
||||||
AddItem(v.input, 1, 0, true).
|
AddItem(v.input, 1, 0, true).
|
||||||
AddItem(v.list, 0, 1, false)
|
AddItem(notesList{v.list, v}, 0, 1, false)
|
||||||
v.root = tview.NewFlex().
|
v.root = tview.NewFlex().
|
||||||
AddItem(left, 0, 1, true).
|
AddItem(left, 0, 1, true).
|
||||||
AddItem(v.details, 0, 1, false)
|
AddItem(v.details, 0, 1, false)
|
||||||
@@ -279,12 +280,10 @@ func (v *searchView) activate() {
|
|||||||
// render rebuilds the list, selecting index sel.
|
// render rebuilds the list, selecting index sel.
|
||||||
func (v *searchView) render(sel int) {
|
func (v *searchView) render(sel int) {
|
||||||
v.list.Clear()
|
v.list.Clear()
|
||||||
for i, r := range v.results {
|
_, _, width, _ := v.list.GetInnerRect()
|
||||||
label := r.label()
|
v.notesWidth = width
|
||||||
if i < len(v.notes) && v.notes[i] != "" {
|
for i := range v.results {
|
||||||
label += " [gray]" + tview.Escape(v.notes[i]) + "[-]"
|
v.list.AddItem(v.itemText(i, width), "", 0, nil)
|
||||||
}
|
|
||||||
v.list.AddItem(label, "", 0, nil)
|
|
||||||
}
|
}
|
||||||
if len(v.results) == 0 {
|
if len(v.results) == 0 {
|
||||||
if v.placeholder != "" {
|
if v.placeholder != "" {
|
||||||
@@ -298,6 +297,41 @@ func (v *searchView) render(sel int) {
|
|||||||
v.showDetails(sel)
|
v.showDetails(sel)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// itemText is the row of result i in a list width columns wide: the label,
|
||||||
|
// and a Trakt list's number (if any) in grey against the right edge, so the
|
||||||
|
// numbers of all rows line up. A label too long for that gets the number
|
||||||
|
// right after it.
|
||||||
|
func (v *searchView) itemText(i, width int) string {
|
||||||
|
label := v.results[i].label()
|
||||||
|
if i >= len(v.notes) || v.notes[i] == "" {
|
||||||
|
return label
|
||||||
|
}
|
||||||
|
note := tview.Escape(v.notes[i])
|
||||||
|
gap := width - tview.TaggedStringWidth(label) - tview.TaggedStringWidth(note)
|
||||||
|
if gap < 2 {
|
||||||
|
gap = 2
|
||||||
|
}
|
||||||
|
return label + strings.Repeat(" ", gap) + "[gray]" + note + "[-]"
|
||||||
|
}
|
||||||
|
|
||||||
|
// notesList draws the results list, first laying the rows out again when the
|
||||||
|
// width changed (the numbers of a Trakt list sit against the right edge).
|
||||||
|
type notesList struct {
|
||||||
|
*tview.List
|
||||||
|
v *searchView
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n notesList) Draw(screen tcell.Screen) {
|
||||||
|
v := n.v
|
||||||
|
if _, _, width, _ := v.list.GetInnerRect(); width != v.notesWidth && len(v.notes) > 0 {
|
||||||
|
v.notesWidth = width
|
||||||
|
for i := range v.results {
|
||||||
|
v.list.SetItemText(i, v.itemText(i, width), "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
n.List.Draw(screen)
|
||||||
|
}
|
||||||
|
|
||||||
func (v *searchView) showDetails(i int) {
|
func (v *searchView) showDetails(i int) {
|
||||||
if i < 0 || i >= len(v.results) {
|
if i < 0 || i >= len(v.results) {
|
||||||
v.details.Clear()
|
v.details.Clear()
|
||||||
|
|||||||
Reference in New Issue
Block a user