refactor: rename internal Fai* design system + fai_ helpers to chain
Some checks failed
Security / Security check (push) Failing after 2s

The Studio design system, widgets and helpers carried a Fai* / fai_
prefix (FaiSpace, FaiColors, FaiTheme, FaiLog, 17 fai_*.dart files, the
faiBinary* l10n keys). Studio is the Ch∆In product, so rename them to
Chain* / chain_ — carefully preserving English fail/failure/failed.
Also fix stale references: the 'fai' binary in l10n strings -> 'chain',
FAI_* env vars (FAI_BIN/DATA_DIR/MODULES_DIR/TODAY/BOOTSTRAP_TOKEN) ->
CHAIN_*, fai_platform -> fai_chain, fai_hub -> chain_hub. Vendor
security-hook tooling (FAI_BANNED_TERMS_FILE) + the .fai bundle ext left.
flutter analyze + test: clean (20 passed).

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
This commit is contained in:
flemming-it 2026-06-16 17:53:17 +02:00
parent 68d23ab7dd
commit 891acd2ba2
52 changed files with 1225 additions and 1225 deletions

View file

@ -0,0 +1,173 @@
// ChainDeltaMark the ChIn signature element. A precise triangle
// () drawn from primitives, not a font glyph. Three states:
//
// - idle: static, accent colour, soft glow
// - live: gentle pulse, like a heartbeat
// - busy: rotates slowly, used while a long operation runs
//
// Sized small. Lives in the navigation rail header so it's
// always visible and identifies the brand without screaming.
import 'dart:math';
import 'package:flutter/material.dart';
enum ChainDeltaMode { idle, live, busy }
class ChainDeltaMark extends StatefulWidget {
final ChainDeltaMode mode;
final double size;
final Color color;
const ChainDeltaMark({
super.key,
required this.color,
this.mode = ChainDeltaMode.idle,
this.size = 36,
});
@override
State<ChainDeltaMark> createState() => _FaiDeltaMarkState();
}
class _FaiDeltaMarkState extends State<ChainDeltaMark>
with SingleTickerProviderStateMixin {
late final AnimationController _ctrl;
@override
void initState() {
super.initState();
_ctrl = AnimationController(
vsync: this,
duration: _durationFor(widget.mode),
);
_restart();
}
Duration _durationFor(ChainDeltaMode m) {
switch (m) {
case ChainDeltaMode.idle:
return const Duration(seconds: 1);
case ChainDeltaMode.live:
return const Duration(milliseconds: 1600);
case ChainDeltaMode.busy:
return const Duration(seconds: 4);
}
}
void _restart() {
_ctrl.duration = _durationFor(widget.mode);
switch (widget.mode) {
case ChainDeltaMode.idle:
_ctrl.stop();
_ctrl.value = 0;
break;
case ChainDeltaMode.live:
_ctrl.repeat(reverse: true);
break;
case ChainDeltaMode.busy:
_ctrl.repeat();
break;
}
}
@override
void didUpdateWidget(covariant ChainDeltaMark old) {
super.didUpdateWidget(old);
if (old.mode != widget.mode) _restart();
}
@override
void dispose() {
_ctrl.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _ctrl,
builder: (_, _) {
return CustomPaint(
size: Size.square(widget.size),
painter: _DeltaPainter(
color: widget.color,
mode: widget.mode,
t: _ctrl.value,
),
);
},
);
}
}
class _DeltaPainter extends CustomPainter {
final Color color;
final ChainDeltaMode mode;
final double t;
_DeltaPainter({required this.color, required this.mode, required this.t});
@override
void paint(Canvas canvas, Size size) {
final cx = size.width / 2;
final cy = size.height / 2;
// In live mode: scale the whole mark between 0.85 and 1.15
// so the pulse is visible without staring. Idle stays at 1.0.
final scale = mode == ChainDeltaMode.live ? 0.85 + 0.30 * t : 1.0;
final r = size.width * 0.36 * scale;
canvas.save();
canvas.translate(cx, cy);
if (mode == ChainDeltaMode.busy) {
canvas.rotate(t * 2 * pi);
}
// Outer triangle path.
final path = Path()
..moveTo(0, -r)
..lineTo(r * cos(pi / 6), r * sin(pi / 6))
..lineTo(-r * cos(pi / 6), r * sin(pi / 6))
..close();
// Glow halo. In live mode the glow ring grows with the pulse
// and the alpha breathes harder.
if (mode != ChainDeltaMode.idle) {
final pulseStrength = mode == ChainDeltaMode.live ? t : 1.0;
final glow = Paint()
..color = color.withValues(alpha: 0.30 + 0.40 * pulseStrength)
..maskFilter = MaskFilter.blur(BlurStyle.normal, 8 + 14 * pulseStrength)
..style = PaintingStyle.fill;
canvas.drawPath(path, glow);
}
// Filled triangle, brighter on the up-beat for live mode.
final fillAlpha = mode == ChainDeltaMode.live ? 0.15 + 0.20 * t : 0.18;
final fill = Paint()
..color = color.withValues(alpha: fillAlpha)
..style = PaintingStyle.fill;
canvas.drawPath(path, fill);
// Outline stroke.
final stroke = Paint()
..color = color
..strokeWidth = 2.2
..style = PaintingStyle.stroke
..strokeJoin = StrokeJoin.round;
canvas.drawPath(path, stroke);
// Inner accent dot.
final dotAlpha = mode == ChainDeltaMode.live ? 0.55 + 0.45 * t : 1.0;
final dot = Paint()
..color = color.withValues(alpha: dotAlpha)
..style = PaintingStyle.fill;
canvas.drawCircle(Offset(0, r * 0.18), r * 0.16, dot);
canvas.restore();
}
@override
bool shouldRepaint(covariant _DeltaPainter old) =>
old.t != t || old.mode != mode || old.color != color;
}