Library: keep the place after removing a title
The list is reloaded after a removal and the selection follows the selected title by id; the removed title is gone, so it fell back to the top. Now a title that has left the library hands its row to the one that moved up into it (or the new last one). A title that is only filtered out still starts the list from the top. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019reK4DUGYqDUjniWYJvwUW
This commit is contained in:
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
- **Library:** after removing a title the selection stays at its place (on the title that moved
|
||||||
|
up into it, or the new last one) instead of jumping to the top of the list.
|
||||||
- **Config (F6):** the default quality profile and root folder are chosen from the lists Radarr
|
- **Config (F6):** the default quality profile and root folder are chosen from the lists Radarr
|
||||||
and Sonarr have, loaded with the address and API key in the fields (when the view opens, and
|
and Sonarr have, loaded with the address and API key in the fields (when the view opens, and
|
||||||
again shortly after either is changed, before saving). A configured value the server does not
|
again shortly after either is changed, before saving). A configured value the server does not
|
||||||
|
|||||||
+18
-2
@@ -391,9 +391,9 @@ func (v *libraryView) render() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v *libraryView) renderPane(p *libPane) {
|
func (v *libraryView) renderPane(p *libPane) {
|
||||||
selID := -1
|
selID, prevRow := -1, 0
|
||||||
if r, _ := p.table.GetSelection(); r >= 1 && r <= len(p.shown) {
|
if r, _ := p.table.GetSelection(); r >= 1 && r <= len(p.shown) {
|
||||||
selID = p.shown[r-1].id
|
selID, prevRow = p.shown[r-1].id, r
|
||||||
}
|
}
|
||||||
p.shown = filterItems(p.all, p.filter, p.text, p.attr)
|
p.shown = filterItems(p.all, p.filter, p.text, p.attr)
|
||||||
|
|
||||||
@@ -408,6 +408,13 @@ func (v *libraryView) renderPane(p *libPane) {
|
|||||||
selRow = i + 1
|
selRow = i + 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if selRow == 0 && selID != -1 && !containsItem(p.all, selID) {
|
||||||
|
// The selected title is gone from the library (removed): stay at its
|
||||||
|
// place, on the title that moved up into it (or the new last one),
|
||||||
|
// instead of jumping to the top. A title that is only filtered out
|
||||||
|
// still starts the list from the top.
|
||||||
|
selRow = min(prevRow, len(p.shown))
|
||||||
|
}
|
||||||
placeholder := "Nothing matches the filter"
|
placeholder := "Nothing matches the filter"
|
||||||
switch {
|
switch {
|
||||||
case p.err != nil && !p.loaded:
|
case p.err != nil && !p.loaded:
|
||||||
@@ -437,6 +444,15 @@ func (v *libraryView) renderPane(p *libPane) {
|
|||||||
p.table.SetTitle(title + " ")
|
p.table.SetTitle(title + " ")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func containsItem(items []libItem, id int) bool {
|
||||||
|
for _, it := range items {
|
||||||
|
if it.id == id {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func (v *libraryView) renderDetails() {
|
func (v *libraryView) renderDetails() {
|
||||||
if it, ok := v.selected(); ok {
|
if it, ok := v.selected(); ok {
|
||||||
v.details.Show(it.details, it.cover)
|
v.details.Show(it.details, it.cover)
|
||||||
|
|||||||
@@ -209,3 +209,51 @@ func TestListedValues(t *testing.T) {
|
|||||||
t.Errorf("empty pool: %v", got)
|
t.Errorf("empty pool: %v", got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRemovingATitleKeepsThePlace(t *testing.T) {
|
||||||
|
a := newTestApp(t)
|
||||||
|
v := newLibraryView(a, a.radarr, a.sonarr)
|
||||||
|
p := v.panes[0]
|
||||||
|
items := func(ids ...int) []libItem {
|
||||||
|
var out []libItem
|
||||||
|
for _, id := range ids {
|
||||||
|
out = append(out, libItem{id: id, title: string(rune('A' + id)), label: string(rune('A' + id))})
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
selectedID := func() int {
|
||||||
|
r, _ := p.table.GetSelection()
|
||||||
|
return p.shown[r-1].id
|
||||||
|
}
|
||||||
|
p.all, p.loaded = items(1, 2, 3, 4, 5), true
|
||||||
|
v.renderPane(p)
|
||||||
|
|
||||||
|
// Remove the third title: the fourth moves up into its place and is selected.
|
||||||
|
p.table.Select(3, 0)
|
||||||
|
p.all = items(1, 2, 4, 5)
|
||||||
|
v.renderPane(p)
|
||||||
|
if r, _ := p.table.GetSelection(); r != 3 || selectedID() != 4 {
|
||||||
|
t.Errorf("after removing the third: row %d, title %d", r, selectedID())
|
||||||
|
}
|
||||||
|
// Remove the last title: the new last one is selected.
|
||||||
|
p.table.Select(4, 0)
|
||||||
|
p.all = items(1, 2, 4)
|
||||||
|
v.renderPane(p)
|
||||||
|
if r, _ := p.table.GetSelection(); r != 3 || selectedID() != 4 {
|
||||||
|
t.Errorf("after removing the last: row %d, title %d", r, selectedID())
|
||||||
|
}
|
||||||
|
// A reload that keeps the title keeps it selected, wherever it is now.
|
||||||
|
p.table.Select(2, 0) // title 2
|
||||||
|
p.all = items(0, 1, 2, 4)
|
||||||
|
v.renderPane(p)
|
||||||
|
if selectedID() != 2 {
|
||||||
|
t.Errorf("kept title not followed: %d", selectedID())
|
||||||
|
}
|
||||||
|
// A title that is only filtered out still starts the list from the top.
|
||||||
|
p.table.Select(4, 0) // title 4
|
||||||
|
p.text = "B" // title 1 only: 4 is filtered out, not removed
|
||||||
|
v.renderPane(p)
|
||||||
|
if r, _ := p.table.GetSelection(); r != 1 {
|
||||||
|
t.Errorf("filtered out: row %d, want the top", r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user