Repository navigation
v1.1.0
Android's Storage Access Framework becomes usable, two long-standing cgo
memory bugs in the Android bridge are fixed, and the test helpers stop
shipping in production binaries. The minor bump is for the new
storage.CreateChild API. Apps that use auth should read Changed:
sign-in tokens are now kept per app, so users sign in once more after
upgrading. Everything else is additive or a fix. This is also the first
release made with the repository public.
Added
storage.CreateChild, for stores that name their own children
(#303).storage.Child
does path arithmetic — it names a resource whether or not anything is
there — and that does not work where the store assigns identity. Under
Android's SAF a document ID is opaque andDocumentsContracthands the URI
back only on creation, so a folder the user picked could not be scaffolded
into at all.CreateChild(parent, name, listable)asks the store to make
the resource and returns what it called it, and
repository.ChildCreatingRepositoryis the optional capability a repository
implements to answer it. Repositories that can name a child by path
arithmetic implement nothing: for themCreateChildisChildplus
CreateListableor an emptyWriter, and it verifies the resource exists
before returning rather than handing back a URI pointing at nothing.driver/software.WindowlessCanvas, so the software driver's constructors
return a nameable type without reaching intobellui/test
(#304).
Changed
- Sign-in tokens are stored per app
(#335). Every bellui app
on a machine shared onebellui-auth/<provider>.enc, so one app could read
another's sign-in. Tokens now live underbellui-auth/<app ID>/, and the
app ID is part of the encryption key. Behaviour change: tokens saved by
an earlier version are not read, so users sign in once more after
upgrading; andSaveToken,LoadTokenandClearTokennow need an app ID,
returning the newauth.ErrNoAppIDwithout one (Preferences already need
it).
Fixed
- Ctrl+Tab moves focus out of a widget that keeps Tab
(#340). A multi-line
Entryand the x/dag canvas keep Tab and Shift+Tab for themselves, and every
Tab with a modifier went to the shortcut path, so a keyboard-only user who
tabbed into one could not leave it (WCAG 2.1.2). Ctrl+Tab and Ctrl+Shift+Tab
now move focus to the next and previous widget from any such widget, on the
desktop, embedded and mobile drivers. Behaviour change: while a widget
that keeps Tab is focused, Ctrl+Tab no longer reaches the app's main-menu or
widget shortcuts; on every other widget it still does. The web build is not
covered yet: browsers keep Ctrl+Tab for themselves
(#357). - GitHub sign-in asks for GitHub's scopes
(#335). The OpenID
default (openid email profile) was applied before the GitHub branch, so
GitHub never got its own default ofuser:email read:user. desktop.Appis implemented on every desktop platform
(#338). It gained
SetSystemTrayTooltipandSetSystemTrayOnTapped, but the app did not
forward them on macOS, Windows or Linux/BSD, so the documented
if desk, ok := a.(desktop.App); ok { … }check was always false and an
app following it silently got no system tray.- The test helpers no longer ship in production binaries
(#304).driver/software
importedbellui/testfor one interface and two constructors, and
bellui/testimports testify — so every desktop and web binary linked
testify,gopkg.in/yaml.v3, spew, difflib andtesting. In the js/wasm
build ofcmd/bellui_settingsthat was 988,505 bytes, 2.09% of the
artifact, and 208 yaml symbols. The canvas moved tointernal/memcanvas;
the public API is unchanged, sincetest.WindowlessCanvasand
test.SoftwarePainterare now aliases of the moved types. A CI gate keeps
it that way. - Android: every write to a file was a double free
(#315).writeStream
freed the buffer the Go caller had allocated withC.CBytesand frees
itself, which Scudo catches and turns into an abort — "invalid chunk state
when deallocating". Pre-existing; found by the first complete
hack/safproberun. - Android:
contentURIGetFileNamecorrupted the heap and answered the wrong
name (#315). It returned
a string literal on its error path, which the Go caller frees —free()on
static storage. It also queried the raw URI, but_display_nameis a column
of the document, so a tree URI had no row to find andName()fell back to
the percent-encoded document ID:primary%3ADocumentswhere a user expects
Documents. The same literal-return shape was inlistContentURIand
listURI. - Android: a picked SAF folder can be scaffolded into
(#303).CreateChildfor
content://goes throughDocumentsContract.createDocument, and refuses a
duplicate name rather than letting the provider silently invent
"name (1)".Childresolves an existing child by display name, and
reportsstorage.ErrNotExistsfor one that is not there instead of a URI
that looks real.ExistsandDeletework forcontent://.Parent
remains unsupported, and now says why: SAF exposes no upward link. - Android: listing a subdirectory listed the picked folder instead
(#303).Listand
CanListtook their document ID fromgetTreeDocumentId, which returns the
root's ID for any URI under the tree — so a scaffolded tree looked flat. - Android: folder grants survive a restart
(#303). Nothing called
takePersistableUriPermission, so every pick was single-use and an app
could not store a folder URI and reopen it later. - Android:
listContentURIleaked a JNI local reference per row
(#303) — a directory of
any size overruns the 512-entry table, which aborts the process. - A pending double-tap no longer outlives its widget
(#310). A single tap on a
DoubleTappableleaves a timer waitingTapDoubleDelayfor a second one,
and nothing cancelled it when the canvas went away — only a second tap did.
It then dispatched into widgets whose renderers had been destroyed. Tap a
widget, close the dialog holding it inside the double-tap window, and that
was a nil dereference. URI.Path()now says what it is: the RFC3986 path component, and a
filesystem path only underfile://. On Android acontent://URI gives
/tree/primary%3ADocuments, which looks like a path, is not one, and
resolves under/if handed toos.MkdirAll
(#303).
Note
The SAF behaviour above is verified on a device — 21 assertions against the
external-storage provider on an API 34 emulator, including the duplicate-name
refusal and a grant surviving a force-stop — using the new hack/safprobe
harness. The remaining gap is that the run was driven by hand rather than by
the harness's own script
(#314).
Dependencies
github.com/belluikit/systrayv1.12.1: an app's exit callback could run
twice whenQuitraced with the platform's own close handling; it is now
guarded so it runs once.github.com/belluikit/fsnotifyv1.10.2: synced with upstream fsnotify
(v1.10.1 plus later fixes), keeping the fork's Windows fixes.x/mmediarequiresgithub.com/belluikit/goffmpegv0.4.1, whose prebuilt
purego bridges were rebuilt and now expose the device-modes API
(#330).
Licensing
- The EmojiOne Color font ships with its license file again, and
THIRD_PARTY_NOTICES.mdnow covers the fyne-x code and test assets, the
vendored packages, every bundled font, the Material Design icons and the
sign-in logos (#325).
Attributions the rebrand had rewritten to "bellui-x" name fyne-x again.
CI
- CI runs on GitHub-hosted runners with stock Go instead of self-hosted
machines and the go-plus toolchain, and installs the system packages those
images lack (#325,
#329). apt-get installneeds-y: five Linux legs died the moment apt had an
upgrade to do (#307).- chromium is launched without
snap-confine, which had refused to start it
from the runner service and took every wasm package down with it
(#311). TestRenderasserts the rendered image rather than an exact PNG byte
string, which go1.27'scompress/flatechanged
(#318).- The PowerShell go-plus assertions accept
(plus <version>), which go1.27's
fork build reports (#320).
The x/* modules (charts, dag, editor, mmedia, tables) are released as v1.1.0 alongside.