import 'dart:math' as math; import 'package:flutter/material.dart'; import '../../utils/Colors.dart'; import 'ScenePainter.dart'; /// A painted landscape that stands in for photography: sky, a low sun, three /// ridges and an oversized figure glyph standing in front of them. The [seed] /// reshapes the ridges and moves the sun, so two routines of the same kind /// never wear the identical picture. class SceneArt extends StatelessWidget { /// sky top, horizon, sun, far ridge, mid ridge, near ridge, ember. final List palette; final int seed; /// The glyph standing in the scene — the kind's icon, usually. final IconData? figure; /// Figure size as a fraction of the shorter side. final double figureScale; final Alignment figureAlignment; /// Darkens the lower half so white type laid over it stays legible. final bool shade; const SceneArt({ super.key, required this.palette, this.seed = 0, this.figure, this.figureScale = 0.5, this.figureAlignment = const Alignment(0.35, 0.15), this.shade = false, }); @override Widget build(BuildContext context) { return LayoutBuilder( builder: (BuildContext context, BoxConstraints constraints) { final double shortest = math.min( constraints.maxWidth.isFinite ? constraints.maxWidth : 200, constraints.maxHeight.isFinite ? constraints.maxHeight : 200, ); final double glyph = shortest * figureScale; return RepaintBoundary( child: Stack( fit: StackFit.expand, children: [ CustomPaint(painter: ScenePainter(palette, seed)), if (figure != null) Align( alignment: figureAlignment, child: SizedBox( width: glyph * 1.6, height: glyph * 1.6, child: Stack( alignment: Alignment.center, children: [ // The ember halo behind the figure — the reference's // orange gi, reduced to light. Container( width: glyph * 1.5, height: glyph * 1.5, decoration: BoxDecoration( shape: BoxShape.circle, gradient: RadialGradient( colors: [ palette[6].withValues(alpha: 0.45), palette[6].withValues(alpha: 0.0), ], ), ), ), Icon( figure, size: glyph, color: colorWhite.withValues(alpha: 0.96), shadows: [ Shadow( color: palette[5].withValues(alpha: 0.55), blurRadius: glyph * 0.22, offset: Offset(0, glyph * 0.08), ), ], ), ], ), ), ), if (shade) DecoratedBox( decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, stops: const [0.35, 1.0], colors: [ colorBlack.withValues(alpha: 0.0), colorBlack.withValues(alpha: 0.55), ], ), ), ), ], ), ); }, ); } }