From cdfe068cd23a58be1a947e208232931bc13550d9 Mon Sep 17 00:00:00 2001 From: decentral1se Date: Wed, 10 May 2023 19:24:10 +0200 Subject: [PATCH] feat: datasheet loading spinner --- gshmm.go | 98 +++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 69 insertions(+), 29 deletions(-) diff --git a/gshmm.go b/gshmm.go index 534215a..d49443d 100644 --- a/gshmm.go +++ b/gshmm.go @@ -8,6 +8,7 @@ import ( "path/filepath" "strings" + "github.com/charmbracelet/bubbles/spinner" "github.com/charmbracelet/bubbles/textinput" "github.com/charmbracelet/bubbles/viewport" tea "github.com/charmbracelet/bubbletea" @@ -68,9 +69,11 @@ func readPDF(name string) (string, error) { type model struct { input textinput.Model // Fuzzy search interface - datasheets []datasheet // All datasheets under cwd - datasheetNames []string // All datasheet names (caching) - filteredDatasheets []string // Filtered view on all datasheets + datasheets []datasheet // All datasheets under cwd + datasheetNames []string // All datasheet names (caching) + filteredDatasheets []string // Filtered view on all datasheets + loadDatasheetSpinner spinner.Model // Spinner to show while loading datasheets + datasheetsLoaded bool // Whether or not the datasheets are loaded or not datasheetViewport viewport.Model // Viewport for the PDF content @@ -108,6 +111,35 @@ func initialModel() model { input := textinput.New() input.Focus() + // TODO: set width/heigh to match terminal. this should also + // be set in relation to the list of filenames also. they + // should have some visually pleasing ratio set i imagine + viewp := viewport.New(60, 30) + + loadDatasheetSpinner := spinner.New() + loadDatasheetSpinner.Spinner = spinner.Dot + loadDatasheetSpinner.Style = lipgloss.NewStyle().Foreground(lipgloss.Color("205")) + + m := model{ + input: input, + datasheetsLoaded: false, + loadDatasheetSpinner: loadDatasheetSpinner, + datasheetViewport: viewp, + filterMode: filenameFilterMode, + } + + return m +} + +// loadedDatasheetsMsg signals to the UI that the datasheets have been loaded. +type loadedDatasheetsMsg struct { + datasheets []datasheet + datasheetNames []string +} + +// loadDatasheets loads the datasheets from disk. The UI shows a spinner while +// this is happening so that nobody gets bored. +func loadDatasheets(m model) loadedDatasheetsMsg { var datasheets []datasheet var datasheetNames []string @@ -138,28 +170,19 @@ func initialModel() model { return nil }) - // TODO: set width/heigh to match terminal. this should also - // be set in relation to the list of filenames also. they - // should have some visually pleasing ratio set i imagine - viewp := viewport.New(60, 30) - selectedDatasheet := datasheets[len(datasheets)-1].contents - viewp.SetContent(selectedDatasheet) - - m := model{ - input: input, - datasheets: datasheets, - datasheetNames: datasheetNames, - filteredDatasheets: datasheetNames, - datasheetViewport: viewp, - filterMode: filenameFilterMode, + return loadedDatasheetsMsg{ + datasheets: datasheets, + datasheetNames: datasheetNames, } - - return m } // Init initialises the program. func (m model) Init() tea.Cmd { - return textinput.Blink + return tea.Batch( + func() tea.Msg { return loadDatasheets(m) }, + textinput.Blink, + m.loadDatasheetSpinner.Tick, + ) } // filterDatasheetNames filters datasheet names based on user input. @@ -189,7 +212,16 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { cmds []tea.Cmd ) - if m.input.Focused() { + m.input, cmd = m.input.Update(msg) + cmds = append(cmds, cmd) + + m.datasheetViewport, cmd = m.datasheetViewport.Update(msg) + cmds = append(cmds, cmd) + + m.loadDatasheetSpinner, cmd = m.loadDatasheetSpinner.Update(msg) + cmds = append(cmds, cmd) + + if m.input.Focused() && m.datasheetsLoaded { m.filteredDatasheets = filterDatasheetNames(m) // TODO: implement cursor for scrolling up/down filtered @@ -202,6 +234,15 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { // TODO: handle terminal resizing switch msg := msg.(type) { + case loadedDatasheetsMsg: + m.datasheets = msg.datasheets + m.datasheetNames = msg.datasheetNames + m.filteredDatasheets = msg.datasheetNames + + selectedDatasheet := msg.datasheets[len(msg.datasheets)-1].contents + m.datasheetViewport.SetContent(selectedDatasheet) + + m.datasheetsLoaded = true case tea.KeyMsg: switch msg.String() { case "ctrl+c": @@ -211,12 +252,6 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } } - m.input, cmd = m.input.Update(msg) - cmds = append(cmds, cmd) - - m.datasheetViewport, cmd = m.datasheetViewport.Update(msg) - cmds = append(cmds, cmd) - return m, tea.Batch(cmds...) } @@ -224,8 +259,13 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { func (m model) View() string { body := strings.Builder{} - // TODO: paginate / trim view to last 10 or something? - sheets := strings.Join(m.filteredDatasheets, "\n") + var sheets string + if !m.datasheetsLoaded { + sheets = fmt.Sprintf("%s gathering datasheets...", m.loadDatasheetSpinner.View()) + } else { + // TODO: paginate / trim view to last 10 or something? + sheets = strings.Join(m.filteredDatasheets, "\n") + } // TODO: style further with lipgloss, e.g. borders, margins, etc. panes := lipgloss.JoinHorizontal(lipgloss.Left, sheets, m.datasheetViewport.View())