summaryrefslogtreecommitdiffstats
path: root/main.go
diff options
context:
space:
mode:
Diffstat (limited to 'main.go')
-rw-r--r--main.go113
1 files changed, 113 insertions, 0 deletions
diff --git a/main.go b/main.go
new file mode 100644
index 0000000..7b55ae3
--- /dev/null
+++ b/main.go
@@ -0,0 +1,113 @@
+package main
+
+import (
+ "fmt"
+ "log"
+ "net/http"
+ "os"
+
+ "golang.org/x/net/html"
+
+ "gioui.org/app"
+ "gioui.org/font/gofont"
+ "gioui.org/io/system"
+ "gioui.org/layout"
+ "gioui.org/op"
+ "gioui.org/unit"
+ "gioui.org/widget/material"
+)
+
+// FeedItem represents a single RSS entry
+type FeedItem struct {
+ Title string
+ Link string
+}
+
+// Simple RSS fetcher (parses only <item><title> and <link>)
+func fetchRSS(url string) ([]FeedItem, error) {
+ resp, err := http.Get(url)
+ if err != nil {
+ return nil, err
+ }
+ defer resp.Body.Close()
+
+ doc, err := html.Parse(resp.Body)
+ if err != nil {
+ return nil, err
+ }
+
+ var items []FeedItem
+ var f func(*html.Node)
+ f = func(n *html.Node) {
+ if n.Type == html.ElementNode && n.Data == "item" {
+ var item FeedItem
+ for c := n.FirstChild; c != nil; c = c.NextSibling {
+ if c.Type == html.ElementNode {
+ switch c.Data {
+ case "title":
+ if c.FirstChild != nil {
+ item.Title = c.FirstChild.Data
+ }
+ case "link":
+ if c.FirstChild != nil {
+ item.Link = c.FirstChild.Data
+ }
+ }
+ }
+ }
+ items = append(items, item)
+ }
+ for c := n.FirstChild; c != nil; c = c.NextSibling {
+ f(c)
+ }
+ }
+ f(doc)
+ return items, nil
+}
+
+func main() {
+ go func() {
+ w := app.NewWindow(
+ app.Title("MiniRSS"),
+ app.Size(unit.Dp(400), unit.Dp(600)),
+ )
+ if err := loop(w); err != nil {
+ log.Fatal(err)
+ }
+ os.Exit(0)
+ }()
+ app.Main()
+}
+
+func loop(w *app.Window) error {
+ th := material.NewTheme(gofont.Collection())
+
+ // Replace with any RSS feed you want to test
+ feedURL := "https://xkcd.com/atom.xml"
+ items, err := fetchRSS(feedURL)
+ if err != nil {
+ return fmt.Errorf("failed to fetch RSS: %w", err)
+ }
+
+ list := layout.List{
+ Axis: layout.Vertical,
+ }
+
+ var ops op.Ops
+ for {
+ e := <-w.Events()
+ switch e := e.(type) {
+ case system.DestroyEvent:
+ return e.Err
+ case system.FrameEvent:
+ gtx := layout.NewContext(&ops, e)
+
+ list.Layout(gtx, len(items), func(gtx layout.Context, i int) layout.Dimensions {
+ title := material.H6(th, items[i].Title)
+ return title.Layout(gtx)
+ })
+
+ e.Frame(gtx.Ops)
+ }
+ }
+}