Open the bundled manual from Help and from Settings

The packages now carry the manual, but nothing in the application opened
it: the help sheet listed gestures and stopped there.

The help sheet gains a Manual button beside Done, and Settings a Manual
row under About beside the version. Both go through dr_ui::manual, which
finds the installed page through dr_plat::system_data_dirs (the package's
share directory on Linux, the executable's directory on Windows), and a
development build also in the checkout it was compiled from. A copy with
no manual says so on the status line rather than doing nothing.

On the desktop the page goes to the system browser. A section is a URL
fragment, and xdg-open's generic mode and Windows' FileProtocolHandler
both turn a file: URL into a path and drop the fragment, so a section is
opened through a one-line redirect page written to the data directory:
the opener gets a plain path, which every opener keeps, and the browser
follows the redirect to index.html#section itself. The launcher behind
the sign-in's open_in_browser is split out so both share it; the https
check stays with the sign-in.

Android has no path to give a browser: an asset is not a file, a copy in
private storage is unreadable to other apps, a file: URI across apps is
refused, and a content: URI leaves the browser resolving every picture
against the provider. So ManualActivity, a WebView reading
file:///android_asset/manual/index.html straight out of the APK, shows
it, started by class name with the section as an extra. JavaScript is
off, links off the page go to the browser, and the theme is day-night so
the page's own light and dark follow the system. A test checks that the
manifest, the Java class and dr_ui agree on the name and the extra.
This commit is contained in:
2026-09-24 22:56:09 -04:00
parent d8f26fb5cd
commit 352e59498b
19 changed files with 571 additions and 98 deletions
+2
View File
@@ -1121,6 +1121,7 @@ in property <bool> panel-visible: true;
diagnostics-prepare() => { root.diagnostics-prepare(); }
diagnostics-save() => { root.diagnostics-save(); }
diagnostics-discard() => { root.diagnostics-discard(); }
open-manual() => { Library.library-open-manual(""); }
close() => { root.settings-close(); }
reset-defaults() => { root.settings-reset(); }
@@ -1439,6 +1440,7 @@ in property <bool> panel-visible: true;
filter-eyes-open: Library.library-filter-eyes-open;
people: Library.library-people;
gestures: Library.library-gestures;
open-manual(anchor) => { Library.library-open-manual(anchor); }
filter-min-rating: Library.library-filter-min-rating;
filter-max-rating: Library.library-filter-max-rating;
filter-rating-range(low, high) => {
+10
View File
@@ -69,6 +69,8 @@ export component GestureSheet inherits Rectangle {
in property <[GestureRow]> rows;
callback close();
/// Open the manual, at a section's anchor or, empty, at the top.
callback open-manual(string);
background: #000000CC;
@@ -172,6 +174,14 @@ export component GestureSheet inherits Rectangle {
HorizontalLayout {
alignment: end;
spacing: Theme.gap;
// The manual is the other half of this sheet: the sheet says
// which move does a thing, the manual shows the thing being
// done. From the one place a puzzled user already is.
Button {
text: "Manual";
clicked => { root.open-manual(""); }
}
Button {
text: "Done";
primary: true;
+5
View File
@@ -723,6 +723,8 @@ export global Library {
/// TRACES: FR-UI-4
/// The gesture reference's rows, read from the generated table.
in property <[GestureRow]> library-gestures;
/// Open the bundled manual, at a section's anchor or, empty, at the top.
callback library-open-manual(string);
in property <[PersonChip]> library-people;
callback library-people-listed();
callback library-filter-person-toggled(int);
@@ -1586,6 +1588,8 @@ export component LibraryGrid inherits Rectangle {
/// The gesture reference's rows, from Rust — which reads them from the
/// generated table. See gestures.slint for why they cannot be written here.
in property <[GestureRow]> gestures;
/// Open the manual, at the section `anchor` names or at the top.
callback open-manual(string);
/// Whether the reference is up. Local, like `naming` and `filing`: nothing
/// in Rust needs to know a sheet is open.
property <bool> helping: false;
@@ -4978,6 +4982,7 @@ export component LibraryGrid inherits Rectangle {
height: 100%;
rows: root.gestures;
close => { root.helping = false; }
open-manual(anchor) => { root.open-manual(anchor); }
}
// --- the naming sheet (FR-CAT-5, FR-CAT-7) ------------------------------
+22
View File
@@ -163,6 +163,10 @@ export component SettingsPage inherits Rectangle {
callback diagnostics-save();
callback diagnostics-discard();
/// TRACES: FR-UI-4
/// Open the manual that came with the application (`dr_ui::manual`).
callback open-manual();
/// TRACES: FR-DSP-8
/// The display showing the canvas, and the colour it is being given.
///
@@ -741,6 +745,24 @@ export component SettingsPage inherits Rectangle {
Value { text: root.app-version; horizontal-stretch: 1; overflow: elide; }
}
// The manual, beside the version because both answer
// "what is this application": one says which, the
// other what it does. Installed with it, so it opens
// with no network.
HorizontalLayout {
spacing: Theme.gap;
Label { text: "Manual"; vertical-alignment: center; }
Rectangle {
horizontal-stretch: 1;
height: Theme.control-height;
Button {
x: 0;
text: "Open the manual";
clicked => { root.open-manual(); }
}
}
}
HorizontalLayout {
spacing: Theme.gap;
Label { text: "Graphics"; }