commit 1499ba5280aaa3fe86be3a98fba6b7ebafe536ef
parent ecefaa6c180930ffe10c71bcf633bcf19df53875
Author: FIGBERT <figbert@figbert.com>
Date: Tue, 5 Sep 2023 08:50:10 -0700
Add open-story-in-browser and error handling
Diffstat:
M | api/api.go | | | 4 | ++-- |
A | cmds.go | | | 52 | ++++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | main.go | | | 43 | +++++++++++++++++++++++++++++++++++++------ |
3 files changed, 91 insertions(+), 8 deletions(-)
diff --git a/api/api.go b/api/api.go
@@ -9,13 +9,13 @@ import (
)
type PageMsg []Post
-type ErrorMsg error
+type ErrorMsg struct{}
func FetchPage(index int) tea.Cmd {
return func() tea.Msg {
posts, err := page(index)
if err != nil {
- return ErrorMsg(err)
+ return ErrorMsg{}
}
return PageMsg(*posts)
diff --git a/cmds.go b/cmds.go
@@ -0,0 +1,52 @@
+package main
+
+import (
+ "os/exec"
+ "runtime"
+ "time"
+
+ "github.com/charmbracelet/bubbles/list"
+ "github.com/charmbracelet/bubbletea"
+)
+
+type genericError struct{}
+type postHasNoLinkToOpen struct{}
+type platformUnsupported struct{}
+type msgExpired struct{}
+type loading struct{}
+
+func attemptToOpenPostURL(itm list.Item) tea.Cmd {
+ return func() tea.Msg {
+ i, ok := itm.(item)
+ if !ok {
+ return genericError{}
+ }
+
+ if i.post.URL == "" {
+ return postHasNoLinkToOpen{}
+ }
+
+ switch runtime.GOOS {
+ case "darwin":
+ cmd := exec.Command("open", i.post.URL)
+ _ = cmd.Start()
+ case "linux":
+ cmd := exec.Command("xdg-open", i.post.URL)
+ _ = cmd.Start()
+ case "windows":
+ cmd := exec.Command("rundll32", "url.dll,FileProtocolHandler", i.post.URL)
+ _ = cmd.Start()
+ }
+
+ return platformUnsupported{}
+ }
+}
+
+func clearMsg() tea.Msg {
+ time.Sleep(time.Second * 5)
+ return msgExpired{}
+}
+
+func startLoading() tea.Msg {
+ return loading{}
+}
diff --git a/main.go b/main.go
@@ -14,11 +14,12 @@ type model struct {
width, height int
page int
+ msg string
posts list.Model
}
func (m model) Init() tea.Cmd {
- return api.FetchPage(m.page)
+ return tea.Batch(api.FetchPage(m.page), startLoading)
}
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
@@ -33,10 +34,12 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch key.String() {
case "ctrl+c":
return m, tea.Quit
+ case "o":
+ cmds = append(cmds, attemptToOpenPostURL(m.posts.SelectedItem()))
case "j":
if m.posts.Index() == len(m.posts.Items())-1 {
m.page++
- cmds = append(cmds, api.FetchPage(m.page))
+ cmds = append(cmds, api.FetchPage(m.page), startLoading)
}
fallthrough
default:
@@ -45,9 +48,26 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
cmds = append(cmds, cmd)
}
} else if psts, ok := msg.(api.PageMsg); ok {
+ m.msg = ""
for _, pst := range []api.Post(psts) {
m.posts.SetItems(append(m.posts.Items(), item{post: pst}))
}
+ } else if _, ok := msg.(api.ErrorMsg); ok {
+ m.msg = "Failed to fetch new stories."
+ cmds = append(cmds, clearMsg)
+ } else if _, ok := msg.(loading); ok {
+ m.msg = "Loading…"
+ } else if _, ok := msg.(genericError); ok {
+ m.msg = "Error! How perplexing."
+ cmds = append(cmds, clearMsg)
+ } else if _, ok := msg.(postHasNoLinkToOpen); ok {
+ m.msg = "This post does not have an external URL to open."
+ cmds = append(cmds, clearMsg)
+ } else if _, ok := msg.(platformUnsupported); ok {
+ m.msg = "Exotic! Opening URLs on your OS is not yet supported. Reach out!"
+ cmds = append(cmds, clearMsg)
+ } else if _, ok := msg.(msgExpired); ok {
+ m.msg = ""
}
return m, tea.Batch(cmds...)
@@ -56,12 +76,23 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
func (m model) View() string {
var view strings.Builder
- view.WriteString("\n " + ui.Title().Render("Lobsters") + "\n")
- view.WriteString(" " + ui.HR(m.width-2) + "\n")
+ view.WriteString("\n " + ui.Title().Render("Lobsters"))
- if len(m.posts.Items()) == 0 {
- view.WriteString(" " + ui.SecondaryText().Render("Loading…"))
+ padding := m.width - 1 - 8 - len(m.msg) - 1
+ if padding < 0 {
+ errorDot := ui.Title().Render("● ")
+ padding = m.width - 1 - 8 - 1 - 1
+ if padding < 0 {
+ view.WriteString(" " + errorDot)
+ } else {
+ view.WriteString(strings.Repeat(" ", padding) + errorDot)
+ }
} else {
+ view.WriteString(strings.Repeat(" ", padding) + ui.SecondaryText().Render(m.msg) + " ")
+ }
+
+ view.WriteString("\n " + ui.HR(m.width-2) + "\n")
+ if len(m.posts.Items()) > 0 {
view.WriteString(m.posts.View())
}