Many imorovments
Build and test / Desktop (Linux) (push) Failing after 1m8s
Build and test / Android (aarch64) (push) Failing after 2s
Build and test / Layer separation (push) Canceled after 23s
Traceability / Requirement traces (push) Failing after 59s

This commit is contained in:
2026-08-12 22:16:15 +02:00
parent fa12afed18
commit 4d78041d1d
24 changed files with 711 additions and 78 deletions
+5
View File
@@ -216,6 +216,8 @@ export component AppWindow inherits Window {
in-out property <[bool]> launch-format-checked;
callback launch-sign-in(string);
/// server, username, app password
callback launch-sign-in-direct(string, string, string);
callback launch-sign-out();
callback launch-choose-folder();
callback launch-open-library();
@@ -575,6 +577,9 @@ export component AppWindow inherits Window {
format-checked: root.launch-format-checked;
sign-in(server) => { root.launch-sign-in(server); }
sign-in-direct(server, user, pw) => {
root.launch-sign-in-direct(server, user, pw);
}
sign-out() => { root.launch-sign-out(); }
choose-folder() => { root.launch-choose-folder(); }
open-library() => { root.launch-open-library(); }
+60
View File
@@ -114,6 +114,8 @@ export component LaunchScreen inherits Rectangle {
// --- events out ---
callback sign-in(string);
/// server, username, app password
callback sign-in-direct(string, string, string);
callback sign-out();
callback choose-folder();
callback open-library();
@@ -196,6 +198,64 @@ export component LaunchScreen inherits Rectangle {
text: "Sign-in happens in your browser. DarkRoom never sees your password.";
wrap: word-wrap;
}
// --- or: an app password entered directly ---
//
// The browser flow above is preferred because no credential
// ever reaches us. This exists for the cases it cannot
// serve: no browser able to complete the handshake, or a
// user who would rather paste a token they can revoke.
HorizontalLayout {
spacing: Theme.gap;
alignment: center;
Rectangle {
height: 1px;
background: Theme.rule;
horizontal-stretch: 1;
}
Caption { text: "or"; }
Rectangle {
height: 1px;
background: Theme.rule;
horizontal-stretch: 1;
}
}
PanelHeading { text: "USERNAME"; }
user-input := Field {
text: "";
placeholder: "your Nextcloud username";
}
PanelHeading { text: "APP PASSWORD"; }
pass-input := Field {
text: "";
placeholder: "xxxxx-xxxxx-xxxxx-xxxxx-xxxxx";
secret: true;
accepted(pw) => {
root.sign-in-direct(server-input.text, user-input.text, pw);
}
}
FormButton {
text: root.busy ? "Connecting…" : "Connect directly";
enabled: !root.busy
&& server-input.text != ""
&& user-input.text != ""
&& pass-input.text != "";
clicked => {
root.sign-in-direct(
server-input.text,
user-input.text,
pass-input.text,
);
}
}
Caption {
text: "Create one in Nextcloud under Settings → Security → Devices & sessions. It is device-scoped and can be revoked on its own.";
wrap: word-wrap;
}
}
// --- login pending: the browser step ---
+4
View File
@@ -528,6 +528,9 @@ export component Panel inherits Rectangle {
export component Field inherits Rectangle {
in-out property <string> text;
in property <string> placeholder;
/// Masks the entry, for a credential that should not be readable over the
/// user's shoulder. The placeholder still shows while the field is empty.
in property <bool> secret: false;
/// Whether the entry currently holds focus, so a caller can enable its
/// submit button from the same fact the border is drawn from.
out property <bool> has-focus: input.has-focus;
@@ -552,6 +555,7 @@ export component Field inherits Rectangle {
width: parent.width - 2 * Theme.gap;
height: 100%;
single-line: true;
input-type: root.secret ? InputType.password : InputType.text;
accepted => { root.accepted(self.text); }
}