259 lines
6.4 KiB
Dart
259 lines
6.4 KiB
Dart
import 'dart:math';
|
|
import 'dart:ui';
|
|
import 'dart:ui' as ui;
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
/// Fallback user avatar with a polygon gradient overlayed with text
|
|
class GradientAvatar extends StatefulWidget {
|
|
/// Constructor for [GradientAvatar]
|
|
const GradientAvatar({
|
|
Key? key,
|
|
required this.name,
|
|
required this.userId,
|
|
}) : super(key: key);
|
|
|
|
/// Name of user to shorten and display
|
|
final String name;
|
|
|
|
/// ID of user to be used for key
|
|
final String userId;
|
|
|
|
@override
|
|
_GradientAvatarState createState() => _GradientAvatarState();
|
|
}
|
|
|
|
class _GradientAvatarState extends State<GradientAvatar> {
|
|
@override
|
|
Widget build(BuildContext context) => Center(
|
|
child: RepaintBoundary(
|
|
child: CustomPaint(
|
|
painter: DemoPainter(
|
|
widget.userId,
|
|
getShortenedName(widget.name),
|
|
DefaultTextStyle.of(context).style.fontFamily ?? 'Roboto',
|
|
),
|
|
child: const SizedBox.expand(),
|
|
),
|
|
),
|
|
);
|
|
|
|
String getShortenedName(String name) {
|
|
var parts = name.split(' ')..removeWhere((e) => e == '');
|
|
|
|
if (parts.length > 2) {
|
|
parts = parts.take(2).toList();
|
|
}
|
|
|
|
var result = '';
|
|
|
|
for (var i = 0; i < parts.length; i++) {
|
|
result = result + parts[i][0].toUpperCase();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
}
|
|
|
|
/// Painter for bg polygon gradient
|
|
class DemoPainter extends CustomPainter {
|
|
/// Constructor for [DemoPainter]
|
|
DemoPainter(
|
|
this.userId,
|
|
this.username,
|
|
this.fontFamily,
|
|
);
|
|
|
|
/// Init grid row count
|
|
static const int rowCount = 5;
|
|
|
|
/// Init grid column count
|
|
static const int columnCount = 5;
|
|
|
|
/// User ID used for key
|
|
String userId;
|
|
|
|
/// User name to display
|
|
String username;
|
|
|
|
/// Font family to use
|
|
String fontFamily;
|
|
|
|
@override
|
|
void paint(Canvas canvas, Size size) {
|
|
final rowUnit = size.width / columnCount;
|
|
final columnUnit = size.height / rowCount;
|
|
final rand = Random(userId.length);
|
|
|
|
final squares = <Offset4>[];
|
|
final points = <Offset>{};
|
|
final gradient = colorGradients[rand.nextInt(colorGradients.length)];
|
|
|
|
for (var i = 0; i < rowCount; i++) {
|
|
for (var j = 0; j < columnCount; j++) {
|
|
final off1 = Offset(rowUnit * j, columnUnit * i);
|
|
final off2 = Offset(rowUnit * (j + 1), columnUnit * i);
|
|
final off3 = Offset(rowUnit * (j + 1), columnUnit * (i + 1));
|
|
final off4 = Offset(rowUnit * j, columnUnit * (i + 1));
|
|
|
|
points.addAll([off1, off2, off3, off4]);
|
|
|
|
final pointsList = points.toList();
|
|
|
|
final p1 = pointsList.indexOf(off1);
|
|
final p2 = pointsList.indexOf(off2);
|
|
final p3 = pointsList.indexOf(off3);
|
|
final p4 = pointsList.indexOf(off4);
|
|
|
|
squares.add(
|
|
Offset4(p1, p2, p3, p4, i, j, rowCount, columnCount, gradient));
|
|
}
|
|
}
|
|
|
|
final list = transformPoints(points, size);
|
|
squares.forEach((e) => e.draw(canvas, list));
|
|
|
|
final smallerSide = size.width > size.height ? size.width : size.height;
|
|
|
|
final textSize = smallerSide / 3;
|
|
|
|
final dxShift = (username.length == 2 ? 1.45 : 0.9) * textSize / 2;
|
|
final dyShift = (username.length == 2 ? 1.0 : 1.65) * textSize / 2;
|
|
|
|
final fontSize = username.length == 2 ? textSize : textSize * 1.5;
|
|
|
|
TextPainter(
|
|
text: TextSpan(
|
|
text: username,
|
|
style: TextStyle(
|
|
fontFamily: fontFamily,
|
|
fontSize: fontSize,
|
|
fontWeight: FontWeight.w500,
|
|
color: Colors.white.withOpacity(0.7),
|
|
),
|
|
),
|
|
textAlign: TextAlign.center,
|
|
textDirection: TextDirection.ltr)
|
|
..layout(maxWidth: size.width)
|
|
..paint(
|
|
canvas,
|
|
Offset(
|
|
(size.width / 2) - dxShift,
|
|
(size.height / 2) - dyShift,
|
|
),
|
|
);
|
|
}
|
|
|
|
@override
|
|
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
|
|
|
|
/// Transforms initial grid into a polygon grid
|
|
List<Offset> transformPoints(Set<Offset> points, Size size) {
|
|
final transformedList = <Offset>[];
|
|
final orgList = points.toList();
|
|
final rand = Random(userId.length);
|
|
|
|
for (var i = 0; i < points.length; i++) {
|
|
final orgDx = orgList[i].dx;
|
|
final orgDy = orgList[i].dy;
|
|
|
|
if (orgDx == 0 ||
|
|
orgDy == 0 ||
|
|
orgDx == size.width ||
|
|
orgDy == size.height) {
|
|
transformedList.add(Offset(orgDx, orgDy));
|
|
continue;
|
|
}
|
|
|
|
final sign1 = rand.nextInt(2) == 1 ? 1 : -1;
|
|
final sign2 = rand.nextInt(2) == 1 ? 1 : -1;
|
|
|
|
final dx = 0.6 * sign1 * rand.nextInt(size.width ~/ columnCount);
|
|
final dy = 0.6 * sign2 * rand.nextInt(size.height ~/ rowCount);
|
|
|
|
transformedList.add(Offset(orgDx + dx, orgDy + dy));
|
|
}
|
|
|
|
return transformedList;
|
|
}
|
|
}
|
|
|
|
/// Class for storing and drawing four points of a polygon
|
|
class Offset4 {
|
|
/// Constructor for [Offset4]
|
|
Offset4(
|
|
this.p1,
|
|
this.p2,
|
|
this.p3,
|
|
this.p4,
|
|
this.row,
|
|
this.column,
|
|
this.rowSize,
|
|
this.colSize,
|
|
this.gradient,
|
|
);
|
|
|
|
/// Point 1
|
|
int p1;
|
|
|
|
/// Point 2
|
|
int p2;
|
|
|
|
/// Point 3
|
|
int p3;
|
|
|
|
/// Point 4
|
|
int p4;
|
|
|
|
/// Position of polygon on grid
|
|
int row;
|
|
|
|
/// Position of polygon on grid
|
|
int column;
|
|
|
|
/// Max row size
|
|
int rowSize;
|
|
|
|
/// Max col size
|
|
int colSize;
|
|
|
|
/// Gradient to be applied to polygon
|
|
List<Color> gradient;
|
|
|
|
/// Draw the polygon on canvas
|
|
void draw(Canvas canvas, List<Offset> points) {
|
|
final paint = Paint()
|
|
..color = Color.fromARGB(255, Random().nextInt(255),
|
|
Random().nextInt(255), Random().nextInt(255))
|
|
..shader = ui.Gradient.linear(
|
|
points[p1],
|
|
points[p3],
|
|
gradient,
|
|
);
|
|
|
|
final backgroundPath = Path()
|
|
..moveTo(points[p1].dx, points[p1].dy)
|
|
..lineTo(points[p2].dx, points[p2].dy)
|
|
..lineTo(points[p3].dx, points[p3].dy)
|
|
..lineTo(points[p4].dx, points[p4].dy)
|
|
..lineTo(points[p1].dx, points[p1].dy)
|
|
..close();
|
|
|
|
canvas.drawPath(backgroundPath, paint);
|
|
}
|
|
}
|
|
|
|
/// Gradient list for polygons
|
|
const colorGradients = [
|
|
[Color(0xffffafbd), Color(0xffffc3a0)],
|
|
[Color(0xff2193b0), Color(0xff6dd5ed)],
|
|
[Color(0xffcc2b5e), Color(0xff753a88)],
|
|
[Color(0xffee9ca7), Color(0xffffdde1)],
|
|
[Color(0xff42275a), Color(0xff734b6d)],
|
|
[Color(0xffde6262), Color(0xffffb88c)],
|
|
[Color(0xff56ab2f), Color(0xffa8e063)],
|
|
[Color(0xff614385), Color(0xff516395)],
|
|
[Color(0xffeacda3), Color(0xffd6ae7b)],
|
|
[Color(0xff02aab0), Color(0xff00cdac)],
|
|
];
|