ui

package
v0.0.0-...-8f85068 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 13, 2026 License: BSD-3-Clause Imports: 19 Imported by: 0

Documentation

Overview

Package ui renders the reader — a Reddit-style topbar + sidebar + feed — into an RGBA pixel buffer. Chrome and cards are drawn with the go-widgets painter; text is anti-aliased TrueType (see text.go) so it stays clean at any zoom / Retina scale. The sidebar is organised into profiles (tabs) that each group a subset of subreddits — e.g. "Pro" and "Perso". The package has no build tag, so its layout, hit-testing and rendering are exercised by native `go test`; the wasm front-end (cmd/front) drives the same Scene.

Index

Constants

View Source
const (
	MinW = 360
	MinH = 240
)

Minimum sensible surface.

View Source
const (
	MinZoom  = 0.5
	MaxZoom  = 3.0
	ZoomStep = 0.1
)

Display-zoom bounds and step.

View Source
const (
	OSMac     = "mac"
	OSLinux   = "linux"
	OSWindows = "windows"
)

OS tokens understood by ThemeFor. The front-end derives these from navigator.platform / userAgentData.

Variables

View Source
var Sorts = []string{"hot", "new", "top", "rising"}

Sorts is the ordered set of listing sorts shown as topbar tabs.

Functions

func ClampZoom

func ClampZoom(z float64) float64

ClampZoom constrains z to [MinZoom, MaxZoom].

func ResolveTheme

func ResolveTheme(name, os string, prefersDark bool) *toolkit.Theme

ResolveTheme maps a persisted theme name ("system"|"light"|"dark") plus the host OS and the system dark preference to a concrete palette.

func StepZoom

func StepZoom(z float64, dir int) float64

StepZoom moves zoom one step (+1 in, -1 out, 0 none), snapped to the grid.

func ThemeFor

func ThemeFor(os string, dark bool) *toolkit.Theme

ThemeFor returns the palette matching os (one of the OS* tokens) in the requested light/dark variant. Unknown platforms fall back to the toolkit default theme.

Types

type Hit

type Hit struct {
	Kind    HitKind
	Post    reddit.Post // HitPost
	Feed    string      // HitFeed ("" = front page)
	Sort    string      // HitSort
	Profile int         // HitProfile / HitSelectProfile / HitRemoveFeed / HitDeleteProfile
	Value   string      // HitTheme / HitRemoveFeed
}

Hit is the result of Scene.HitTest.

type HitKind

type HitKind int

HitKind classifies what a click landed on.

const (
	HitNone     HitKind = iota
	HitPost             // a feed post (open it)
	HitFeed             // a sidebar bookmark (switch subreddit)
	HitSort             // a topbar sort tab (switch sort)
	HitProfile          // a sidebar profile tab (switch active profile)
	HitSettings         // the sidebar settings entry (open preferences)

	// Settings-view actions (Mode == ModeSettings):
	HitTheme         // Value = "system"|"light"|"dark"
	HitSelectProfile // Profile = index being edited
	HitRemoveFeed    // Profile = index, Value = feed
	HitAddFeed       // commit the input into the edited profile
	HitNewProfile
	HitDeleteProfile // Profile = index
	HitCloseSettings

	// Login-view actions (Mode == ModeLogin):
	HitLoginField  // Profile = 0 (client id) or 1 (client secret)
	HitLoginSubmit // submit the credentials (Touch ID)
	HitLoginCancel

	// Sidebar account entry (feed view):
	HitOpenLogin // open the login form
	HitLogout    // forget stored credentials

	// Topbar search field (feed view):
	HitSearch // focus the filter/search input
)

type Mode

type Mode int

Mode selects which view the scene renders.

const (
	ModeFeed     Mode = iota // the topbar + sidebar + feed
	ModeSettings             // the in-canvas preferences editor
	ModeLogin                // the in-canvas Reddit login form
)

type Scene

type Scene struct {
	W, H int

	Subreddit string // selected subreddit ("" => front page)
	Sort      string
	Profiles  []settings.Profile // sidebar tabs
	Active    int                // active profile index
	Posts     []reddit.Post
	Status    string
	ScrollY   int
	Scale     float64 // display scale (zoom × devicePixelRatio); 0 => 1

	// Preferences view. The "add subreddit" field is a persistent toolkit.Entry
	// (built once in NewScene, edited through its OnEvent), not a plain string
	// rebuilt every frame.
	Mode      Mode
	ThemeName string // "system"|"light"|"dark" (persisted)

	LoggedIn bool // reflects the auth state (drives the sidebar label)
	// contains filtered or unexported fields
}

Scene is the mutable reader state.

func NewScene

func NewScene() *Scene

NewScene returns a Scene at the default size with the light theme and the default (Pro/Perso) profiles.

