Now you can filter news too

Also note that the main stash state and the filter state now operate
independently.
This commit is contained in:
Christian Rocha 2020-11-25 20:15:21 -05:00
parent 40a02259fc
commit fc898831af
3 changed files with 50 additions and 71 deletions

View file

@ -51,14 +51,21 @@ const (
stashStateLoadingDocument stashStateLoadingDocument
stashStateSettingNote stashStateSettingNote
stashStateShowingError stashStateShowingError
stashStateFilterNotes
stashStateShowFiltered
stashStateShowNews stashStateShowNews
) )
type filterState int
const (
unfiltered filterState = iota
filtering // user is actively setting a filter
filterApplied // a filter is applied and user is not editing filter
)
type stashModel struct { type stashModel struct {
general *general general *general
state stashState state stashState
filterState filterState
err error err error
spinner spinner.Model spinner spinner.Model
noteInput textinput.Model noteInput textinput.Model
@ -124,6 +131,7 @@ func (m *stashModel) setSize(width, height int) {
} }
func (m *stashModel) resetFiltering() { func (m *stashModel) resetFiltering() {
m.filterState = unfiltered
m.filterInput.Reset() m.filterInput.Reset()
sort.Stable(markdownsByLocalFirst(m.markdowns)) sort.Stable(markdownsByLocalFirst(m.markdowns))
m.filteredMarkdowns = nil m.filteredMarkdowns = nil
@ -132,14 +140,7 @@ func (m *stashModel) resetFiltering() {
// Is a filter currently being applied? // Is a filter currently being applied?
func (m stashModel) isFiltering() bool { func (m stashModel) isFiltering() bool {
switch m.state { return m.filterState != unfiltered
case stashStateFilterNotes, stashStateShowFiltered:
return true
case stashStatePromptDelete, stashStateSettingNote:
return m.filterInput.Value() != ""
default:
return false
}
} }
// Should we be updating the filter? // Should we be updating the filter?
@ -422,8 +423,7 @@ func (m stashModel) update(msg tea.Msg) (stashModel, tea.Cmd) {
// Stash or news results have come in from the server. // Stash or news results have come in from the server.
// //
// With the stash, this doesn't mean the whole stash listing is loaded, // With the stash, this doesn't mean the whole stash listing is loaded,
// but some we've finished checking for the stash, at least, so mark // but now know it can load, at least, so mark the stash as loaded here.
// the stash as loaded here.
var docs []*markdown var docs []*markdown
switch msg := msg.(type) { switch msg := msg.(type) {
@ -507,14 +507,17 @@ func (m stashModel) update(msg tea.Msg) (stashModel, tea.Cmd) {
} }
} }
if m.filterState == filtering {
cmds = append(cmds, m.handleFiltering(msg))
return m, tea.Batch(cmds...)
}
// Updates per the current state // Updates per the current state
switch m.state { switch m.state {
case stashStateReady, stashStateShowFiltered, stashStateShowNews: case stashStateReady, stashStateShowNews:
cmds = append(cmds, m.handleDocumentBrowsing(msg)) cmds = append(cmds, m.handleDocumentBrowsing(msg))
case stashStatePromptDelete: case stashStatePromptDelete:
cmds = append(cmds, m.handleDeleteConfirmation(msg)) cmds = append(cmds, m.handleDeleteConfirmation(msg))
case stashStateFilterNotes:
cmds = append(cmds, m.handleFiltering(msg))
case stashStateSettingNote: case stashStateSettingNote:
cmds = append(cmds, m.handleNoteInput(msg)) cmds = append(cmds, m.handleNoteInput(msg))
case stashStateShowingError: case stashStateShowingError:
@ -553,10 +556,9 @@ func (m *stashModel) handleDocumentBrowsing(msg tea.Msg) tea.Cmd {
m.paginator.Page = m.paginator.TotalPages - 1 m.paginator.Page = m.paginator.TotalPages - 1
m.index = m.paginator.ItemsOnPage(pages) - 1 m.index = m.paginator.ItemsOnPage(pages) - 1
// Note: esc is only passed trough in stashStateFilterNotes and stashStateShowNews
case "esc": case "esc":
m.state = stashStateReady
m.resetFiltering() m.resetFiltering()
m.state = stashStateReady
// Open document // Open document
case "enter": case "enter":
@ -584,7 +586,7 @@ func (m *stashModel) handleDocumentBrowsing(msg tea.Msg) tea.Cmd {
m.paginator.Page = 0 m.paginator.Page = 0
m.index = 0 m.index = 0
m.state = stashStateFilterNotes m.filterState = filtering
m.filterInput.CursorEnd() m.filterInput.CursorEnd()
m.filterInput.Focus() m.filterInput.Focus()
return textinput.Blink return textinput.Blink
@ -750,13 +752,6 @@ func (m *stashModel) handleDeleteConfirmation(msg tea.Msg) tea.Cmd {
} }
} }
// Set state and delete
if m.isFiltering() {
m.state = stashStateShowFiltered
} else {
m.state = stashStateReady
}
// Update pagination // Update pagination
m.setTotalPages() m.setTotalPages()
@ -765,10 +760,6 @@ func (m *stashModel) handleDeleteConfirmation(msg tea.Msg) tea.Cmd {
default: default:
// Any other keys cancels deletion // Any other keys cancels deletion
m.state = stashStateReady m.state = stashStateReady
if m.filterInput.Value() != "" {
m.state = stashStateShowFiltered
}
return nil
} }
} }
@ -785,7 +776,6 @@ func (m *stashModel) handleFiltering(msg tea.Msg) tea.Cmd {
switch msg.String() { switch msg.String() {
case "esc": case "esc":
// Cancel filtering // Cancel filtering
m.state = stashStateReady
m.resetFiltering() m.resetFiltering()
case "enter", "tab", "shift+tab", "ctrl+k", "up", "ctrl+j", "down": case "enter", "tab", "shift+tab", "ctrl+k", "up", "ctrl+j", "down":
m.hideStatusMessage() m.hideStatusMessage()
@ -814,9 +804,8 @@ func (m *stashModel) handleFiltering(msg tea.Msg) tea.Cmd {
m.filterInput.Blur() m.filterInput.Blur()
m.state = stashStateShowFiltered m.filterState = filterApplied
if m.filterInput.Value() == "" { if m.filterInput.Value() == "" {
m.state = stashStateReady
m.resetFiltering() m.resetFiltering()
} }
} }
@ -847,12 +836,8 @@ func (m *stashModel) handleNoteInput(msg tea.Msg) tea.Cmd {
switch msg.String() { switch msg.String() {
case "esc": case "esc":
// Cancel note // Cancel note
if m.filterInput.Value() != "" {
m.state = stashStateShowFiltered
} else {
m.state = stashStateReady
}
m.noteInput.Reset() m.noteInput.Reset()
m.state = stashStateReady
case "enter": case "enter":
// Set new note // Set new note
md := m.selectedMarkdown() md := m.selectedMarkdown()
@ -860,11 +845,7 @@ func (m *stashModel) handleNoteInput(msg tea.Msg) tea.Cmd {
cmd := saveDocumentNote(m.general.cc, md.ID, newNote) cmd := saveDocumentNote(m.general.cc, md.ID, newNote)
md.Note = newNote md.Note = newNote
m.noteInput.Reset() m.noteInput.Reset()
if m.filterInput.Value() != "" { m.state = stashStateReady
m.state = stashStateShowFiltered
} else {
m.state = stashStateReady
}
return cmd return cmd
} }
} }
@ -890,7 +871,7 @@ func (m stashModel) view() string {
return errorView(m.err, false) return errorView(m.err, false)
case stashStateLoadingDocument: case stashStateLoadingDocument:
s += " " + m.spinner.View() + " Loading document..." s += " " + m.spinner.View() + " Loading document..."
case stashStateReady, stashStateSettingNote, stashStatePromptDelete, stashStateFilterNotes, stashStateShowFiltered, stashStateShowNews: case stashStateReady, stashStateSettingNote, stashStatePromptDelete, stashStateShowNews:
loadingIndicator := " " loadingIndicator := " "
if !m.localOnly() && (!m.loadingDone() || m.loadingFromNetwork || m.spinner.Visible()) { if !m.localOnly() && (!m.loadingDone() || m.loadingFromNetwork || m.spinner.Visible()) {
@ -926,7 +907,7 @@ func (m stashModel) view() string {
logoOrFilter := glowLogoView(" Glow ") logoOrFilter := glowLogoView(" Glow ")
// If we're filtering we replace the logo with the filter field // If we're filtering we replace the logo with the filter field
if m.state == stashStateFilterNotes || m.state == stashStateShowFiltered { if m.isFiltering() {
logoOrFilter = m.filterInput.View() logoOrFilter = m.filterInput.View()
} else if m.state == stashStateShowNews { } else if m.state == stashStateShowNews {
logoOrFilter += newsTitleStyle(" News ") logoOrFilter += newsTitleStyle(" News ")
@ -1081,11 +1062,11 @@ func stashHelpView(m stashModel) string {
h = append(h, "enter: confirm", "esc: cancel") h = append(h, "enter: confirm", "esc: cancel")
} else if m.state == stashStatePromptDelete { } else if m.state == stashStatePromptDelete {
h = append(h, "y: delete", "n: cancel") h = append(h, "y: delete", "n: cancel")
} else if m.state == stashStateFilterNotes && numDocs == 1 { } else if m.filterState == filtering && numDocs == 1 {
h = append(h, "enter: open", "esc: cancel") h = append(h, "enter: open", "esc: cancel")
} else if m.state == stashStateFilterNotes && numDocs == 0 { } else if m.filterState == filtering && numDocs == 0 {
h = append(h, "enter/esc: cancel") h = append(h, "enter/esc: cancel")
} else if m.state == stashStateFilterNotes { } else if m.filterState == filtering {
h = append(h, "enter: confirm", "esc: cancel", "ctrl+j/ctrl+k, ↑/↓: choose") h = append(h, "enter: confirm", "esc: cancel", "ctrl+j/ctrl+k, ↑/↓: choose")
} else if m.state == stashStateShowNews { } else if m.state == stashStateShowNews {
h = append(h, "enter: open", "esc: return", "j/k, ↑/↓: choose", "q: quit") h = append(h, "enter: open", "esc: return", "j/k, ↑/↓: choose", "q: quit")
@ -1093,7 +1074,7 @@ func stashHelpView(m stashModel) string {
if len(m.markdowns) > 0 { if len(m.markdowns) > 0 {
h = append(h, "enter: open") h = append(h, "enter: open")
} }
if m.state == stashStateShowFiltered { if m.filterState == filterApplied {
h = append(h, "esc: clear filter") h = append(h, "esc: clear filter")
} }
if len(m.markdowns) > 1 { if len(m.markdowns) > 1 {

View file

@ -45,15 +45,15 @@ func stashItemView(b *strings.Builder, m stashModel, index int, md *markdown) {
} }
isSelected := index == m.index isSelected := index == m.index
isFilteringNotes := m.state == stashStateFilterNotes isFiltering := m.filterState == filtering
// If there are multiple items being filtered we don't highlight a selected // If there are multiple items being filtered we don't highlight a selected
// item in the results. If we've filtered down to one item, however, // item in the results. If we've filtered down to one item, however,
// highlight that first item since pressing return will open it. // highlight that first item since pressing return will open it.
singleFilteredItem := singleFilteredItem :=
m.state == stashStateFilterNotes && len(m.getVisibleMarkdowns()) == 1 isFiltering && len(m.getVisibleMarkdowns()) == 1
if isSelected && !isFilteringNotes || singleFilteredItem { if isSelected && !isFiltering || singleFilteredItem {
// Selected item // Selected item
switch m.state { switch m.state {
@ -70,7 +70,7 @@ func stashItemView(b *strings.Builder, m stashModel, index int, md *markdown) {
default: default:
gutter = dullFuchsiaFg(verticalLine) gutter = dullFuchsiaFg(verticalLine)
icon = dullFuchsiaFg(icon) icon = dullFuchsiaFg(icon)
if m.state == stashStateShowFiltered || singleFilteredItem { if m.filterState == filterApplied || singleFilteredItem {
s := termenv.Style{}.Foreground(common.Fuschia.Color()) s := termenv.Style{}.Foreground(common.Fuschia.Color())
title = styleFilteredText(title, m.filterInput.Value(), s, s.Underline()) title = styleFilteredText(title, m.filterInput.Value(), s, s.Underline())
} else { } else {
@ -84,7 +84,7 @@ func stashItemView(b *strings.Builder, m stashModel, index int, md *markdown) {
if md.markdownType == NewsDocument { if md.markdownType == NewsDocument {
gutter = " " gutter = " "
if isFilteringNotes && m.filterInput.Value() == "" { if isFiltering && m.filterInput.Value() == "" {
title = dimIndigoFg(title) title = dimIndigoFg(title)
date = dimSubtleIndigoFg(date) date = dimSubtleIndigoFg(date)
} else { } else {
@ -92,7 +92,7 @@ func stashItemView(b *strings.Builder, m stashModel, index int, md *markdown) {
title = styleFilteredText(title, m.filterInput.Value(), s, s.Underline()) title = styleFilteredText(title, m.filterInput.Value(), s, s.Underline())
date = subtleIndigoFg(date) date = subtleIndigoFg(date)
} }
} else if isFilteringNotes && m.filterInput.Value() == "" { } else if isFiltering && m.filterInput.Value() == "" {
icon = dimGreenFg(icon) icon = dimGreenFg(icon)
if title == noMemoTitle { if title == noMemoTitle {
title = dimWarmGrayFg(title) title = dimWarmGrayFg(title)

View file

@ -164,15 +164,10 @@ type model struct {
// method alters the model we also need to send along any commands returned. // method alters the model we also need to send along any commands returned.
func (m *model) unloadDocument() []tea.Cmd { func (m *model) unloadDocument() []tea.Cmd {
m.state = stateShowStash m.state = stateShowStash
m.stash.state = stashStateReady
m.pager.unload() m.pager.unload()
m.pager.showHelp = false m.pager.showHelp = false
if m.stash.filterInput.Value() == "" {
m.stash.state = stashStateReady
} else {
m.stash.state = stashStateShowFiltered
}
var batch []tea.Cmd var batch []tea.Cmd
if m.pager.viewport.HighPerformanceRendering { if m.pager.viewport.HighPerformanceRendering {
batch = append(batch, tea.ClearScrollArea) batch = append(batch, tea.ClearScrollArea)
@ -250,19 +245,22 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch m.state { switch m.state {
case stateShowStash: case stateShowStash:
switch m.stash.state { // Q quits if we're filtering, but we still send esc though.
if m.stash.isFiltering() {
// Send q/esc through in these cases if msg.String() == "q" {
case stashStateSettingNote, stashStatePromptDelete,
stashStateShowingError, stashStateFilterNotes,
stashStateShowFiltered, stashStateShowNews:
// If we're fitering, only send esc through so we can clear
// the filter results. Q quits as normal.
if m.stash.state == stashStateShowFiltered && msg.String() == "q" {
return m, tea.Quit return m, tea.Quit
} }
// Q also quits glow when displaying only newsitems m.stash, cmd = m.stash.update(msg)
return m, cmd
}
// Send q/esc through in these cases
switch m.stash.state {
case stashStateSettingNote, stashStatePromptDelete,
stashStateShowingError, stashStateShowNews:
// Q also quits glow when displaying only newsitems. Esc
// still passes through.
if m.stash.state == stashStateShowNews && msg.String() == "q" { if m.stash.state == stashStateShowNews && msg.String() == "q" {
return m, tea.Quit return m, tea.Quit
} }