From 1976a3df7de90d88c79d0388d5ccafd4be04400a Mon Sep 17 00:00:00 2001 From: Hugo Pointcheval Date: Thu, 16 Feb 2023 15:13:21 +0100 Subject: [PATCH] feat(ui_kit): add loader implementation --- .../lib/src/components/components.dart | 1 + .../lib/src/components/loader/loader.dart | 145 ++++++++++++++++++ .../lib/src/components/loader/loader.g.dart | 51 ++++++ .../loader/loader_theme_resolver.dart | 53 +++++++ .../wyatt_ui_kit/lib/src/domain/domain.dart | 3 +- .../src/domain/loader_theme_extension.dart | 32 ++++ 6 files changed, 284 insertions(+), 1 deletion(-) create mode 100644 packages/wyatt_ui_kit/lib/src/components/loader/loader.dart create mode 100644 packages/wyatt_ui_kit/lib/src/components/loader/loader.g.dart create mode 100644 packages/wyatt_ui_kit/lib/src/components/loader/loader_theme_resolver.dart create mode 100644 packages/wyatt_ui_kit/lib/src/domain/loader_theme_extension.dart diff --git a/packages/wyatt_ui_kit/lib/src/components/components.dart b/packages/wyatt_ui_kit/lib/src/components/components.dart index b696808e..191af8e8 100644 --- a/packages/wyatt_ui_kit/lib/src/components/components.dart +++ b/packages/wyatt_ui_kit/lib/src/components/components.dart @@ -16,3 +16,4 @@ export './buttons/buttons.dart'; export './cards/cards.dart'; +export './loader/loader.dart'; diff --git a/packages/wyatt_ui_kit/lib/src/components/loader/loader.dart b/packages/wyatt_ui_kit/lib/src/components/loader/loader.dart new file mode 100644 index 00000000..620b5d70 --- /dev/null +++ b/packages/wyatt_ui_kit/lib/src/components/loader/loader.dart @@ -0,0 +1,145 @@ +// Copyright (C) 2023 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +import 'dart:math'; + +import 'package:flutter/material.dart'; +import 'package:flutter_animate/flutter_animate.dart'; +import 'package:wyatt_component_copy_with_extension/component_copy_with_extension.dart'; +import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart'; +import 'package:wyatt_ui_kit/src/components/loader/loader_theme_resolver.dart'; +import 'package:wyatt_ui_kit/wyatt_ui_kit.dart'; + +part 'loader.g.dart'; + +@ComponentCopyWithExtension() +class Loader extends LoaderComponent with $LoaderCWMixin { + const Loader({ + super.colors, + super.radius, + super.stroke, + super.duration, + super.flip, + super.themeResolver, + super.key, + }); + + @override + LoaderThemeResolver? get themeResolver => + super.themeResolver as LoaderThemeResolver?; + + /// Negotiate the theme to get a complete style. + LoaderStyle _resolve(BuildContext context) { + final LoaderThemeResolver resolver = themeResolver ?? + LoaderThemeResolver( + computeExtensionValueFn: ( + context, + defaultValue, + themeExtension, { + extra, + }) => + LoaderStyle( + colors: themeExtension.colors, + stroke: themeExtension.stroke, + ), + customStyleFn: (context, {extra}) => LoaderStyle( + colors: colors, + stroke: stroke, + ), + ); + + return resolver.negotiate(context); + } + + @override + Widget build(BuildContext context) { + final style = _resolve(context); + final dimension = + (radius != null) ? radius! * 2 : context.buttonTheme.height; + + return SizedBox.square( + dimension: dimension, + child: RepaintBoundary( + child: CustomPaint( + painter: _LoaderPainter( + style.colors!, + dimension / 2, + style.stroke!, + flip: flip ?? false, + ), + ) + .animate( + onPlay: (controller) => controller.repeat(), + ) + .rotate( + duration: duration ?? 900.ms, + begin: (flip ?? false) ? 0 : 1, + end: (flip ?? false) ? 1 : 0, + ), + ), + ); + } +} + +class _LoaderPainter extends CustomPainter { + _LoaderPainter( + this.colors, + this.radius, + this.stroke, { + required this.flip, + }); + + final MultiColor colors; + final double radius; + final double stroke; + final bool flip; + + @override + void paint(Canvas canvas, Size size) { + final center = Offset(size.width / 2, size.height / 2); + final circleSurface = Rect.fromCircle(center: center, radius: radius); + + final dotColor = colors.color; + final dotCenter = + Offset(size.width / 2 + (flip ? -radius : radius), size.height / 2); + final gradient = + colors.isGradient ? colors.colors : [colors.color, colors.color]; + + final gradientCirclePainter = Paint() + ..shader = SweepGradient( + colors: (flip ? gradient.reversed : gradient).toList(), + transform: flip ? const GradientRotation(pi) : null, + ).createShader(circleSurface) + ..strokeWidth = stroke + ..style = PaintingStyle.stroke + ..strokeCap = StrokeCap.round; + + final dotPainter = Paint() + ..color = dotColor + ..style = PaintingStyle.fill + ..strokeCap = StrokeCap.round; + + canvas + ..drawCircle(center, radius, gradientCirclePainter) + ..drawCircle(dotCenter, stroke / 2, dotPainter); + } + + @override + bool shouldRepaint(_LoaderPainter oldDelegate) => false; + + @override + bool shouldRebuildSemantics(_LoaderPainter oldDelegate) => false; +} diff --git a/packages/wyatt_ui_kit/lib/src/components/loader/loader.g.dart b/packages/wyatt_ui_kit/lib/src/components/loader/loader.g.dart new file mode 100644 index 00000000..4f1243de --- /dev/null +++ b/packages/wyatt_ui_kit/lib/src/components/loader/loader.g.dart @@ -0,0 +1,51 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'loader.dart'; + +// ************************************************************************** +// ComponentCopyWithGenerator +// ************************************************************************** + +class $LoaderCWProxyImpl implements $LoaderComponentCWProxy { + const $LoaderCWProxyImpl(this._value); + final Loader _value; + @override + Loader colors(MultiColor? colors) => this(colors: colors); + @override + Loader radius(double? radius) => this(radius: radius); + @override + Loader stroke(double? stroke) => this(stroke: stroke); + @override + Loader duration(Duration? duration) => this(duration: duration); + @override + Loader flip(bool? flip) => this(flip: flip); + @override + Loader themeResolver( + ThemeResolver? themeResolver) => + this(themeResolver: themeResolver); + @override + Loader key(Key? key) => this(key: key); + @override + Loader call({ + MultiColor? colors, + double? radius, + double? stroke, + Duration? duration, + bool? flip, + ThemeResolver? themeResolver, + Key? key, + }) => + Loader( + colors: colors ?? _value.colors, + radius: radius ?? _value.radius, + stroke: stroke ?? _value.stroke, + duration: duration ?? _value.duration, + flip: flip ?? _value.flip, + themeResolver: themeResolver ?? _value.themeResolver, + key: key ?? _value.key, + ); +} + +mixin $LoaderCWMixin on Component { + $LoaderComponentCWProxy get copyWith => $LoaderCWProxyImpl(this as Loader); +} diff --git a/packages/wyatt_ui_kit/lib/src/components/loader/loader_theme_resolver.dart b/packages/wyatt_ui_kit/lib/src/components/loader/loader_theme_resolver.dart new file mode 100644 index 00000000..60047759 --- /dev/null +++ b/packages/wyatt_ui_kit/lib/src/components/loader/loader_theme_resolver.dart @@ -0,0 +1,53 @@ +// Copyright (C) 2023 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +import 'package:flutter/material.dart'; +import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart'; +import 'package:wyatt_ui_kit/wyatt_ui_kit.dart'; + +class LoaderThemeResolver + extends ThemeResolver { + const LoaderThemeResolver({ + required this.computeExtensionValueFn, + required this.customStyleFn, + }); + + /// Values taken from + @override + LoaderStyle computeDefaultValue( + BuildContext context, { + void extra, + }) => + LoaderStyle( + colors: MultiColor([ + Theme.of(context).progressIndicatorTheme.color ?? + context.colorScheme.primary, + context.colorScheme.onPrimary, + ]), + stroke: 4, + ); + + @override + final LoaderStyle? Function( + BuildContext context, + LoaderStyle defaultValue, + LoaderThemeExtension themeExtension, { + void extra, + }) computeExtensionValueFn; + + @override + final LoaderStyle? Function(BuildContext context, {void extra}) customStyleFn; +} diff --git a/packages/wyatt_ui_kit/lib/src/domain/domain.dart b/packages/wyatt_ui_kit/lib/src/domain/domain.dart index 901c7de9..8ee38b4c 100644 --- a/packages/wyatt_ui_kit/lib/src/domain/domain.dart +++ b/packages/wyatt_ui_kit/lib/src/domain/domain.dart @@ -14,5 +14,6 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -export 'button_theme_extension/button_theme_extension.dart'; +export './button_theme_extension/button_theme_extension.dart'; +export './loader_theme_extension.dart'; export 'card_theme_extension.dart'; diff --git a/packages/wyatt_ui_kit/lib/src/domain/loader_theme_extension.dart b/packages/wyatt_ui_kit/lib/src/domain/loader_theme_extension.dart new file mode 100644 index 00000000..dc23f0f7 --- /dev/null +++ b/packages/wyatt_ui_kit/lib/src/domain/loader_theme_extension.dart @@ -0,0 +1,32 @@ +// Copyright (C) 2023 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +import 'package:flutter/material.dart'; +import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart'; + +abstract class LoaderThemeExtension + extends ThemeExtension { + const LoaderThemeExtension({ + this.colors, + this.stroke, + }); + + /// Gradient colors from start to end. + final MultiColor? colors; + + /// Loader stroke width + final double? stroke; +}