Fix two highlighted fields in the add dialog when unmonitoring
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -60,3 +60,33 @@ func focusedDropDown(f *tview.Form, item int) (*tview.DropDown, bool) {
|
||||
dd, ok := f.GetFormItem(item).(*tview.DropDown)
|
||||
return dd, ok
|
||||
}
|
||||
|
||||
// bindSearchNow keeps a "Search now" checkbox consistent with whether a search
|
||||
// can find anything. While searchable() is false the box is unchecked, greyed
|
||||
// out and cannot be ticked (blocked is called instead); it returns to the
|
||||
// user's earlier choice afterwards. The returned function must be called
|
||||
// whenever the answer of searchable() may have changed.
|
||||
//
|
||||
// tview's SetDisabled is avoided on purpose: on a form item it re-triggers
|
||||
// the form's focus handling and leaves two fields highlighted.
|
||||
func bindSearchNow(box *tview.Checkbox, searchable func() bool, blocked func()) (sync func()) {
|
||||
want := true
|
||||
box.SetChangedFunc(func(checked bool) {
|
||||
switch {
|
||||
case searchable():
|
||||
want = checked
|
||||
case checked:
|
||||
box.SetChecked(false)
|
||||
blocked()
|
||||
}
|
||||
})
|
||||
return func() {
|
||||
if searchable() {
|
||||
box.SetLabelColor(tview.Styles.SecondaryTextColor)
|
||||
box.SetChecked(want)
|
||||
return
|
||||
}
|
||||
box.SetLabelColor(tcell.ColorGray)
|
||||
box.SetChecked(false)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,3 +48,63 @@ func TestArrowNavigation(t *testing.T) {
|
||||
t.Fatalf("Up from first button: item %d, want 1", item)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSearchNowFollowsMonitored(t *testing.T) {
|
||||
f := tview.NewForm().
|
||||
AddDropDown("P", []string{"a"}, 0, nil).
|
||||
AddDropDown("R", []string{"a"}, 0, nil).
|
||||
AddCheckbox("M", true, nil).
|
||||
AddCheckbox("S", true, nil).
|
||||
AddButton("Add", nil)
|
||||
arrowNavigation(f)
|
||||
var focus func(p tview.Primitive)
|
||||
focus = func(p tview.Primitive) { p.Focus(focus) }
|
||||
f.Focus(focus)
|
||||
|
||||
mon := f.GetFormItem(2).(*tview.Checkbox)
|
||||
search := f.GetFormItem(3).(*tview.Checkbox)
|
||||
blocked := 0
|
||||
sync := bindSearchNow(search, mon.IsChecked, func() { blocked++ })
|
||||
mon.SetChangedFunc(func(bool) { sync() })
|
||||
|
||||
cap := f.GetInputCapture()
|
||||
key := func(k tcell.Key) { cap(tcell.NewEventKey(k, 0, 0)) }
|
||||
space := func(item tview.FormItem) {
|
||||
item.InputHandler()(tcell.NewEventKey(tcell.KeyRune, ' ', 0), func(tview.Primitive) {})
|
||||
}
|
||||
focused := func() (n int) {
|
||||
for i := 0; i < f.GetFormItemCount(); i++ {
|
||||
if f.GetFormItem(i).HasFocus() {
|
||||
n++
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
key(tcell.KeyDown)
|
||||
key(tcell.KeyDown) // on "Monitored"
|
||||
space(mon) // unmonitor
|
||||
if search.IsChecked() {
|
||||
t.Error("Search now must be unchecked when not monitored")
|
||||
}
|
||||
key(tcell.KeyUp)
|
||||
if n := focused(); n != 1 {
|
||||
t.Fatalf("%d fields have focus after moving up, want 1", n)
|
||||
}
|
||||
if item, _ := f.GetFocusedItemIndex(); item != 1 {
|
||||
t.Errorf("focus on item %d, want 1", item)
|
||||
}
|
||||
|
||||
key(tcell.KeyDown)
|
||||
key(tcell.KeyDown) // on "Search now"
|
||||
space(search)
|
||||
if search.IsChecked() || blocked != 1 {
|
||||
t.Errorf("ticking while blocked: checked=%v blocked=%d", search.IsChecked(), blocked)
|
||||
}
|
||||
|
||||
key(tcell.KeyUp)
|
||||
space(mon) // monitor again
|
||||
if !search.IsChecked() {
|
||||
t.Error("Search now should return to its previous choice")
|
||||
}
|
||||
}
|
||||
|
||||
+2
-14
@@ -315,26 +315,14 @@ func (v *searchView) add(i int) {
|
||||
// "Search now" only makes sense when something will be monitored.
|
||||
monitored := form.GetFormItemByLabel(lMonitor).(*tview.Checkbox)
|
||||
searchNow := form.GetFormItemByLabel(lSearch).(*tview.Checkbox)
|
||||
wantSearch := true
|
||||
searchable := func() bool {
|
||||
if !monitored.IsChecked() {
|
||||
return false
|
||||
}
|
||||
return len(modes) == 0 || modes[selected(form, lEpisode)].value != sonarr.MonitorNone
|
||||
}
|
||||
syncSearch := func() {
|
||||
if searchable() {
|
||||
searchNow.SetDisabled(false)
|
||||
searchNow.SetChecked(wantSearch)
|
||||
return
|
||||
}
|
||||
searchNow.SetDisabled(true)
|
||||
searchNow.SetChecked(false)
|
||||
}
|
||||
searchNow.SetChangedFunc(func(checked bool) {
|
||||
if searchable() {
|
||||
wantSearch = checked
|
||||
}
|
||||
syncSearch := bindSearchNow(searchNow, searchable, func() {
|
||||
v.app.Notify(levelWarn, "Search now needs something to be monitored")
|
||||
})
|
||||
monitored.SetChangedFunc(func(bool) { syncSearch() })
|
||||
if len(modes) > 0 {
|
||||
|
||||
Reference in New Issue
Block a user