app

package
v1.5.0 Latest Latest
Warning

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

Go to latest
Published: Oct 17, 2026 License: Apache-2.0 Imports: 40 Imported by: 0

Documentation

Overview

Package app is Godwit's desktop interface: one App whose view is rebuilt every frame from state that only the UI thread changes.

Index

Constants

This section is empty.

Variables

View Source
var Version = "dev"

Version is the app's version; cmd/godwit sets it from the packaged app.

Functions

This section is empty.

Types

type App

type App struct {
	// contains filtered or unexported fields
}

App is the interface's state. Every field is read and written on the UI thread.

func New

func New(d Deps) *App

New builds an App; Start brings it up.

func (*App) BeforeClose

func (a *App) BeforeClose(proceed func())

BeforeClose saves the signature page's edit and the settings' account fields, waits for every write in flight, then calls proceed: before the window closes or the App quits (compose windows have flushed their drafts by then, on their own). When a write fails, or they have not finished within flushWait, the window shows and asks whether to close anyway; writes that finish while it asks close after all.

func (*App) BodyBuilt

func (a *App) BodyBuilt(view ui.NativeWebView, message int64, cut, remote bool)

BodyBuilt is told message's body as its page got it: whether it is only the start (ReaderBody.Cut), for the truncated notice, and has the remote images (Remote), which hides their notice.

func (*App) BodyFailed

func (a *App) BodyFailed(view ui.NativeWebView, message int64, err error)

BodyFailed is told reading message's body with its remote images failed: the notice offers a retry.

func (*App) BodyHeight

func (a *App) BodyHeight(view ui.NativeWebView, message int64, px int)

BodyHeight is told the height, in CSS pixels, of message's body as its page laid it out: its element takes it.

func (a *App) BodyLink(view ui.NativeWebView, link string)

BodyLink opens a link of a body's page as one of the native reader's: http(s) after the confirmation, mailto in a compose window.

func (*App) BodyNavigate

func (a *App) BodyNavigate(view ui.NativeWebView, dir int)

BodyNavigate goes back or forward for a body's page (⌘[ and ⌘]).

func (*App) BodySearch

func (a *App) BodySearch(view ui.NativeWebView)

BodySearch opens the mail list's search for a body's page (⌘F).

func (*App) BodyWheel

func (a *App) BodyWheel(view ui.NativeWebView, dy float64)

BodyWheel is told a vertical wheel delta a body's page did not use: the reader scrolls by it, within its content.

func (*App) Close

func (a *App) Close()

Close cancels all work in flight, whose done callbacks never run, closes the reader's body pages and removes the temporary copies of opened attachments. UI thread.

func (*App) Compose

func (a *App) Compose()

Compose starts a new draft in a compose window, as the sidebar's button does.

func (*App) ComposeWindowsChanged

func (a *App) ComposeWindowsChanged()

ComposeWindowsChanged is told a compose window opened or went (on the UI thread): the drafts list is read again, and the pane follows its draft.

func (*App) ConversationCreated

func (a *App) ConversationCreated(id, version int64)

ConversationCreated is told the Wit page's first question made conversation id, under snapshot version: while the route still shows that version's new conversation it takes id in place (back and forward keep it), and the page is told it as a new version, so a page that reloaded meanwhile shows it too; the sidebar reads the conversations again either way.

func (*App) KeepInBackground

func (a *App) KeepInBackground() bool

KeepInBackground reports whether closing the window only hides it.

func (*App) LocalAPIStopped

func (a *App) LocalAPIStopped(gen uint64, err error)

LocalAPIStopped tells the App that the Local API server that request gen asked for ended by itself with err. Safe from any goroutine.

func (*App) Navigate

func (a *App) Navigate(dir int)

Navigate goes back (dir < 0) or forward (dir > 0), as ⌘[ and ⌘] do: the Wit page forwards them, as native shortcuts miss keys it has.

func (*App) NotificationClicked

func (a *App) NotificationClicked(id string)

NotificationClicked shows the window with what a notification was about: its message, or the account's inbox for a gathered one. Only the newest click navigates, and only if the route has not changed meanwhile; a click before the first load waits for it.

func (*App) OnUI

func (a *App) OnUI(f func())

