Name the launch screen's entries, and let its folder rows be pressed

A heading above a text field names it on screen and names nothing to the
platform: Slint associates the two only if something says so, and nothing did.
So the four entries a user signs in through — server, username, app password,
folder — reached AT-SPI as unnamed boxes with a separate piece of static text
floating above each. The word is now written twice, deliberately, and the
second copy is the one attached to the control being typed into.

FolderRow is the more consequential half. It is a Rectangle with a TouchArea
over it, which is a button to the user and a decorated box to the platform —
its label got through, because the `Value` inside is a Text, while the fact
that the row could be entered at all did not. The folder picker was therefore
readable and not navigable, which for the screen that chooses where the whole
library lives is the difference between using the application and not.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-30 10:25:58 +02:00
co-authored by Claude Opus 5
parent 7409cb7767
commit 80298403f7
+20
View File
@@ -41,11 +41,21 @@ component FormButton inherits Button {
}
// One folder in the picker. The whole row is the target, not just the text.
//
// A `Rectangle` with a `TouchArea` over it is a button as far as the user is
// concerned and a decorated box as far as the platform is, so the name reaches
// a screen reader — the `Value` below is a `Text` — while the fact that it can
// be entered does not. Saying so is what makes the picker navigable rather
// than merely readable (NFR-A11Y-2).
component FolderRow inherits Rectangle {
in property <string> label;
in property <bool> is-parent: false;
callback clicked();
accessible-role: button;
accessible-label: root.label;
accessible-action-default => { root.clicked(); }
height: Theme.touch-target;
background: touch.has-hover ? Theme.surface-raised : transparent;
border-radius: 3px;
@@ -180,6 +190,13 @@ export component LaunchScreen inherits Rectangle {
PanelHeading { text: @tr("SERVER"); }
server-input := Field {
// The `PanelHeading` above each of these entries names
// it on screen and names nothing at all as far as the
// accessibility tree is concerned — Slint associates a
// heading with the control below it only if something
// says so. `Field.label` is that something, so the word
// is written twice on purpose.
label: @tr("Server address");
text: root.server-url;
placeholder: "https://cloud.example.com";
accepted(url) => { root.sign-in(url); }
@@ -227,12 +244,14 @@ export component LaunchScreen inherits Rectangle {
PanelHeading { text: @tr("USERNAME"); }
user-input := Field {
label: @tr("Username");
text: "";
placeholder: @tr("your Nextcloud username");
}
PanelHeading { text: @tr("APP PASSWORD"); }
pass-input := Field {
label: @tr("App password");
text: "";
placeholder: "xxxxx-xxxxx-xxxxx-xxxxx-xxxxx";
secret: true;
@@ -285,6 +304,7 @@ export component LaunchScreen inherits Rectangle {
PanelHeading { text: @tr("FOLDER"); }
folder-input := Field {
label: @tr("Library folder");
text: root.folder-path;
placeholder: "/home/you/Pictures";
accepted(path) => { root.use-folder(path); }