import 'dart:io'; import 'dart:math'; import 'package:image/image.dart' as img; /// Generates app icon PNG files for Agenda Tasks /// Run with: cd tool && dart pub get && dart run generate_icon.dart void main() async { print('Generating app icons...'); // Generate main icon (1024x1024) final mainIcon = generateIcon(1024, withBackground: true); final mainPng = img.encodePng(mainIcon); await File('../assets/icon/app_icon.png').writeAsBytes(mainPng); print('Created: assets/icon/app_icon.png (${mainPng.length} bytes)'); // Generate adaptive icon foreground (1024x1024) final foregroundIcon = generateIcon(1024, withBackground: false); final fgPng = img.encodePng(foregroundIcon); await File('../assets/icon/app_icon_foreground.png').writeAsBytes(fgPng); print('Created: assets/icon/app_icon_foreground.png (${fgPng.length} bytes)'); print('Done! Now run from project root: flutter pub run flutter_launcher_icons'); } /// Generate an icon with a checkmark design img.Image generateIcon(int size, {required bool withBackground}) { final image = img.Image(width: size, height: size); final center = size / 2; final radius = size * 0.42; // Colors - Material Purple final purple = img.ColorRgba8(103, 80, 164, 255); // #6750A4 final white = img.ColorRgba8(255, 255, 255, 255); final transparent = img.ColorRgba8(0, 0, 0, 0); // Checkmark stroke width final checkStroke = size * 0.09; // Checkmark points - classic check shape // Point 1: Start of short leg (left side) final p1x = center - radius * 0.40; final p1y = center + radius * 0.05; // Point 2: Corner/bottom of check final p2x = center - radius * 0.05; final p2y = center + radius * 0.40; // Point 3: End of long leg (top right) final p3x = center + radius * 0.50; final p3y = center - radius * 0.35; // Fill image for (int y = 0; y < size; y++) { for (int x = 0; x < size; x++) { final dx = x - center; final dy = y - center; final distance = sqrt(dx * dx + dy * dy); img.Color pixelColor = transparent; if (withBackground) { // Draw filled purple circle if (distance <= radius) { pixelColor = purple; } // Draw white checkmark on top final dist1 = distanceToSegment(x.toDouble(), y.toDouble(), p1x, p1y, p2x, p2y); final dist2 = distanceToSegment(x.toDouble(), y.toDouble(), p2x, p2y, p3x, p3y); if (dist1 <= checkStroke || dist2 <= checkStroke) { pixelColor = white; } } else { // Foreground only - purple circle outline and checkmark final ringOuter = radius; final ringInner = radius * 0.88; // Circle outline if (distance <= ringOuter && distance >= ringInner) { pixelColor = purple; } // Purple checkmark final dist1 = distanceToSegment(x.toDouble(), y.toDouble(), p1x, p1y, p2x, p2y); final dist2 = distanceToSegment(x.toDouble(), y.toDouble(), p2x, p2y, p3x, p3y); if (dist1 <= checkStroke || dist2 <= checkStroke) { pixelColor = purple; } } image.setPixel(x, y, pixelColor); } } return image; } /// Calculate distance from point (px, py) to line segment (x1,y1)-(x2,y2) double distanceToSegment(double px, double py, double x1, double y1, double x2, double y2) { final dx = x2 - x1; final dy = y2 - y1; final lengthSq = dx * dx + dy * dy; if (lengthSq == 0) { return sqrt((px - x1) * (px - x1) + (py - y1) * (py - y1)); } var t = ((px - x1) * dx + (py - y1) * dy) / lengthSq; t = t.clamp(0.0, 1.0); final nearestX = x1 + t * dx; final nearestY = y1 + t * dy; return sqrt((px - nearestX) * (px - nearestX) + (py - nearestY) * (py - nearestY)); }