feat(studio): rich theme picker (presets + custom colour) + editor 0.11.0
Some checks failed
Security / Security check (push) Failing after 1s

Settings dialog's Theme Plugin section is now a grid of
swatched tiles:

- Built-in (none) — falls back to FaiTheme.light/.dark
- One tile per installed studio.theme.* plugin, each
  showing the plugin's primary/secondary/tertiary as
  live colour dots. Tile loads its preview lazily so a
  dozen installed themes don't block the picker.
- Custom — opens a colour-picker dialog with 12 curated
  Material presets + a hex input + live preview. Selecting
  applies ColorScheme.fromSeed for both brightnesses.

main.dart's _pluginThemes parses a 'custom:#RRGGBB' sigil
in the same notifier slot as plugin capability ids, so the
existing persistence + restoration paths cover the custom
case with no new state.

Bumps editor to 0.11.0 (type-checked port connections +
dynamic card width fix + card-height border allowance) and
Studio to 0.58.0.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
This commit is contained in:
flemming-it 2026-06-02 01:29:34 +02:00
parent 69864da934
commit c1c60d5434
30 changed files with 1280 additions and 846 deletions

View file

@ -15,12 +15,10 @@ import 'package:path/path.dart' as p;
/// based on its own `auth.tokens:` config.
class HubAuthToken {
static String _faiHome() {
final home = Platform.environment['HOME'] ??
Platform.environment['USERPROFILE'];
final home =
Platform.environment['HOME'] ?? Platform.environment['USERPROFILE'];
if (home == null || home.isEmpty) {
throw StateError(
'Cannot resolve home directory (no HOME / USERPROFILE)',
);
throw StateError('Cannot resolve home directory (no HOME / USERPROFILE)');
}
return p.join(home, '.fai');
}
@ -79,7 +77,9 @@ class HubAuthToken {
if ((Platform.isLinux || Platform.isMacOS) && !parentExisted) {
try {
await Process.run('chmod', ['700', parent.path]);
} catch (_) {/* best-effort */}
} catch (_) {
/* best-effort */
}
}
// Write to the temp path with restrictive mode set up
// BEFORE the rename the final file is never visible
@ -88,7 +88,9 @@ class HubAuthToken {
if (Platform.isLinux || Platform.isMacOS) {
try {
await Process.run('chmod', ['600', tmp.path]);
} catch (_) {/* best-effort */}
} catch (_) {
/* best-effort */
}
}
// Atomic rename: on POSIX, replaces the destination
// in one syscall. On Windows, Dart's File.rename uses
@ -105,7 +107,9 @@ class HubAuthToken {
if (Platform.isLinux || Platform.isMacOS) {
try {
await Process.run('chmod', ['600', f.path]);
} catch (_) {/* best-effort */}
} catch (_) {
/* best-effort */
}
}
await tmp.delete();
}