import 'dart:math' as math; import 'dart:ui' as ui; import 'package:flutter/material.dart'; // 3D Pyramid logo — two faces + base outline + spine class PyramidLogo extends StatelessWidget { final double size; final Color color; const PyramidLogo({super.key, this.size = 36, this.color = Colors.white}); @override Widget build(BuildContext context) => CustomPaint(size: Size(size, size), painter: _PyramidLogoPainter(color: color)); } class _PyramidLogoPainter extends CustomPainter { final Color color; const _PyramidLogoPainter({required this.color}); @override void paint(Canvas canvas, Size size) { final w = size.width; final h = size.height; final sx = w / 48; final sy = h / 48; Offset p(double x, double y) => Offset(x * sx, y * sy); final apex = p(24, 6); final baseL = p(6, 40); final baseR = p(42, 40); final baseM = p(24, 34); // Left face — full opacity → 55% final leftPath = Path()..moveTo(apex.dx, apex.dy)..lineTo(baseL.dx, baseL.dy)..lineTo(baseM.dx, baseM.dy)..close(); canvas.drawPath(leftPath, Paint()..shader = ui.Gradient.linear( Offset(0, apex.dy), Offset(0, baseL.dy), [color.withAlpha(255), color.withAlpha(140)], )); // Right face — 85% → 25% final rightPath = Path()..moveTo(apex.dx, apex.dy)..lineTo(baseR.dx, baseR.dy)..lineTo(baseM.dx, baseM.dy)..close(); canvas.drawPath(rightPath, Paint()..shader = ui.Gradient.linear( Offset(apex.dx, apex.dy), Offset(baseR.dx, baseR.dy), [color.withAlpha(217), color.withAlpha(64)], )); // Base outline canvas.drawPath( Path()..moveTo(baseL.dx, baseL.dy)..lineTo(baseM.dx, baseM.dy)..lineTo(baseR.dx, baseR.dy), Paint()..color = color.withAlpha(102)..style = PaintingStyle.stroke ..strokeWidth = math.max(sx, 0.7)..strokeJoin = StrokeJoin.round, ); // Spine canvas.drawLine(apex, baseM, Paint()..color = color.withAlpha(230) ..strokeWidth = math.max(sx * 0.8, 0.6)); } @override bool shouldRepaint(_PyramidLogoPainter old) => old.color != color; } // Pyramid mark — stylised stacked triangles class PyramidMark extends StatelessWidget { final double size; final Color? color; const PyramidMark({super.key, this.size = 30, this.color}); @override Widget build(BuildContext context) { final c = color ?? Colors.white; return SizedBox( width: size, height: size, child: CustomPaint(painter: _PyramidPainter(c)), ); } } class _PyramidPainter extends CustomPainter { final Color color; _PyramidPainter(this.color); @override void paint(Canvas canvas, Size size) { final paint = Paint()..color = color..style = PaintingStyle.fill; final w = size.width; final h = size.height; // bottom big triangle final big = Path() ..moveTo(w * 0.5, h * 0.1) ..lineTo(w * 0.92, h * 0.88) ..lineTo(w * 0.08, h * 0.88) ..close(); canvas.drawPath(big, paint); // inner cutout (dark) to create layered look final cut = Paint() ..color = Colors.black.withAlpha(80) ..style = PaintingStyle.fill; final inner = Path() ..moveTo(w * 0.5, h * 0.28) ..lineTo(w * 0.74, h * 0.72) ..lineTo(w * 0.26, h * 0.72) ..close(); canvas.drawPath(inner, cut); } @override bool shouldRepaint(_PyramidPainter old) => old.color != color; } // Pyramid space glyph (letter + triangle overlay) class PyramidGlyph extends StatelessWidget { final double size; final Color color; final String label; const PyramidGlyph({ super.key, this.size = 30, required this.color, required this.label, }); @override Widget build(BuildContext context) { return SizedBox( width: size, height: size, child: Stack( alignment: Alignment.center, children: [ CustomPaint( size: Size(size, size), painter: _PyramidPainter(color), ), Text( label.isNotEmpty ? label[0].toUpperCase() : '?', style: TextStyle( color: Colors.white, fontSize: size * 0.38, fontWeight: FontWeight.bold, height: 1, ), ), ], ), ); } } // Presence indicator dot class PresenceDot extends StatelessWidget { final String status; // online, away, busy, offline final double size; final Color borderColor; const PresenceDot({ super.key, required this.status, this.size = 10, this.borderColor = const Color(0xFF111114), }); Color get _color => switch (status) { 'online' => const Color(0xFF4ADE80), 'away' => const Color(0xFFFACC15), 'busy' => const Color(0xFFF87171), _ => const Color(0xFF6F6F7D), }; @override Widget build(BuildContext context) { return Container( width: size, height: size, decoration: BoxDecoration( color: _color, shape: BoxShape.circle, border: Border.all(color: borderColor, width: 2), ), ); } }