OnUI posts f to the UI thread unless the App has closed by then, for callbacks from elsewhere (the Wit page's).

func (*App) OpenMessage

func (a *App) OpenMessage(id int64)

OpenMessage opens message id in the reader (a mail the Wit page cites).

func (*App) OpenModels

func (a *App) OpenModels()

OpenModels opens the model settings (the Wit page's model chip).

func (*App) OpenSettings added in v0.2.0

func (a *App) OpenSettings()

OpenSettings opens the settings, as the app menu's Settings… does.

func (*App) SetForeground

func (a *App) SetForeground(on bool)

SetForeground records whether the window is in front.

func (*App) SetWitAsk

func (a *App) SetWitAsk(ask func(query string))

SetWitAsk gives the App the hand-off of a question to the Wit page (the page starts the run itself, so it follows it and Stop works). Call it before Start.

func (*App) SetWitPage

func (a *App) SetWitPage(view ui.NativeWebView, open, created func(conv int64) (version int64))

SetWitPage gives the App the Wit page's web view and open, which tells the page the route's conversation and returns its snapshot version; created does the same for a conversation the page's first question made. Call it before Start.

func (*App) Start

func (a *App) Start(ctx context.Context)

Start loads accounts and settings and starts the event pump. Cancelling ctx closes the App's work as Close does.

func (*App) SyncAll

func (a *App) SyncAll()

SyncAll syncs every account now.

func (*App) View

func (a *App) View(c *ui.Context)

View builds the window: the title bar, then the page's sidebar on the window material beside its content. First run shows only the onboarding page.

type Clock

type Clock interface {
	Now() time.Time
	AfterFunc(d time.Duration, f func()) (stop func() bool)
}

Clock is the App's time source; tests swap in a fake one.

type Deps

type Deps struct {
	Svc      *core.Service
	Platform Platform
	Post     func(func())
	Clock    Clock
	OAuth    OAuthFlow

	// SystemLanguage is the system's language tag; the interface uses it
	// while Settings.UILanguage is "".
	SystemLanguage string
	// SetLanguage applies the UI preference; an empty tag follows the system.
	// By default only the catalog changes; the desktop also updates MyGo.
	SetLanguage func(string)

	// Vibrancy: the window has a material, which shows around the panel.
	Vibrancy bool

	// Logf logs what fails out of the user's sight (log.Printf by default).
	// Lines carry no secrets and no mail content.
	Logf func(format string, args ...any)

	// Dev: the build is a development one: the rail offers the Kit gallery.
	Dev bool
}

Deps are the App's collaborators. Post runs a function on the UI thread (win.Update in production). Clock and OAuth default to the real ones.

type Notification

type Notification struct {
	ID, Title, Subtitle, Body string
	MessageID                 int64
	Sender                    string // only set when preview is enabled
	ThreadID                  int64
}

Notification is a system notification about a message.

type OAuthFlow

type OAuthFlow interface {
	Begin(ctx context.Context, provider, loginHint string) (flowID, authURL string, err error)
	Await(ctx context.Context, flowID string) (email string, err error)
	Cancel(flowID string)
}

OAuthFlow signs in with an OAuth provider; the default wraps the Service.

type Page

type Page int

Page is a top-level screen.

const (
	PageMail Page = iota
	PageWit
	PageSettings
	PageOnboarding
	PageKit // dev builds only
)

type Platform

type Platform interface {
	OpenURL(url string) error
	OpenPath(path string) error
	OpenFiles(multiple bool) ([]string, error)
	OpenDirectory() (string, error)
	SaveFile(defaultName string) (string, error)
	Notify(n Notification) error
	NotificationsSupported() bool
	SetOpenAtLogin(on bool) error
	SetTrayUnread(n int)              // the inboxes' unread total on the tray; 0 clears it
	SetAppUnread(n int)               // the inboxes' unread total on the app icon; 0 clears it
	SetSignInCodes([]core.SignInCode) // replaces the tray's recent codes; UI thread
	ShowSignInCode(*core.SignInCode)  // a nonactivating copy card; nil dismisses it; UI thread
	SignInCodeBannerSupported() bool  // UI thread; false keeps ordinary mail notifications
	ShowWindow()                      // shows the window, in front
	SetThemeSource(theme string)
	TempDir() string
	// SetLocalAPI starts (on) or stops the Local API server for request
	// gen, returning its socket's path while on. Off when it fails. Blocks:
	// call off the UI thread.
	SetLocalAPI(gen uint64, on bool) (path string, err error)
	// DataDir is the data directory; custom: it is not the default one.
	DataDir() (dir string, custom bool)
	// OpenCompose shows draftID in a compose window of its own.
	OpenCompose(draftID int64)
	// ComposeOpen reports whether draftID's compose window is open or opening.
	// The platform tells the App when that changes: ComposeWindowsChanged.
	ComposeOpen(draftID int64) bool
	// DraftDeleted is told draft id was deleted here: its compose window,
	// if one is open, closes.
	DraftDeleted(id int64)
	// SettingsChanged is told the settings after every change.
	SettingsChanged(st core.Settings)
	// NewBodyView makes a reader page in the main window showing message's
	// body (bound to it before it loads); close unbinds and destroys it.
	// The page reports to BodyHeight, BodyWheel, BodyLink, BodyNavigate,
	// BodyBuilt and BodyFailed with the view. UI thread only; it may run
	// the event loop.
	NewBodyView(message int64) (view ui.NativeWebView, close func(), err error)
	// AllowImages lets the pages showing message load its remote images
	// (加载图片). Call it after NewBodyView: it forgets once the last page
	// of the message closes.
	AllowImages(message int64)
	// TranslateBody replaces only the body's text nodes; nil shows the original.
	TranslateBody(message int64, texts map[string]string)
	// NewSignatureView makes the signature page (the account settings'
	// rich-text editor) in the main window; the App makes one and closes
	// it (unregistered and destroyed) as it closes. show
	// switches it to account: the page saves the shown account's edit as
	// that account first. flush asks the page to save now; done hears
	// whether it did, on the UI thread, at most once. UI thread only.
	NewSignatureView() (view ui.NativeWebView, show func(account int64), flush func(done func(ok bool)), close func(), err error)
}

Platform is what the App needs from the operating system. OpenFiles, OpenDirectory and SaveFile block: call them only off the UI thread.

type Route

type Route struct {
	Page                                Page
	View                                core.View
	ThreadID, MessageID, ConversationID int64
	Settings                            string
}

Route is where the App is.

Jump to

Keyboard shortcuts

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