diff --git a/docs/store/feature_graphic.png b/docs/store/feature_graphic.png new file mode 100644 index 0000000..f769c84 Binary files /dev/null and b/docs/store/feature_graphic.png differ diff --git a/lib/ui/branding/feature_graphic_painter.dart b/lib/ui/branding/feature_graphic_painter.dart new file mode 100644 index 0000000..630d33f --- /dev/null +++ b/lib/ui/branding/feature_graphic_painter.dart @@ -0,0 +1,36 @@ +// lib/ui/branding/feature_graphic_painter.dart +import 'package:flutter/material.dart'; + +import 'app_icon_painter.dart'; + +/// Paints the Play feature graphic (1024×500): navy field, the brand blocks on +/// the left, wordmark + tagline on the right. +class FeatureGraphic { + static void paint(Canvas canvas, Size size) { + final rect = Offset.zero & size; + AppIconMark.paintBackground(canvas, rect); + + // Blocks on the left, vertically centered. + canvas.save(); + final blockArea = size.height * 0.74; + canvas.translate(size.height * 0.16, (size.height - blockArea) / 2); + AppIconMark.paintBlocks(canvas, blockArea, groupFraction: 0.92); + canvas.restore(); + + void text(String s, double dy, double fontSize, FontWeight w, Color c) { + final tp = TextPainter( + text: TextSpan( + text: s, + style: TextStyle( + color: c, fontSize: fontSize, fontWeight: w, letterSpacing: 0.5), + ), + textDirection: TextDirection.ltr, + )..layout(); + tp.paint(canvas, Offset(size.height * 1.02, dy)); + } + + text('Block Seasons', size.height * 0.34, 76, FontWeight.w900, Colors.white); + text('A new season of blocks every few weeks.', size.height * 0.50, 30, + FontWeight.w500, const Color(0xFFB9C4E6)); + } +} diff --git a/test/tool/generate_brand_assets_test.dart b/test/tool/generate_brand_assets_test.dart index 4ef9a89..45d7fba 100644 --- a/test/tool/generate_brand_assets_test.dart +++ b/test/tool/generate_brand_assets_test.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'dart:ui'; import 'package:block_seasons/ui/branding/app_icon_painter.dart'; +import 'package:block_seasons/ui/branding/feature_graphic_painter.dart'; import 'package:flutter_test/flutter_test.dart'; Future _writePng(String path, int size, void Function(Canvas) draw) async { @@ -41,4 +42,20 @@ void main() { expect(File('assets/icon/$f').existsSync(), isTrue, reason: f); } }); + + testWidgets('generate feature graphic', (tester) async { + await tester.runAsync(() async { + const w = 1024, h = 500; + final recorder = PictureRecorder(); + final canvas = Canvas(recorder); + FeatureGraphic.paint(canvas, const Size(1024, 500)); + final picture = recorder.endRecording(); + final image = await picture.toImage(w, h); + final bytes = await image.toByteData(format: ImageByteFormat.png); + File('docs/store/feature_graphic.png').parent.createSync(recursive: true); + File('docs/store/feature_graphic.png') + .writeAsBytesSync(bytes!.buffer.asUint8List()); + }); + expect(File('docs/store/feature_graphic.png').existsSync(), isTrue); + }); }