func (*Scene) ActiveFeeds

func (s *Scene) ActiveFeeds() []string

ActiveFeeds returns the subreddits of the active profile.

func (*Scene) AddInputFeed

func (s *Scene) AddInputFeed()

AddInputFeed adds the typed subreddit to the edited profile and clears the field. Blank/duplicate entries are ignored.

func (*Scene) Backspace

func (s *Scene) Backspace()

Backspace removes the last rune of the focused text field.

func (*Scene) CloseSettings

func (s *Scene) CloseSettings()

CloseSettings returns to the feed view.

func (*Scene) DeleteProfile

func (s *Scene) DeleteProfile(i int)

DeleteProfile removes profile i (never below one profile) and re-clamps the active + edited indices.

func (*Scene) Draw

func (s *Scene) Draw(buf []byte)

Draw paints the whole scene into buf (s.W*s.H*4 RGBA bytes).

func (*Scene) FeedName

func (s *Scene) FeedName() string

FeedName returns a human-readable label for the current feed.

func (*Scene) FocusLoginField

func (s *Scene) FocusLoginField(i int)

FocusLoginField selects which field receives typed text (0 id, 1 secret).

func (*Scene) FocusSearch

func (s *Scene) FocusSearch(v bool)

FocusSearch sets/clears focus on the topbar filter field.

func (*Scene) HitTest

func (s *Scene) HitTest(x, y int) Hit

HitTest maps a click to an action.

func (*Scene) Input

func (s *Scene) Input() string

Input returns the current add-subreddit text (for the front-end display).

func (*Scene) LoginCredentials

func (s *Scene) LoginCredentials() (id, secret string)

LoginCredentials returns the typed client id + secret.

func (*Scene) MaxScroll

func (s *Scene) MaxScroll() int

MaxScroll is the largest valid ScrollY for the current content.

func (*Scene) NewProfile

func (s *Scene) NewProfile()

NewProfile appends a fresh profile and selects it for editing.

func (*Scene) NextLoginField

func (s *Scene) NextLoginField()

NextLoginField moves focus to the other field (Tab).

func (*Scene) OpenLogin

func (s *Scene) OpenLogin()

OpenLogin enters the login view with empty fields.

func (*Scene) OpenSettings

func (s *Scene) OpenSettings()

OpenSettings enters the preferences view, editing the active profile.

func (*Scene) RemoveFeed

func (s *Scene) RemoveFeed(i int, feed string)

RemoveFeed drops feed from profile i.

func (*Scene) Resize

func (s *Scene) Resize(w, h int)

Resize sets the surface to w×h pixels (clamped) and re-clamps scroll.

func (*Scene) Scroll

func (s *Scene) Scroll(dy int) bool

Scroll adjusts the vertical scroll by dy, clamped. Returns whether it moved.

func (*Scene) Search

func (s *Scene) Search() string

Search returns the current filter term (the SearchEntry's committed text).

func (*Scene) SearchFocused

func (s *Scene) SearchFocused() bool

SearchFocused reports whether the topbar filter field has focus.

func (*Scene) SelectEdit

func (s *Scene) SelectEdit(i int)

SelectEdit picks which profile the editor operates on (clamped).

func (*Scene) SetActive

func (s *Scene) SetActive(i int)

SetActive selects the active profile (clamped to a valid index).

func (*Scene) SetFeed

func (s *Scene) SetFeed(subreddit, sort string)

SetFeed records the current subreddit/sort selection. subreddit "" is the front page.

func (*Scene) SetLoginError

func (s *Scene) SetLoginError(msg string)

SetLoginError shows an error under the form (e.g. a cancelled Touch ID).

func (*Scene) SetPosts

func (s *Scene) SetPosts(posts []reddit.Post)

SetPosts replaces the visible posts and resets scroll.

func (*Scene) SetProfiles

func (s *Scene) SetProfiles(profiles []settings.Profile, active int)

SetProfiles replaces the profile list and active index (clamped).

func (*Scene) SetSearch

func (s *Scene) SetSearch(q string)

SetSearch replaces the filter term and resets scroll.

func (*Scene) SetTheme

func (s *Scene) SetTheme(t *toolkit.Theme)

SetTheme swaps the palette. A nil theme is ignored.

func (*Scene) SetThemeName

func (s *Scene) SetThemeName(name string)

SetThemeName records the chosen theme ("system"|"light"|"dark").

func (*Scene) Settings

func (s *Scene) Settings() settings.Settings

Settings snapshots the editor state for persistence.

func (*Scene) TypeRune

func (s *Scene) TypeRune(r rune)

TypeRune appends a printable rune to whichever text field has focus (the topbar filter, the add-subreddit field in settings, or a login field).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL