feat(studio): de-jargonize, reveal-in-OS, copyable errors, today carousel, AppBar alignment, F∆I window title (v0.34.0)
Sweeping pass against six user reports collected this session. 1. "Capabilities ist nicht deutsch, Chain auch nicht." The DE locale still leaked English vocabulary. Replaced "Capabilities" → "Fähigkeiten" and "Chain" / "Hash-Chain" → "Kette" / "Hash-Kette" everywhere — store search hint, recommended-source body, federated toast, doctor summary chain row, modules panel summary, MCP / n8n hints, the approvals history blurb. Wire-level identifiers (`chain.reset`) stay as code. 2. "Bei Fehlern unten muss man die auch ins clipboard kopieren können." New `FaiErrorBox` widget: selectable monospace block with a small copy-to-clipboard icon button that flips to a checkmark for two seconds after click. Applied to the Doctor update banner output and the Settings channel toast — the two places long stderr / stdout lands. 3. "Öffnen bei Log kann es nicht öffnen. Audit-DB auch nicht. PID auch nicht." Cause: `SystemActions.openInOs` shells out to `open` / `xdg-open` on file paths the OS has no default handler for (SQLite DB, PID file, log without an .ext that binds). New `revealInOs` uses `open -R` on macOS, `explorer /select,` on Windows, and the parent directory via `xdg-open` on Linux. Doctor's path rows carry an `isDirectory` flag that routes through the new `openOrReveal` so files reveal in Finder / Explorer instead of failing silently. 4. "Oben im Store könnte man diesen Redaktionshinweis auch so bauen, dass man mit pfeil nach rechts links auch weitere anzeigen kann." The Today-Hero became a carousel. Curated fallback list grew from one entry to four (public sources, the sandbox-by-default permission story, the hash-chained audit story, the air-gap-ready single-binary pitch). Hero gets prev / next chevrons plus a dot indicator when the current snapshot has more than one slide. Operator-accepted stories stay single — the carousel collapses when there's only one to show. 5. "Ich fände es schöner wenn rechts und links im Store die Abstände konsistent sind, das Reload-Symbol rechts ist zu weit rechts und Store links auch nicht bündig." AppBar now has `titleSpacing: FaiSpace.xl` so the title's left edge sits flush with the body's left padding (24 dp), and the trailing `SizedBox` after the reload icon shrunk so the icon's outer edge meets the right edge of the rightmost grid card. 6. "Oben der Titel zeigt fai_studio an, das sollte F∆I Studio sein." The OS window title was the pubspec-derived "fai_studio". Macos/Linux/Windows runners now hard-code "F∆I Studio" (with the U+2206 triangle escape so the C++ source stays ASCII). macOS bundle name and display name lifted out of the PRODUCT_NAME variable for the same reason. Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
This commit is contained in:
parent
22a851b7e2
commit
3b5fb027c3
17 changed files with 454 additions and 119 deletions
|
|
@ -39,6 +39,50 @@ class SystemActions {
|
|||
}
|
||||
}
|
||||
|
||||
/// Reveal [path] in the platform file manager. Works for binary
|
||||
/// files (the SQLite audit DB, the PID file) where `openInOs`
|
||||
/// would fall flat — macOS refuses to "open" a file with no
|
||||
/// registered app. macOS uses `open -R`; Windows
|
||||
/// `explorer /select,`; Linux falls back to opening the parent
|
||||
/// directory because there is no portable reveal-and-highlight.
|
||||
static Future<({bool ok, String stderr})> revealInOs(String path) async {
|
||||
if (path.isEmpty) {
|
||||
return (ok: false, stderr: 'empty path');
|
||||
}
|
||||
try {
|
||||
final ProcessResult r;
|
||||
if (Platform.isMacOS) {
|
||||
r = await Process.run('open', ['-R', path]);
|
||||
} else if (Platform.isWindows) {
|
||||
// /select, requires no space after the comma; explorer
|
||||
// returns 1 even on success, so don't gate on exitCode.
|
||||
r = await Process.run('explorer', ['/select,$path']);
|
||||
return (ok: true, stderr: '');
|
||||
} else {
|
||||
// Linux: open the containing directory in the default
|
||||
// file manager. Best portable approximation.
|
||||
final parent = File(path).parent.path;
|
||||
r = await Process.run('xdg-open', [parent]);
|
||||
}
|
||||
if (r.exitCode == 0) return (ok: true, stderr: '');
|
||||
return (ok: false, stderr: r.stderr.toString().trim());
|
||||
} catch (e) {
|
||||
return (ok: false, stderr: e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/// Convenience: reveal binary files, open directories /
|
||||
/// text-shaped paths normally. Doctor's path rows use this so
|
||||
/// the operator never has to know which strategy fits which
|
||||
/// kind of file.
|
||||
static Future<({bool ok, String stderr})> openOrReveal(
|
||||
String path, {
|
||||
required bool isDirectory,
|
||||
}) async {
|
||||
if (isDirectory) return openInOs(path);
|
||||
return revealInOs(path);
|
||||
}
|
||||
|
||||
/// Run a `fai daemon ...` subcommand and surface the captured
|
||||
/// output. Used by Doctor's "Restart daemon" button.
|
||||
static Future<({bool ok, String stdout, String stderr})> faiDaemon(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue