This commit is contained in:
2025-02-12 14:20:11 +02:00
parent 7d3920bb95
commit 2f77d5d813
28 changed files with 448 additions and 420 deletions

View File

@@ -2,9 +2,49 @@ include: package:lints/recommended.yaml
linter: linter:
rules: rules:
# ==== Project Organization Rules ====
# Enforces relative imports to maintain project structure and avoid unnecessary long paths
- prefer_relative_imports - prefer_relative_imports
- close_sinks
- avoid_empty_else # Ensures that files are named in lowercase_with_underscores format
- file_names - file_names
# ==== Best Practices ====
# Enforces the closing of streams and sinks to avoid memory leaks
- close_sinks
# Avoids empty 'else' blocks to reduce confusion and improve code readability
- avoid_empty_else
# Prefer using 'const' constructors wherever possible for better performance and immutability
- prefer_const_constructors - prefer_const_constructors
# Avoid leading underscores for local variable names to prevent conflicts and improve clarity
- no_leading_underscores_for_local_identifiers - no_leading_underscores_for_local_identifiers
# ==== Code Consistency ====
# Avoids the use of 'print' statements in production code, encouraging proper logging instead
- avoid_print
# Encourages using 'final' for fields that are not reassigned to promote immutability
- prefer_final_fields
# Ensures that all types are explicitly specified for better readability and type safety
- always_specify_types
# Ensures constructors are at the top of the class for better readability and consistency
- sort_constructors_first
# Avoids redundant default argument values to keep the code clean
- avoid_redundant_argument_values
# Enforces consistency by preferring single quotes over double quotes for string literals
- prefer_single_quotes
# ==== Documentation Rules ====
# Enforces documentation for all public classes, methods, and fields to improve API clarity
# - public_member_api_docs
# ==== Null Safety ====
# Avoids unnecessary null checks and encourages the use of null-aware operators
- unnecessary_null_checks

View File

@@ -48,8 +48,8 @@ class GradientBoxBorder extends Border {
} }
void _paintCircle(Canvas canvas, Rect rect) { void _paintCircle(Canvas canvas, Rect rect) {
final paint = _getPaint(rect); final Paint paint = _getPaint(rect);
final radius = (rect.shortestSide - width) / 2.0; final double radius = (rect.shortestSide - width) / 2.0;
canvas.drawCircle(rect.center, radius, paint); canvas.drawCircle(rect.center, radius, paint);
} }

View File

@@ -55,17 +55,17 @@ class GradientOutlineInputBorder extends InputBorder {
double gapPercentage = 0.0, double gapPercentage = 0.0,
TextDirection? textDirection, TextDirection? textDirection,
}) { }) {
final paint = _getPaint(rect); final Paint paint = _getPaint(rect);
final outer = borderRadius.toRRect(rect); final RRect outer = borderRadius.toRRect(rect);
final center = outer.deflate(borderSide.width / 2.0); final RRect center = outer.deflate(borderSide.width / 2.0);
if (gapStart == null || gapExtent <= 0.0 || gapPercentage == 0.0) { if (gapStart == null || gapExtent <= 0.0 || gapPercentage == 0.0) {
canvas.drawRRect(center, paint); canvas.drawRRect(center, paint);
} else { } else {
final extent = final double extent =
lerpDouble(0.0, gapExtent + gapPadding * 2.0, gapPercentage)!; lerpDouble(0.0, gapExtent + gapPadding * 2.0, gapPercentage)!;
switch (textDirection!) { switch (textDirection!) {
case TextDirection.rtl: case TextDirection.rtl:
final path = _gapBorderPath( final Path path = _gapBorderPath(
canvas, canvas,
center, center,
math.max(0, gapStart + gapPadding - extent), math.max(0, gapStart + gapPadding - extent),
@@ -75,7 +75,7 @@ class GradientOutlineInputBorder extends InputBorder {
break; break;
case TextDirection.ltr: case TextDirection.ltr:
final path = _gapBorderPath( final Path path = _gapBorderPath(
canvas, canvas,
center, center,
math.max(0, gapStart - gapPadding), math.max(0, gapStart - gapPadding),
@@ -112,39 +112,39 @@ class GradientOutlineInputBorder extends InputBorder {
// When the corner radii on any side add up to be greater than the // When the corner radii on any side add up to be greater than the
// given height, each radius has to be scaled to not exceed the // given height, each radius has to be scaled to not exceed the
// size of the width/height of the RRect. // size of the width/height of the RRect.
final scaledRRect = center.scaleRadii(); final RRect scaledRRect = center.scaleRadii();
final tlCorner = Rect.fromLTWH( final Rect tlCorner = Rect.fromLTWH(
scaledRRect.left, scaledRRect.left,
scaledRRect.top, scaledRRect.top,
scaledRRect.tlRadiusX * 2.0, scaledRRect.tlRadiusX * 2.0,
scaledRRect.tlRadiusY * 2.0, scaledRRect.tlRadiusY * 2.0,
); );
final trCorner = Rect.fromLTWH( final Rect trCorner = Rect.fromLTWH(
scaledRRect.right - scaledRRect.trRadiusX * 2.0, scaledRRect.right - scaledRRect.trRadiusX * 2.0,
scaledRRect.top, scaledRRect.top,
scaledRRect.trRadiusX * 2.0, scaledRRect.trRadiusX * 2.0,
scaledRRect.trRadiusY * 2.0, scaledRRect.trRadiusY * 2.0,
); );
final brCorner = Rect.fromLTWH( final Rect brCorner = Rect.fromLTWH(
scaledRRect.right - scaledRRect.brRadiusX * 2.0, scaledRRect.right - scaledRRect.brRadiusX * 2.0,
scaledRRect.bottom - scaledRRect.brRadiusY * 2.0, scaledRRect.bottom - scaledRRect.brRadiusY * 2.0,
scaledRRect.brRadiusX * 2.0, scaledRRect.brRadiusX * 2.0,
scaledRRect.brRadiusY * 2.0, scaledRRect.brRadiusY * 2.0,
); );
final blCorner = Rect.fromLTWH( final Rect blCorner = Rect.fromLTWH(
scaledRRect.left, scaledRRect.left,
scaledRRect.bottom - scaledRRect.blRadiusY * 2.0, scaledRRect.bottom - scaledRRect.blRadiusY * 2.0,
scaledRRect.blRadiusX * 2.0, scaledRRect.blRadiusX * 2.0,
scaledRRect.blRadiusX * 2.0, scaledRRect.blRadiusX * 2.0,
); );
const cornerArcSweep = math.pi / 2.0; const double cornerArcSweep = math.pi / 2.0;
final tlCornerArcSweep = start < scaledRRect.tlRadiusX final double tlCornerArcSweep = start < scaledRRect.tlRadiusX
? math.asin((start / scaledRRect.tlRadiusX).clamp(-1.0, 1.0)) ? math.asin((start / scaledRRect.tlRadiusX).clamp(-1.0, 1.0))
: math.pi / 2.0; : math.pi / 2.0;
final path = Path() final Path path = Path()
..addArc(tlCorner, math.pi, tlCornerArcSweep) ..addArc(tlCorner, math.pi, tlCornerArcSweep)
..moveTo(scaledRRect.left + scaledRRect.tlRadiusX, scaledRRect.top); ..moveTo(scaledRRect.left + scaledRRect.tlRadiusX, scaledRRect.top);
@@ -152,16 +152,16 @@ class GradientOutlineInputBorder extends InputBorder {
path.lineTo(scaledRRect.left + start, scaledRRect.top); path.lineTo(scaledRRect.left + start, scaledRRect.top);
} }
const trCornerArcStart = (3 * math.pi) / 2.0; const double trCornerArcStart = (3 * math.pi) / 2.0;
const trCornerArcSweep = cornerArcSweep; const double trCornerArcSweep = cornerArcSweep;
if (start + extent < scaledRRect.width - scaledRRect.trRadiusX) { if (start + extent < scaledRRect.width - scaledRRect.trRadiusX) {
path path
..relativeMoveTo(extent, 0) ..relativeMoveTo(extent, 0)
..lineTo(scaledRRect.right - scaledRRect.trRadiusX, scaledRRect.top) ..lineTo(scaledRRect.right - scaledRRect.trRadiusX, scaledRRect.top)
..addArc(trCorner, trCornerArcStart, trCornerArcSweep); ..addArc(trCorner, trCornerArcStart, trCornerArcSweep);
} else if (start + extent < scaledRRect.width) { } else if (start + extent < scaledRRect.width) {
final dx = scaledRRect.width - (start + extent); final double dx = scaledRRect.width - (start + extent);
final sweep = math.acos(dx / scaledRRect.trRadiusX); final double sweep = math.acos(dx / scaledRRect.trRadiusX);
path.addArc(trCorner, trCornerArcStart + sweep, trCornerArcSweep - sweep); path.addArc(trCorner, trCornerArcStart + sweep, trCornerArcSweep - sweep);
} }

View File

@@ -1,6 +1,3 @@
import 'dart:math' as math;
import 'dart:ui';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class GradientUnderlineInputBorder extends InputBorder { class GradientUnderlineInputBorder extends InputBorder {
@@ -52,7 +49,7 @@ class GradientUnderlineInputBorder extends InputBorder {
double gapPercentage = 0.0, double gapPercentage = 0.0,
TextDirection? textDirection, TextDirection? textDirection,
}) { }) {
final paint = _getPaint(rect); final Paint paint = _getPaint(rect);
Rect underlineRect = Rect.fromLTWH(rect.left, rect.height - width, rect.width, width); Rect underlineRect = Rect.fromLTWH(rect.left, rect.height - width, rect.width, width);
canvas.drawRect(underlineRect, paint); canvas.drawRect(underlineRect, paint);
} }

View File

@@ -79,7 +79,7 @@ class AstromicButtons {
onTap: onTap, onTap: onTap,
onHold: onHold, onHold: onHold,
configuration: configuration, configuration: configuration,
isUnderlined: isUnderlined ?? (e) => e, isUnderlined: isUnderlined ?? (bool e) => e,
contentPadding: contentPadding, contentPadding: contentPadding,
style: style, style: style,
text: text, text: text,

View File

@@ -12,16 +12,6 @@ import 'models/models.exports.dart';
//s1 Exports //s1 Exports
class AstromicButtonBase extends StatefulWidget { class AstromicButtonBase extends StatefulWidget {
//SECTION - Widget Arguments
//s1 -- Functionality
final VoidCallback? onTap;
final VoidCallback? onHold;
//s1 -- Configurations
final AstromicButtonConfiguration? configuration;
//s1 -- Style
final AstromicButtonStyle Function(bool isEnabled, bool isHighlighted)? style;
//s1 -- Content
final Widget Function(bool isEnabled, bool isHighlighted) child;
//!SECTION //!SECTION
// //
const AstromicButtonBase({ const AstromicButtonBase({
@@ -38,6 +28,16 @@ class AstromicButtonBase extends StatefulWidget {
}) : super( }) : super(
key: key, key: key,
); );
//SECTION - Widget Arguments
//s1 -- Functionality
final VoidCallback? onTap;
final VoidCallback? onHold;
//s1 -- Configurations
final AstromicButtonConfiguration? configuration;
//s1 -- Style
final AstromicButtonStyle Function(bool isEnabled, bool isHighlighted)? style;
//s1 -- Content
final Widget Function(bool isEnabled, bool isHighlighted) child;
@override @override
State<AstromicButtonBase> createState() => _AstromicButtonBaseState(); State<AstromicButtonBase> createState() => _AstromicButtonBaseState();
@@ -121,7 +121,7 @@ class _AstromicButtonBaseState extends State<AstromicButtonBase> {
onTap: _config.isEnabled && widget.onTap != null ? widget.onTap : null, onTap: _config.isEnabled && widget.onTap != null ? widget.onTap : null,
onLongPress: _config.isEnabled && widget.onHold != null ? widget.onHold : null, onLongPress: _config.isEnabled && widget.onHold != null ? widget.onHold : null,
onHighlightChanged: _config.withHighlightChange onHighlightChanged: _config.withHighlightChange
? (v) { ? (bool v) {
setState(() { setState(() {
_isHighlighted = v; _isHighlighted = v;
}); });

View File

@@ -12,18 +12,6 @@ import 'models/models.exports.dart';
//s1 Exports //s1 Exports
class AstromicIconButton extends StatefulWidget { class AstromicIconButton extends StatefulWidget {
//SECTION - Widget Arguments
//s1 -- Functionality
final void Function(VoidCallback start, VoidCallback stop)? onTap;
final Function(VoidCallback start, VoidCallback stop)? onHold;
//s1 -- Configurations
final AstromicButtonConfiguration? configuration;
//s1 -- Style
final bool isCircular;
final AstromicButtonStyle Function(bool isEnabled, bool isHighlighted, bool isLoading)? style;
//s1 -- Content
final Widget? loadingContent;
final Widget Function(bool isEnabled, bool isHighlighted) icon;
//!SECTION //!SECTION
// //
const AstromicIconButton({ const AstromicIconButton({
@@ -40,6 +28,18 @@ class AstromicIconButton extends StatefulWidget {
this.loadingContent, this.loadingContent,
required this.icon, required this.icon,
}); });
//SECTION - Widget Arguments
//s1 -- Functionality
final void Function(VoidCallback start, VoidCallback stop)? onTap;
final Function(VoidCallback start, VoidCallback stop)? onHold;
//s1 -- Configurations
final AstromicButtonConfiguration? configuration;
//s1 -- Style
final bool isCircular;
final AstromicButtonStyle Function(bool isEnabled, bool isHighlighted, bool isLoading)? style;
//s1 -- Content
final Widget? loadingContent;
final Widget Function(bool isEnabled, bool isHighlighted) icon;
@override @override
State<AstromicIconButton> createState() => _AstromicIconButtonState(); State<AstromicIconButton> createState() => _AstromicIconButtonState();
@@ -117,10 +117,10 @@ class _AstromicIconButtonState extends State<AstromicIconButton> {
: null, : null,
style: widget.style == null style: widget.style == null
? null ? null
: (enabled, highlighted) => widget.style!.call(enabled, highlighted, isLoading).copyWith( : (bool enabled, bool highlighted) => widget.style!.call(enabled, highlighted, isLoading).copyWith(
borderRadius: widget.isCircular ? BorderRadiusDirectional.circular(100000000000) : null, borderRadius: widget.isCircular ? BorderRadiusDirectional.circular(100000000000) : null,
), ),
child: (enabled, highlighted) => isLoading && widget.loadingContent != null ? widget.loadingContent! : widget.icon(enabled, highlighted), child: (bool enabled, bool highlighted) => isLoading && widget.loadingContent != null ? widget.loadingContent! : widget.icon(enabled, highlighted),
); );
//s1 -Widgets //s1 -Widgets

View File

@@ -12,22 +12,6 @@ import 'models/models.exports.dart';
//s1 Exports //s1 Exports
class AstromicLinkButton extends StatelessWidget { class AstromicLinkButton extends StatelessWidget {
//SECTION - Widget Arguments
//s1 -- Functionality
final VoidCallback? onTap;
final VoidCallback? onHold;
//s1 -- Configurations
final AstromicButtonConfiguration? configuration;
//s1 -- Style
final bool Function(bool isEnabled) isUnderlined;
final EdgeInsetsGeometry? contentPadding;
final TextStyle Function(bool isEnabled)? style;
//
//s1 -- Content
final String? text;
final Widget? textWidget;
final Widget? prefix;
final Widget? suffix;
//!SECTION //!SECTION
// //
const AstromicLinkButton({ const AstromicLinkButton({
@@ -50,6 +34,22 @@ class AstromicLinkButton extends StatelessWidget {
super( super(
key: key, key: key,
); );
//SECTION - Widget Arguments
//s1 -- Functionality
final VoidCallback? onTap;
final VoidCallback? onHold;
//s1 -- Configurations
final AstromicButtonConfiguration? configuration;
//s1 -- Style
final bool Function(bool isEnabled) isUnderlined;
final EdgeInsetsGeometry? contentPadding;
final TextStyle Function(bool isEnabled)? style;
//
//s1 -- Content
final String? text;
final Widget? textWidget;
final Widget? prefix;
final Widget? suffix;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -64,27 +64,24 @@ class AstromicLinkButton extends StatelessWidget {
//SECTION - Build Return //SECTION - Build Return
return Row( return Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
textDirection: configuration?.textDirection, textDirection: configuration?.textDirection,
children: [ children: <Widget>[
AstromicButtonBase( AstromicButtonBase(
onTap: onTap, onTap: onTap,
onHold: onHold, onHold: onHold,
// //
configuration: configuration, configuration: configuration,
// //
style: (isEnabled, isHighlighted) => AstromicButtonStyle( style: (bool isEnabled, bool isHighlighted) => AstromicButtonStyle(
contentPadding: contentPadding, contentPadding: contentPadding,
borderWidth: 0, borderWidth: 0,
borderRadius: BorderRadius.zero, borderRadius: BorderRadius.zero,
borderColor: Colors.transparent, borderColor: Colors.transparent,
), ),
// //
child: (isEnabled, isHighlighted) => Row( child: (bool isEnabled, bool isHighlighted) => Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[
children: [
if (prefix != null) prefix!, if (prefix != null) prefix!,
textWidget != null textWidget != null
? textWidget! ? textWidget!

View File

@@ -2,23 +2,6 @@ import 'package:flutter/material.dart';
/// Styling model for the button element. /// Styling model for the button element.
class AstromicButtonStyle { class AstromicButtonStyle {
//s1 -- Colors
final Color? backgroundColor;
final Gradient? backgroundGradient;
final Color? hoverColor;
final Color? splashColor;
final Color? highlightColor;
final Color? borderColor;
final Gradient? borderGradient;
//
//s1 -- Spacing & Insets
final double? fixedHeight;
final double? fixedWidth;
final EdgeInsetsGeometry? contentPadding;
final BorderRadiusGeometry? borderRadius;
final double? borderWidth;
//s1 -- Interactions
final InteractiveInkFeatureFactory? splashFactory;
const AstromicButtonStyle({ const AstromicButtonStyle({
this.backgroundColor = Colors.transparent, this.backgroundColor = Colors.transparent,
this.backgroundGradient, this.backgroundGradient,
@@ -37,6 +20,23 @@ class AstromicButtonStyle {
this.splashFactory, this.splashFactory,
// //
}); });
//s1 -- Colors
final Color? backgroundColor;
final Gradient? backgroundGradient;
final Color? hoverColor;
final Color? splashColor;
final Color? highlightColor;
final Color? borderColor;
final Gradient? borderGradient;
//
//s1 -- Spacing & Insets
final double? fixedHeight;
final double? fixedWidth;
final EdgeInsetsGeometry? contentPadding;
final BorderRadiusGeometry? borderRadius;
final double? borderWidth;
//s1 -- Interactions
final InteractiveInkFeatureFactory? splashFactory;
AstromicButtonStyle copyWith({ AstromicButtonStyle copyWith({
Color? backgroundColor, Color? backgroundColor,

View File

@@ -13,20 +13,6 @@ import 'models/models.exports.dart';
//s1 Exports //s1 Exports
class AstromicStateButton extends StatefulWidget { class AstromicStateButton extends StatefulWidget {
//SECTION - Widget Arguments
//s1 -- Functionality
final void Function(VoidCallback start, VoidCallback stop)? onTap;
final Function(VoidCallback start, VoidCallback stop)? onHold;
//s1 -- Configurations
final AstromicButtonConfiguration? configuration;
//s1 -- Style
final AstromicSizingStrategy? widthSizingStrategy;
final AstromicSizingStrategy? heightSizingStrategy;
final AstromicButtonStyle Function(bool isEnabled, bool isHighlighted, bool isLoading)? style;
//s1 -- Content
final Widget? loadingContent;
final Widget Function(bool isEnabled, bool isHighlighted) content;
//!SECTION //!SECTION
// //
const AstromicStateButton({ const AstromicStateButton({
@@ -44,6 +30,20 @@ class AstromicStateButton extends StatefulWidget {
this.loadingContent, this.loadingContent,
required this.content, required this.content,
}) : assert(heightSizingStrategy != AstromicSizingStrategy.fill, 'Height strategy cannot be fill'); }) : assert(heightSizingStrategy != AstromicSizingStrategy.fill, 'Height strategy cannot be fill');
//SECTION - Widget Arguments
//s1 -- Functionality
final void Function(VoidCallback start, VoidCallback stop)? onTap;
final Function(VoidCallback start, VoidCallback stop)? onHold;
//s1 -- Configurations
final AstromicButtonConfiguration? configuration;
//s1 -- Style
final AstromicSizingStrategy? widthSizingStrategy;
final AstromicSizingStrategy? heightSizingStrategy;
final AstromicButtonStyle Function(bool isEnabled, bool isHighlighted, bool isLoading)? style;
//s1 -- Content
final Widget? loadingContent;
final Widget Function(bool isEnabled, bool isHighlighted) content;
@override @override
State<AstromicStateButton> createState() => _AstromicStateButtonState(); State<AstromicStateButton> createState() => _AstromicStateButtonState();
@@ -119,22 +119,20 @@ class _AstromicStateButtonState extends State<AstromicStateButton> {
}); });
} }
: null, : null,
style: (enabled, highlighted) => widget.style!(enabled, highlighted, isLoading).copyWith( style: (bool enabled, bool highlighted) => widget.style!(enabled, highlighted, isLoading).copyWith(
contentPadding: widget.heightSizingStrategy == AstromicSizingStrategy.fixed && widget.widthSizingStrategy == AstromicSizingStrategy.fixed contentPadding: widget.heightSizingStrategy == AstromicSizingStrategy.fixed && widget.widthSizingStrategy == AstromicSizingStrategy.fixed
? EdgeInsets.zero ? EdgeInsets.zero
: widget.heightSizingStrategy == AstromicSizingStrategy.fixed && widget.widthSizingStrategy != AstromicSizingStrategy.fixed : widget.heightSizingStrategy == AstromicSizingStrategy.fixed && widget.widthSizingStrategy != AstromicSizingStrategy.fixed
? EdgeInsets.symmetric( ? EdgeInsets.symmetric(
horizontal: widget.style!(enabled, highlighted, isLoading).contentPadding?.horizontal ?? 0, horizontal: widget.style!(enabled, highlighted, isLoading).contentPadding?.horizontal ?? 0,
vertical: 0,
) )
: widget.widthSizingStrategy == AstromicSizingStrategy.fixed && widget.heightSizingStrategy != AstromicSizingStrategy.fixed : widget.widthSizingStrategy == AstromicSizingStrategy.fixed && widget.heightSizingStrategy != AstromicSizingStrategy.fixed
? EdgeInsets.symmetric( ? EdgeInsets.symmetric(
vertical: widget.style!(enabled, highlighted, isLoading).contentPadding?.vertical ?? 0, vertical: widget.style!(enabled, highlighted, isLoading).contentPadding?.vertical ?? 0,
horizontal: 0,
) )
: null, : null,
), ),
child: (enabled, highlighted) => isLoading && widget.loadingContent != null ? widget.loadingContent! : widget.content(enabled, highlighted), child: (bool enabled, bool highlighted) => isLoading && widget.loadingContent != null ? widget.loadingContent! : widget.content(enabled, highlighted),
); );
//s1 -Widgets //s1 -Widgets
@@ -143,7 +141,7 @@ class _AstromicStateButtonState extends State<AstromicStateButton> {
//SECTION - Build Return //SECTION - Build Return
return Row( return Row(
mainAxisSize: widget.widthSizingStrategy == AstromicSizingStrategy.hug ? MainAxisSize.min : MainAxisSize.max, mainAxisSize: widget.widthSizingStrategy == AstromicSizingStrategy.hug ? MainAxisSize.min : MainAxisSize.max,
children: [ children: <Widget>[
widget.widthSizingStrategy == AstromicSizingStrategy.fill widget.widthSizingStrategy == AstromicSizingStrategy.fill
? Expanded( ? Expanded(
child: SizedBox( child: SizedBox(

View File

@@ -30,7 +30,7 @@ class AstromicFields {
Iterable<ContextMenuButtonItem>? contextButtons, Iterable<ContextMenuButtonItem>? contextButtons,
}) => }) =>
Column( Column(
children: [ children: <Widget>[
AstromicTextField( AstromicTextField(
textController: controller, textController: controller,
stateKey: stateKey, stateKey: stateKey,
@@ -64,8 +64,8 @@ class AstromicFields {
Widget? Function(bool isEnabled, VoidCallback stateSetter)? suffixWidget, Widget? Function(bool isEnabled, VoidCallback stateSetter)? suffixWidget,
Widget? Function(bool isEnabled)? messageBuilder}) => Widget? Function(bool isEnabled)? messageBuilder}) =>
Column( Column(
children: [ children: <Widget>[
AstromicActionField( AstromicActionField<T>(
stateKey: stateKey, stateKey: stateKey,
textController: controller, textController: controller,
initialValue: initialValue, initialValue: initialValue,

View File

@@ -12,6 +12,26 @@ import 'models/models.exports.dart';
//s1 Exports //s1 Exports
class AstromicActionField<T> extends StatefulWidget { class AstromicActionField<T> extends StatefulWidget {
//!SECTION
//
const AstromicActionField({
super.key,
//
this.initialValue,
this.stateKey,
required this.textController,
required this.onValueChangedMapper,
this.onTap,
this.onHold,
//
this.configuration,
this.style,
//
this.hint,
this.prefixWidget,
this.suffixWidget,
this.messageBuilder,
});
//SECTION - Widget Arguments //SECTION - Widget Arguments
//s1 -- Functionality //s1 -- Functionality
final Key? stateKey; final Key? stateKey;
@@ -33,26 +53,6 @@ class AstromicActionField<T> extends StatefulWidget {
final Widget? Function(bool isEnabled, VoidCallback stateSetter)? prefixWidget; final Widget? Function(bool isEnabled, VoidCallback stateSetter)? prefixWidget;
final Widget? Function(bool isEnabled, VoidCallback stateSetter)? suffixWidget; final Widget? Function(bool isEnabled, VoidCallback stateSetter)? suffixWidget;
final Widget? Function(bool isEnabled)? messageBuilder; final Widget? Function(bool isEnabled)? messageBuilder;
//!SECTION
//
const AstromicActionField({
super.key,
//
this.initialValue,
this.stateKey,
required this.textController,
required this.onValueChangedMapper,
this.onTap,
this.onHold,
//
this.configuration,
this.style,
//
this.hint,
this.prefixWidget,
this.suffixWidget,
this.messageBuilder,
});
@override @override
State<AstromicActionField<T>> createState() => _AstromicActionFieldState<T>(); State<AstromicActionField<T>> createState() => _AstromicActionFieldState<T>();
@@ -136,12 +136,12 @@ class _AstromicActionFieldState<T> extends State<AstromicActionField<T>> {
// onChanged: (v) {}, // onChanged: (v) {},
// onSubmited: (v) {}, // onSubmited: (v) {},
configuration: widget.configuration, configuration: widget.configuration,
style: widget.style == null ? null : (enabled, focused) => widget.style!(enabled), style: widget.style == null ? null : (bool enabled, bool focused) => widget.style!(enabled),
hint: widget.hint, hint: widget.hint,
prefixWidget: widget.prefixWidget == null ? null : (enabled, focused, stateSetter) => widget.prefixWidget!(enabled, stateSetter), prefixWidget: widget.prefixWidget == null ? null : (bool enabled, bool focused, void Function() stateSetter) => widget.prefixWidget!(enabled, stateSetter),
suffixWidget: widget.suffixWidget == null ? null : (enabled, focused, stateSetter) => widget.suffixWidget!(enabled, stateSetter), suffixWidget: widget.suffixWidget == null ? null : (bool enabled, bool focused, void Function() stateSetter) => widget.suffixWidget!(enabled, stateSetter),
messageBuilder: widget.messageBuilder == null ? null : (enabled, focused) => widget.messageBuilder!(enabled), messageBuilder: widget.messageBuilder == null ? null : (bool enabled, bool focused) => widget.messageBuilder!(enabled),
fieldStackedWidget: (finalHeight, border) => SizedBox( fieldStackedWidget: (double finalHeight, ShapeBorder? border) => SizedBox(
width: double.infinity, width: double.infinity,
height: finalHeight, height: finalHeight,
child: Material( child: Material(

View File

@@ -17,6 +17,27 @@ import 'models/models.exports.dart';
//s1 Exports //s1 Exports
class AstromicFieldBase extends StatefulWidget { class AstromicFieldBase extends StatefulWidget {
//!SECTION
//
const AstromicFieldBase({
super.key,
//
required this.textController,
this.stateKey,
this.onChanged,
this.onSubmited,
//
this.configuration,
//
this.style,
//
this.fieldStackedWidget,
this.hint,
this.prefixWidget,
this.suffixWidget,
this.messageBuilder,
this.contextButtons,
});
//SECTION - Widget Arguments //SECTION - Widget Arguments
//s1 -- Functionality //s1 -- Functionality
final TextEditingController textController; final TextEditingController textController;
@@ -40,27 +61,6 @@ class AstromicFieldBase extends StatefulWidget {
final Widget? Function(bool isEnabled, bool isFocused)? messageBuilder; final Widget? Function(bool isEnabled, bool isFocused)? messageBuilder;
// //
final Iterable<ContextMenuButtonItem>? contextButtons; final Iterable<ContextMenuButtonItem>? contextButtons;
//!SECTION
//
const AstromicFieldBase({
super.key,
//
required this.textController,
this.stateKey,
this.onChanged,
this.onSubmited,
//
this.configuration,
//
this.style,
//
this.fieldStackedWidget,
this.hint,
this.prefixWidget,
this.suffixWidget,
this.messageBuilder,
this.contextButtons,
});
@override @override
State<AstromicFieldBase> createState() => _AstromicFieldBaseState(); State<AstromicFieldBase> createState() => _AstromicFieldBaseState();
@@ -128,9 +128,9 @@ class _AstromicFieldBaseState extends State<AstromicFieldBase> {
//SECTION - Stateless functions //SECTION - Stateless functions
_getTextHeight(String text, TextStyle style, ui.TextDirection direction) { _getTextHeight(String text, TextStyle style, ui.TextDirection direction) {
final span = TextSpan(text: text, style: style); final TextSpan span = TextSpan(text: text, style: style);
final tp = TextPainter(text: span, textDirection: direction); final TextPainter tp = TextPainter(text: span, textDirection: direction);
tp.layout(maxWidth: double.infinity); tp.layout();
return tp.height; return tp.height;
} }
@@ -167,7 +167,7 @@ class _AstromicFieldBaseState extends State<AstromicFieldBase> {
? widget.textController.text ? widget.textController.text
: (widget.hint?.isNotEmpty ?? false) : (widget.hint?.isNotEmpty ?? false)
? widget.hint! ? widget.hint!
: "", : '',
widget.textController.text.isNotEmpty && _style().textStyle != null widget.textController.text.isNotEmpty && _style().textStyle != null
? _style().textStyle! ? _style().textStyle!
: _style().hintStyle != null : _style().hintStyle != null
@@ -213,7 +213,7 @@ class _AstromicFieldBaseState extends State<AstromicFieldBase> {
) ?? ) ??
BorderRadius.circular(0)) BorderRadius.circular(0))
: OutlineInputBorder( : OutlineInputBorder(
borderSide: BorderSide(color: style.borderColor ?? Colors.grey, width: style.borderWidth ?? 2.0, style: BorderStyle.solid), borderSide: BorderSide(color: style.borderColor ?? Colors.grey, width: style.borderWidth ?? 2.0),
borderRadius: style.borderRadius?.resolve( borderRadius: style.borderRadius?.resolve(
_config.textDirection, _config.textDirection,
) ?? ) ??
@@ -229,7 +229,7 @@ class _AstromicFieldBaseState extends State<AstromicFieldBase> {
) ?? ) ??
BorderRadius.circular(0)) BorderRadius.circular(0))
: UnderlineInputBorder( : UnderlineInputBorder(
borderSide: BorderSide(color: style.borderColor ?? Colors.grey, width: style.borderWidth ?? 2.0, style: BorderStyle.solid), borderSide: BorderSide(color: style.borderColor ?? Colors.grey, width: style.borderWidth ?? 2.0),
borderRadius: style.borderRadius?.resolve( borderRadius: style.borderRadius?.resolve(
_config.textDirection, _config.textDirection,
) ?? ) ??
@@ -334,7 +334,7 @@ class _AstromicFieldBaseState extends State<AstromicFieldBase> {
return Column( return Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: <Widget>[
Directionality( Directionality(
textDirection: _finalTextDirection(), textDirection: _finalTextDirection(),
child: Container( child: Container(
@@ -345,7 +345,7 @@ class _AstromicFieldBaseState extends State<AstromicFieldBase> {
: null, : null,
alignment: _style().textAlignVertical.toAlignment(), alignment: _style().textAlignVertical.toAlignment(),
child: Stack( child: Stack(
children: [ children: <Widget>[
TextFormField( TextFormField(
//s1 -- Functionality //s1 -- Functionality
key: widget.stateKey, key: widget.stateKey,
@@ -353,7 +353,7 @@ class _AstromicFieldBaseState extends State<AstromicFieldBase> {
focusNode: _focusNode, focusNode: _focusNode,
textInputAction: _config.inputAction, textInputAction: _config.inputAction,
// //
onChanged: (v) { onChanged: (String v) {
setState(() { setState(() {
if (widget.onChanged != null) { if (widget.onChanged != null) {
widget.onChanged!(v); widget.onChanged!(v);
@@ -361,7 +361,7 @@ class _AstromicFieldBaseState extends State<AstromicFieldBase> {
}); });
}, },
// //
onFieldSubmitted: (v) { onFieldSubmitted: (String v) {
// //
if (_config.inputAction == TextInputAction.next) { if (_config.inputAction == TextInputAction.next) {
_focusNode.nextFocus(); _focusNode.nextFocus();
@@ -371,7 +371,7 @@ class _AstromicFieldBaseState extends State<AstromicFieldBase> {
} }
}, },
// //
onTapOutside: (tapEvent) { onTapOutside: (PointerDownEvent tapEvent) {
if (_config.unfocusOnTapOutside) { if (_config.unfocusOnTapOutside) {
_focusNode.unfocus(); _focusNode.unfocus();
} }
@@ -398,7 +398,7 @@ class _AstromicFieldBaseState extends State<AstromicFieldBase> {
// //
expands: _config.isFixedHeight && _config.isTextArea ? true : false, expands: _config.isFixedHeight && _config.isTextArea ? true : false,
// - Validation // - Validation
validator: _config.validator != null ? (s) => _config.validator!(_config.isEnabled, _isFocused, s) : null, validator: _config.validator != null ? (String? s) => _config.validator!(_config.isEnabled, _isFocused, s) : null,
// - Validation // - Validation
//s1 -- Style //s1 -- Style
style: _style().textStyle, style: _style().textStyle,
@@ -409,7 +409,7 @@ class _AstromicFieldBaseState extends State<AstromicFieldBase> {
//s1 -- Input Decoration //s1 -- Input Decoration
decoration: inputDecoration, decoration: inputDecoration,
//s1 -- Content //s1 -- Content
contextMenuBuilder: (_, state) { contextMenuBuilder: (_, EditableTextState state) {
List<ContextMenuButtonItem> baseContextButtons = state.contextMenuButtonItems; List<ContextMenuButtonItem> baseContextButtons = state.contextMenuButtonItems;
if (widget.contextButtons != null) { if (widget.contextButtons != null) {
baseContextButtons.addAll(widget.contextButtons!); baseContextButtons.addAll(widget.contextButtons!);

View File

@@ -1,34 +1,9 @@
import 'dart:ui' as ui; import 'dart:ui' as ui;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
/// Configuration model for the field element. /// Configuration model for the field element.
class AstromicFieldConfiguration { class AstromicFieldConfiguration {
//
final bool isEnabled;
final bool? isTextObscured;
final bool isFixedHeight;
final bool isTextArea;
//
final bool withAutofocus;
final bool respectBorderWidthPadding;
final bool withObscurity;
final bool withAutomaticDirectionalitySwitching;
final bool unfocusOnTapOutside;
//
final ui.TextDirection? hintDirection;
final ui.TextDirection? textDirection;
final ui.TextDirection? messageDirection;
//
final TextInputType inputType;
final TextInputAction inputAction;
//
final MaxLengthEnforcement maxLengthEnforcement;
//
final AutovalidateMode? validatingMode;
final String? Function(bool isEnabled, bool isFocused, String? text)? validator;
final List<TextInputFormatter>? inputFormatters;
// //
const AstromicFieldConfiguration({ const AstromicFieldConfiguration({
this.isEnabled = true, this.isEnabled = true,
@@ -55,6 +30,30 @@ class AstromicFieldConfiguration {
// //
}); });
// //
final bool isEnabled;
final bool? isTextObscured;
final bool isFixedHeight;
final bool isTextArea;
//
final bool withAutofocus;
final bool respectBorderWidthPadding;
final bool withObscurity;
final bool withAutomaticDirectionalitySwitching;
final bool unfocusOnTapOutside;
//
final ui.TextDirection? hintDirection;
final ui.TextDirection? textDirection;
final ui.TextDirection? messageDirection;
//
final TextInputType inputType;
final TextInputAction inputAction;
//
final MaxLengthEnforcement maxLengthEnforcement;
//
final AutovalidateMode? validatingMode;
final String? Function(bool isEnabled, bool isFocused, String? text)? validator;
final List<TextInputFormatter>? inputFormatters;
//
AstromicFieldConfiguration copyWith({ AstromicFieldConfiguration copyWith({
bool? isEnabled, bool? isEnabled,

View File

@@ -3,6 +3,37 @@ import '../enums/border_type.enum.dart';
/// Styling model for the field element. /// Styling model for the field element.
class AstromicFieldStyle { class AstromicFieldStyle {
const AstromicFieldStyle({
this.isFilled = true,
//
this.minLines = 1,
this.maxLines = 1,
this.maxLength,
this.textAlign = TextAlign.start,
this.textAlignVertical = TextAlignVertical.center,
//
this.fixedHeight,
//
this.borderRadius,
this.borderWidth,
this.borderType = AstromicFieldBorderType.underlined,
this.customBorder,
//
this.contentPadding = EdgeInsets.zero,
this.messagePadding = EdgeInsets.zero,
this.prefixSpacing = 4,
this.prefixSize = 24,
this.suffixSpacing = 4,
this.suffixSize = 24,
//
this.fillColor = const Color(0xffffffff),
this.borderColor,
this.borderGradient,
this.cursorColor,
this.hintStyle,
this.textStyle,
});
//s1 - Styling Configs //s1 - Styling Configs
final bool isFilled; final bool isFilled;
//s1 - Sizing & Spacing //s1 - Sizing & Spacing
@@ -38,37 +69,6 @@ class AstromicFieldStyle {
//s1 - Styling //s1 - Styling
final TextStyle? hintStyle; final TextStyle? hintStyle;
final TextStyle? textStyle; final TextStyle? textStyle;
const AstromicFieldStyle({
this.isFilled = true,
//
this.minLines = 1,
this.maxLines = 1,
this.maxLength,
this.textAlign = TextAlign.start,
this.textAlignVertical = TextAlignVertical.center,
//
this.fixedHeight,
//
this.borderRadius,
this.borderWidth,
this.borderType = AstromicFieldBorderType.underlined,
this.customBorder,
//
this.contentPadding = EdgeInsets.zero,
this.messagePadding = EdgeInsets.zero,
this.prefixSpacing = 4,
this.prefixSize = 24,
this.suffixSpacing = 4,
this.suffixSize = 24,
//
this.fillColor = const Color(0xffffffff),
this.borderColor,
this.borderGradient,
this.cursorColor,
this.hintStyle,
this.textStyle,
});
// //
AstromicFieldStyle copyWith({ AstromicFieldStyle copyWith({
bool? isFilled, bool? isFilled,

View File

@@ -12,6 +12,26 @@ import 'models/models.exports.dart';
//s1 Exports //s1 Exports
class AstromicTextField extends StatelessWidget { class AstromicTextField extends StatelessWidget {
//!SECTION
//
const AstromicTextField({
super.key,
//
required this.textController,
this.stateKey,
this.onChanged,
this.onSubmited,
//
this.configuration,
//
this.style,
//
this.hint,
this.prefixWidget,
this.suffixWidget,
this.messageBuilder,
this.contextButtons,
});
//SECTION - Widget Arguments //SECTION - Widget Arguments
//s1 -- Functionality //s1 -- Functionality
final TextEditingController textController; final TextEditingController textController;
@@ -34,26 +54,6 @@ class AstromicTextField extends StatelessWidget {
final Widget? Function(bool isEnabled, bool isFocused)? messageBuilder; final Widget? Function(bool isEnabled, bool isFocused)? messageBuilder;
// //
final Iterable<ContextMenuButtonItem>? contextButtons; final Iterable<ContextMenuButtonItem>? contextButtons;
//!SECTION
//
const AstromicTextField({
super.key,
//
required this.textController,
this.stateKey,
this.onChanged,
this.onSubmited,
//
this.configuration,
//
this.style,
//
this.hint,
this.prefixWidget,
this.suffixWidget,
this.messageBuilder,
this.contextButtons,
});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View File

@@ -45,7 +45,7 @@ class AstromicSelectors {
required Widget Function(T item, bool isEnabled, bool isSelected, VoidCallback? onTap, VoidCallback? onClearTapped) itemBuilder, required Widget Function(T item, bool isEnabled, bool isSelected, VoidCallback? onTap, VoidCallback? onClearTapped) itemBuilder,
Widget Function(List<Widget> items)? groupBuilder, Widget Function(List<Widget> items)? groupBuilder,
}) => }) =>
AstromicChipSelector( AstromicChipSelector<T>(
initialSelectedValues: initialSelectedValues, initialSelectedValues: initialSelectedValues,
onChanged: onChanged, onChanged: onChanged,
configuration: configuration, configuration: configuration,
@@ -53,6 +53,6 @@ class AstromicSelectors {
runSpacing: runSpacing, runSpacing: runSpacing,
items: items, items: items,
itemBuilder: itemBuilder, itemBuilder: itemBuilder,
groupBuilder: groupBuilder!, groupBuilder: groupBuilder,
); );
} }

View File

@@ -13,20 +13,6 @@ import 'models/models.exports.dart';
/// Selector that allows multible items to be selected from a group of items with the option to unselect and clear. /// Selector that allows multible items to be selected from a group of items with the option to unselect and clear.
class AstromicChipSelector<T> extends StatefulWidget { class AstromicChipSelector<T> extends StatefulWidget {
//SECTION - Widget Arguments
//s1 -- Functionality
final List<T>? initialSelectedValues;
final Function(List<T> selectedItems)? onChanged;
//s1 -- Configuration
final AstromicChipSelectorConfiguration? configuration;
//s1 -- Style
final double? itemSpacing;
final double? runSpacing;
//
//s1 -- Content
final List<(T item, bool isEnabled)> items;
final Widget Function(T item, bool isEnabled, bool isSelected, VoidCallback? onTap, VoidCallback? onClearTapped) itemBuilder;
final Widget Function(List<Widget> items)? groupBuilder;
//!SECTION //!SECTION
// //
AstromicChipSelector({ AstromicChipSelector({
@@ -44,12 +30,26 @@ class AstromicChipSelector<T> extends StatefulWidget {
required this.itemBuilder, required this.itemBuilder,
this.groupBuilder, this.groupBuilder,
}) : assert( }) : assert(
(configuration?.isNullable ?? true) || (initialSelectedValues != null && items.map((i) => i.$1).toList().containsAll(initialSelectedValues)), (configuration?.isNullable ?? true) || (initialSelectedValues != null && items.map(((T, bool) i) => i.$1).toList().containsAll(initialSelectedValues)),
"Initial values are not all present in the items!", 'Initial values are not all present in the items!',
), ),
super( super(
key: key, key: key,
); );
//SECTION - Widget Arguments
//s1 -- Functionality
final List<T>? initialSelectedValues;
final Function(List<T> selectedItems)? onChanged;
//s1 -- Configuration
final AstromicChipSelectorConfiguration? configuration;
//s1 -- Style
final double? itemSpacing;
final double? runSpacing;
//
//s1 -- Content
final List<(T item, bool isEnabled)> items;
final Widget Function(T item, bool isEnabled, bool isSelected, VoidCallback? onTap, VoidCallback? onClearTapped) itemBuilder;
final Widget Function(List<Widget> items)? groupBuilder;
@override @override
State<AstromicChipSelector<T>> createState() => _AstromicChipSelectorState<T>(); State<AstromicChipSelector<T>> createState() => _AstromicChipSelectorState<T>();
@@ -80,7 +80,7 @@ class _AstromicChipSelectorState<T> extends State<AstromicChipSelector<T>> {
//s1 --Controllers & Listeners //s1 --Controllers & Listeners
// //
//s1 --State //s1 --State
selectedItems = widget.initialSelectedValues ?? []; selectedItems = widget.initialSelectedValues ?? <T>[];
//s1 --State //s1 --State
// //
//s1 --Late & Async Initializers //s1 --Late & Async Initializers
@@ -126,7 +126,7 @@ class _AstromicChipSelectorState<T> extends State<AstromicChipSelector<T>> {
//s1 -Values //s1 -Values
// //
//s1 -Widgets //s1 -Widgets
List<Widget> baseChildren = widget.items.map((currentItem) { List<Widget> baseChildren = widget.items.map(((T, bool) currentItem) {
// //
AstromicChipSelectorConfiguration configuration = widget.configuration ?? const AstromicChipSelectorConfiguration(); AstromicChipSelectorConfiguration configuration = widget.configuration ?? const AstromicChipSelectorConfiguration();
// //

View File

@@ -3,15 +3,6 @@ import 'package:flutter/widgets.dart';
/// Configuration model for the chip selector element. /// Configuration model for the chip selector element.
class AstromicChipSelectorConfiguration { class AstromicChipSelectorConfiguration {
final bool isNullable;
final bool isWrap;
final WrapAlignment wrapMainAllignment;
final WrapCrossAlignment wrapCrossAllignment;
final bool isConsequent;
final bool withClearButton;
final int maxSelectedItems;
final int crossAxisCount;
final double? fixedRowHeight;
const AstromicChipSelectorConfiguration({ const AstromicChipSelectorConfiguration({
this.isNullable = true, this.isNullable = true,
// //
@@ -24,6 +15,15 @@ class AstromicChipSelectorConfiguration {
this.crossAxisCount = 3, this.crossAxisCount = 3,
this.fixedRowHeight, this.fixedRowHeight,
}); });
final bool isNullable;
final bool isWrap;
final WrapAlignment wrapMainAllignment;
final WrapCrossAlignment wrapCrossAllignment;
final bool isConsequent;
final bool withClearButton;
final int maxSelectedItems;
final int crossAxisCount;
final double? fixedRowHeight;
AstromicChipSelectorConfiguration copyWith({ AstromicChipSelectorConfiguration copyWith({
bool? isNullable, bool? isNullable,

View File

@@ -2,12 +2,6 @@ import 'package:flutter/widgets.dart';
/// Configuration model for the radio selector element. /// Configuration model for the radio selector element.
class AstromicRadioSelectorConfiguration { class AstromicRadioSelectorConfiguration {
final Axis axis;
final bool isNullable;
//
final MainAxisAlignment? mainAxisAlignment;
final MainAxisSize? mainAxisSize;
final CrossAxisAlignment? crossAxisAlignment;
const AstromicRadioSelectorConfiguration({ const AstromicRadioSelectorConfiguration({
this.axis = Axis.horizontal, this.axis = Axis.horizontal,
this.isNullable = true, this.isNullable = true,
@@ -16,6 +10,12 @@ class AstromicRadioSelectorConfiguration {
this.mainAxisSize, this.mainAxisSize,
this.crossAxisAlignment, this.crossAxisAlignment,
}); });
final Axis axis;
final bool isNullable;
//
final MainAxisAlignment? mainAxisAlignment;
final MainAxisSize? mainAxisSize;
final CrossAxisAlignment? crossAxisAlignment;
AstromicRadioSelectorConfiguration copyWith({ AstromicRadioSelectorConfiguration copyWith({
Axis? axis, Axis? axis,

View File

@@ -12,17 +12,6 @@ import 'models/models.exports.dart';
/// Selector that allows only one item to be selected from a group of items. /// Selector that allows only one item to be selected from a group of items.
class AstromicRadioSelector<T> extends StatefulWidget { class AstromicRadioSelector<T> extends StatefulWidget {
//SECTION - Widget Arguments
//s1 -- Functionality
final T? initialSelectedValue;
final Function(T selectedItem)? onChanged;
//s1 -- Configuration
final AstromicRadioSelectorConfiguration? configuration;
//s1 -- Style
final double? itemSpacing;
//s1 -- Content
final List<(T item, bool isEnabled)> items;
final Widget Function(T item, bool isEnabled, bool isSelected, VoidCallback? onTap) itemBuilder;
//!SECTION //!SECTION
// //
AstromicRadioSelector({ AstromicRadioSelector({
@@ -42,16 +31,27 @@ class AstromicRadioSelector<T> extends StatefulWidget {
configuration!.isNullable || configuration!.isNullable ||
(items (items
.map( .map(
(e) => e.$1, ((T, bool) e) => e.$1,
) )
.toList() .toList()
.contains(initialSelectedValue) && .contains(initialSelectedValue) &&
items.where((e) => e.$1 == initialSelectedValue).first.$2), items.where(((T, bool) e) => e.$1 == initialSelectedValue).first.$2),
"Initial value is not present in the items or is not enabled!", 'Initial value is not present in the items or is not enabled!',
), ),
super( super(
key: key, key: key,
); );
//SECTION - Widget Arguments
//s1 -- Functionality
final T? initialSelectedValue;
final Function(T selectedItem)? onChanged;
//s1 -- Configuration
final AstromicRadioSelectorConfiguration? configuration;
//s1 -- Style
final double? itemSpacing;
//s1 -- Content
final List<(T item, bool isEnabled)> items;
final Widget Function(T item, bool isEnabled, bool isSelected, VoidCallback? onTap) itemBuilder;
@override @override
State<AstromicRadioSelector<T>> createState() => _AstromicRadioSelectorState<T>(); State<AstromicRadioSelector<T>> createState() => _AstromicRadioSelectorState<T>();
@@ -116,7 +116,7 @@ class _AstromicRadioSelectorState<T> extends State<AstromicRadioSelector<T>> {
//s1 -Values //s1 -Values
// //
//s1 -Widgets //s1 -Widgets
List<Widget> baseChildren = widget.items.map((currentItem) { List<Widget> baseChildren = widget.items.map(((T, bool) currentItem) {
T item = currentItem.$1; T item = currentItem.$1;
bool isEnabled = currentItem.$2; bool isEnabled = currentItem.$2;
bool isSelected = item == selectedItem; bool isSelected = item == selectedItem;

View File

@@ -12,20 +12,6 @@ import '../models/models.exports.dart';
//s1 Exports //s1 Exports
class AstromicCheckboxToggle extends StatefulWidget { class AstromicCheckboxToggle extends StatefulWidget {
//SECTION - Widget Arguments
//s1 -- Functionality
/// If provided, you have to change the variable yourself in the onStateChanged!
final bool? stateVariable;
final bool? initialState;
final void Function(bool)? onStateChanged;
//s1 -- Configuration
final AstromicToggleConfiguration? configuration;
//s1 -- Style
final AstromicCheckboxToggleStyle Function(bool isEnabled, bool isSelected)? style;
//
//s1 -- Content
final Widget Function(bool isEnabled, bool isSelected)? innerWidget;
final Widget Function(bool isEnabled, bool isSelected)? label;
//!SECTION //!SECTION
// //
const AstromicCheckboxToggle({ const AstromicCheckboxToggle({
@@ -42,6 +28,20 @@ class AstromicCheckboxToggle extends StatefulWidget {
this.innerWidget, this.innerWidget,
this.label, this.label,
}) : assert(stateVariable == null || initialState == null, "Can't define both the state variable and the initial state"); }) : assert(stateVariable == null || initialState == null, "Can't define both the state variable and the initial state");
//SECTION - Widget Arguments
//s1 -- Functionality
/// If provided, you have to change the variable yourself in the onStateChanged!
final bool? stateVariable;
final bool? initialState;
final void Function(bool)? onStateChanged;
//s1 -- Configuration
final AstromicToggleConfiguration? configuration;
//s1 -- Style
final AstromicCheckboxToggleStyle Function(bool isEnabled, bool isSelected)? style;
//
//s1 -- Content
final Widget Function(bool isEnabled, bool isSelected)? innerWidget;
final Widget Function(bool isEnabled, bool isSelected)? label;
@override @override
State<AstromicCheckboxToggle> createState() => _AstromicCheckboxToggleState(); State<AstromicCheckboxToggle> createState() => _AstromicCheckboxToggleState();
@@ -129,7 +129,7 @@ class _AstromicCheckboxToggleState extends State<AstromicCheckboxToggle> {
textDirection: _config.textDirection, textDirection: _config.textDirection,
child: Row( child: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: <Widget>[
//Item //Item
SizedBox( SizedBox(
width: _style.itemSize, width: _style.itemSize,

View File

@@ -2,6 +2,14 @@ import 'package:flutter/material.dart';
/// Styling model for the CheckBox Toggle element. /// Styling model for the CheckBox Toggle element.
class AstromicCheckboxToggleStyle { class AstromicCheckboxToggleStyle {
AstromicCheckboxToggleStyle({
this.itemSize = 24.0,
this.labelSpacing = 8.0,
this.border = const Border.fromBorderSide(BorderSide(width: 2)),
this.borderRadius = const BorderRadius.all(Radius.circular(4)),
this.backgroundColor = Colors.transparent,
});
final double? itemSize; final double? itemSize;
final double? labelSpacing; final double? labelSpacing;
// //
@@ -9,14 +17,6 @@ class AstromicCheckboxToggleStyle {
final BorderRadius? borderRadius; final BorderRadius? borderRadius;
final Color? backgroundColor; final Color? backgroundColor;
AstromicCheckboxToggleStyle({
this.itemSize = 24.0,
this.labelSpacing = 8.0,
this.border = const Border.fromBorderSide(BorderSide(width: 2, color: Colors.black)),
this.borderRadius = const BorderRadius.all(Radius.circular(4)),
this.backgroundColor = Colors.transparent,
});
AstromicCheckboxToggleStyle copyWith({ AstromicCheckboxToggleStyle copyWith({
double? itemSize, double? itemSize,
double? labelSpacing, double? labelSpacing,

View File

@@ -2,24 +2,6 @@ import 'package:flutter/widgets.dart';
/// Styling model for the Switcher Toggle element. /// Styling model for the Switcher Toggle element.
class AstromicSwitcherToggleStyle { class AstromicSwitcherToggleStyle {
final double width;
final double height;
final double labelSpacing;
final double toggleSize;
final double togglePadding;
final double borderRadius;
//
final Color activeColor;
final Color? activeToggleColor;
final BoxBorder? activeToggleBorder;
final BoxBorder? activeSwitchBorder;
final Widget? innerActiveWidget;
//
final Color inactiveColor;
final Color? inactiveToggleColor;
final BoxBorder? inactiveSwitchBorder;
final BoxBorder? inactiveToggleBorder;
final Widget? innerInactiveWidget;
// //
const AstromicSwitcherToggleStyle({ const AstromicSwitcherToggleStyle({
this.width = 70, this.width = 70,
@@ -39,4 +21,22 @@ class AstromicSwitcherToggleStyle {
this.innerActiveWidget, this.innerActiveWidget,
this.innerInactiveWidget, this.innerInactiveWidget,
}); });
final double width;
final double height;
final double labelSpacing;
final double toggleSize;
final double togglePadding;
final double borderRadius;
//
final Color activeColor;
final Color? activeToggleColor;
final BoxBorder? activeToggleBorder;
final BoxBorder? activeSwitchBorder;
final Widget? innerActiveWidget;
//
final Color inactiveColor;
final Color? inactiveToggleColor;
final BoxBorder? inactiveSwitchBorder;
final BoxBorder? inactiveToggleBorder;
final Widget? innerInactiveWidget;
} }

View File

@@ -13,18 +13,6 @@ import '../models/models.exports.dart';
//s1 Exports //s1 Exports
class AstromicSwitcherToggle extends StatefulWidget { class AstromicSwitcherToggle extends StatefulWidget {
//SECTION - Widget Arguments
//s1 -- Functionality
/// If provided, you have to change the variable yourself in the onStateChanged!
final bool? stateVariable;
final bool? initialState;
final void Function(bool)? onStateChanged;
//s1 -- Configuration
final AstromicToggleConfiguration? configuration;
//s1 -- Style
final AstromicSwitcherToggleStyle Function(bool isEnabled, bool isSelected)? style;
//s1 -- Content
final Widget Function(bool isEnabled, bool isSelected)? label;
//!SECTION //!SECTION
// //
const AstromicSwitcherToggle({ const AstromicSwitcherToggle({
@@ -39,6 +27,18 @@ class AstromicSwitcherToggle extends StatefulWidget {
// //
this.label, this.label,
}); });
//SECTION - Widget Arguments
//s1 -- Functionality
/// If provided, you have to change the variable yourself in the onStateChanged!
final bool? stateVariable;
final bool? initialState;
final void Function(bool)? onStateChanged;
//s1 -- Configuration
final AstromicToggleConfiguration? configuration;
//s1 -- Style
final AstromicSwitcherToggleStyle Function(bool isEnabled, bool isSelected)? style;
//s1 -- Content
final Widget Function(bool isEnabled, bool isSelected)? label;
@override @override
State<AstromicSwitcherToggle> createState() => AstromicSwitcherToggleState(); State<AstromicSwitcherToggle> createState() => AstromicSwitcherToggleState();
@@ -111,7 +111,7 @@ class AstromicSwitcherToggleState extends State<AstromicSwitcherToggle> {
textDirection: _config.textDirection, textDirection: _config.textDirection,
child: Row( child: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: <Widget>[
//S1 -- Item //S1 -- Item
FlutterSwitch( FlutterSwitch(
width: _style.width, width: _style.width,
@@ -119,7 +119,6 @@ class AstromicSwitcherToggleState extends State<AstromicSwitcherToggle> {
borderRadius: _style.borderRadius, borderRadius: _style.borderRadius,
value: _currentState, value: _currentState,
toggleSize: _style.toggleSize, toggleSize: _style.toggleSize,
disabled: false,
// //
activeColor: _style.activeColor, activeColor: _style.activeColor,
activeToggleColor: _style.activeToggleColor, activeToggleColor: _style.activeToggleColor,
@@ -134,8 +133,7 @@ class AstromicSwitcherToggleState extends State<AstromicSwitcherToggle> {
inactiveIcon: _style.innerInactiveWidget, inactiveIcon: _style.innerInactiveWidget,
// //
padding: _style.togglePadding, padding: _style.togglePadding,
showOnOff: false, onToggle: (bool s) => _onTap(s),
onToggle: (s) => _onTap(s),
), ),
//S1 -- Label Spacing //S1 -- Label Spacing
if (_config.withLabel) SizedBox(width: _style.labelSpacing), if (_config.withLabel) SizedBox(width: _style.labelSpacing),

View File

@@ -2,16 +2,16 @@ import 'dart:ui';
/// SConfiguration model for the Toggles element group. /// SConfiguration model for the Toggles element group.
class AstromicToggleConfiguration { class AstromicToggleConfiguration {
final bool isEnabled;
final bool withLabel;
final bool isLabelTapable;
final TextDirection textDirection;
AstromicToggleConfiguration({ AstromicToggleConfiguration({
this.isEnabled = true, this.isEnabled = true,
this.withLabel = false, this.withLabel = false,
this.isLabelTapable = true, this.isLabelTapable = true,
this.textDirection = TextDirection.ltr, this.textDirection = TextDirection.ltr,
}); });
final bool isEnabled;
final bool withLabel;
final bool isLabelTapable;
final TextDirection textDirection;
AstromicToggleConfiguration copyWith({ AstromicToggleConfiguration copyWith({
bool? isEnabled, bool? isEnabled,

View File

@@ -11,15 +11,6 @@ import 'package:flutter/material.dart';
//s1 Exports //s1 Exports
class AstromicBlur extends StatelessWidget { class AstromicBlur extends StatelessWidget {
//SECTION - Widget Arguments
final Widget child;
final (double x, double y)? sigma;
final TileMode? tileMode;
final Color? overlayColor;
final Gradient? overlayGradient;
final BorderRadius? radius;
final List<BoxShadow>? shadow;
final Widget? childOnTop;
//!SECTION //!SECTION
// //
const AstromicBlur({ const AstromicBlur({
@@ -33,6 +24,15 @@ class AstromicBlur extends StatelessWidget {
this.shadow, this.shadow,
this.childOnTop, this.childOnTop,
}); });
//SECTION - Widget Arguments
final Widget child;
final (double x, double y)? sigma;
final TileMode? tileMode;
final Color? overlayColor;
final Gradient? overlayGradient;
final BorderRadius? radius;
final List<BoxShadow>? shadow;
final Widget? childOnTop;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -56,7 +56,7 @@ class AstromicBlur extends StatelessWidget {
borderRadius: radius ?? BorderRadius.zero, borderRadius: radius ?? BorderRadius.zero,
child: Stack( child: Stack(
fit: StackFit.expand, fit: StackFit.expand,
children: [ children: <Widget>[
child, // The main widget goes under the blurred background child, // The main widget goes under the blurred background
BackdropFilter( BackdropFilter(
filter: ImageFilter.blur(sigmaX: sigma!.$1, sigmaY: sigma!.$2), filter: ImageFilter.blur(sigmaX: sigma!.$1, sigmaY: sigma!.$2),

View File

@@ -47,42 +47,6 @@ _DeclaredAssetType _parseAssetType(
} }
class AstromicImage extends StatelessWidget { class AstromicImage extends StatelessWidget {
//SECTION - Widget Arguments
//S1 -- Assets
final String? assetPath;
final String? assetURL;
final Uint8List? assetBytes;
final String? assetFallback;
//S1 -- Sizing
final ImageSizingMaster? sizingMaster;
final (double factor, double? min, double? max)? widthSizing;
/// Used when the width is Master and want to set fixed width OR if height is Master and want to constraint the width
final double? fixedWidth;
final (double factor, double? min, double? max)? heightSizing;
/// Used when the height is Master and want to set fixed height OR if width is Master and want to constraint the height
final double? fixedHeight;
//S1 -- STYLING
final bool? isCircular;
final double? borderWidth;
final Color? borderColor;
final EdgeInsetsGeometry? borderPadding;
final BorderRadiusGeometry? radius;
final List<BoxShadow>? shadow;
final Color? overlayColor;
final Gradient? overlayGradient;
//S1 -- CONFIGURATIONS
final Alignment? alignment;
final BoxFit? fit;
final BlendMode? blendMode;
final Curve? fadeInCurve;
final Duration? fadeInDuration;
//S1 -- SVG FILTERS
final Color? svgColor;
//S1 -- STATE WIDGETS
final Widget Function(int? loadedBytes, int? totalBytesToLoad)? loadingWidget;
final Widget Function(dynamic error, StackTrace? stackTrace)? errorWidget;
//!SECTION //!SECTION
// //
AstromicImage({ AstromicImage({
@@ -121,16 +85,52 @@ class AstromicImage extends StatelessWidget {
}) : }) :
// Assert that a source is provided, or provide a fallback source.. // Assert that a source is provided, or provide a fallback source..
assert(((assetPath?.isNotEmpty ?? false) || (assetURL?.isNotEmpty ?? false) || (assetBytes?.isNotEmpty ?? false)) || (assetFallback?.isNotEmpty ?? false), assert(((assetPath?.isNotEmpty ?? false) || (assetURL?.isNotEmpty ?? false) || (assetBytes?.isNotEmpty ?? false)) || (assetFallback?.isNotEmpty ?? false),
"Please specify a source or provide a fallback."), 'Please specify a source or provide a fallback.'),
// Assert that only ONE source is provided... // Assert that only ONE source is provided...
assert( assert(
(assetPath != null && assetBytes == null && assetURL == null) || (assetPath != null && assetBytes == null && assetURL == null) ||
(assetPath == null && assetBytes != null && assetURL == null) || (assetPath == null && assetBytes != null && assetURL == null) ||
(assetPath == null && assetBytes == null && assetURL != null), (assetPath == null && assetBytes == null && assetURL != null),
"Please specify only ONE Asset Source"), 'Please specify only ONE Asset Source'),
// Assert that correct sizing plan is provided... // Assert that correct sizing plan is provided...
assert((sizingMaster == ImageSizingMaster.w && (widthSizing != null || fixedWidth != null)) || (sizingMaster == ImageSizingMaster.h && (heightSizing != null || fixedHeight != null)), assert((sizingMaster == ImageSizingMaster.w && (widthSizing != null || fixedWidth != null)) || (sizingMaster == ImageSizingMaster.h && (heightSizing != null || fixedHeight != null)),
"Please provide the correct sizing configurations based on the SizingMaster choosen"); 'Please provide the correct sizing configurations based on the SizingMaster choosen');
//SECTION - Widget Arguments
//S1 -- Assets
final String? assetPath;
final String? assetURL;
final Uint8List? assetBytes;
final String? assetFallback;
//S1 -- Sizing
final ImageSizingMaster? sizingMaster;
final (double factor, double? min, double? max)? widthSizing;
/// Used when the width is Master and want to set fixed width OR if height is Master and want to constraint the width
final double? fixedWidth;
final (double factor, double? min, double? max)? heightSizing;
/// Used when the height is Master and want to set fixed height OR if width is Master and want to constraint the height
final double? fixedHeight;
//S1 -- STYLING
final bool? isCircular;
final double? borderWidth;
final Color? borderColor;
final EdgeInsetsGeometry? borderPadding;
final BorderRadiusGeometry? radius;
final List<BoxShadow>? shadow;
final Color? overlayColor;
final Gradient? overlayGradient;
//S1 -- CONFIGURATIONS
final Alignment? alignment;
final BoxFit? fit;
final BlendMode? blendMode;
final Curve? fadeInCurve;
final Duration? fadeInDuration;
//S1 -- SVG FILTERS
final Color? svgColor;
//S1 -- STATE WIDGETS
final Widget Function(int? loadedBytes, int? totalBytesToLoad)? loadingWidget;
final Widget Function(dynamic error, StackTrace? stackTrace)? errorWidget;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -152,7 +152,7 @@ class AstromicImage extends StatelessWidget {
Widget? finalSVGWidget(Size size, Widget? loadingWidget) => assetType == _DeclaredAssetType.path Widget? finalSVGWidget(Size size, Widget? loadingWidget) => assetType == _DeclaredAssetType.path
? SvgPicture.asset( ? SvgPicture.asset(
assetRef, assetRef,
key: ValueKey(assetRef), key: ValueKey<String>(assetRef),
width: size.width, width: size.width,
height: size.height, height: size.height,
fit: fit!, fit: fit!,
@@ -167,7 +167,7 @@ class AstromicImage extends StatelessWidget {
: assetType == _DeclaredAssetType.url : assetType == _DeclaredAssetType.url
? SvgPicture.network( ? SvgPicture.network(
assetRef, assetRef,
key: ValueKey(assetRef), key: ValueKey<String>(assetRef),
width: size.width, width: size.width,
height: size.height, height: size.height,
fit: fit!, fit: fit!,
@@ -183,9 +183,9 @@ class AstromicImage extends StatelessWidget {
Widget buildImage(Size size) { Widget buildImage(Size size) {
return Stack( return Stack(
children: [ children: <Widget>[
OctoImage( OctoImage(
key: ValueKey(assetType == _DeclaredAssetType.bytes ? (assetRef as Uint8List).length.toString() : assetRef), key: ValueKey<String>(assetType == _DeclaredAssetType.bytes ? (assetRef as Uint8List).length.toString() : assetRef),
// //
width: size.width, width: size.width,
height: size.height, height: size.height,
@@ -195,8 +195,8 @@ class AstromicImage extends StatelessWidget {
color: svgColor, color: svgColor,
colorBlendMode: blendMode ?? (isSVG ? BlendMode.srcATop : null), colorBlendMode: blendMode ?? (isSVG ? BlendMode.srcATop : null),
// //
errorBuilder: (context, error, stackTrace) { errorBuilder: (BuildContext context, Object error, StackTrace? stackTrace) {
debugPrint("AstromicImage Error: $error"); debugPrint('AstromicImage Error: $error');
return errorWidget != null return errorWidget != null
? errorWidget!(error, stackTrace) ? errorWidget!(error, stackTrace)
: assetFallback != null : assetFallback != null
@@ -204,15 +204,15 @@ class AstromicImage extends StatelessWidget {
: defaultErrorWidget(error); : defaultErrorWidget(error);
}, },
// //
progressIndicatorBuilder: (_, bytes) => SizedBox( progressIndicatorBuilder: (_, ImageChunkEvent? bytes) => SizedBox(
width: size.width, width: size.width,
height: size.height, height: size.height,
child: loadingWidget != null ? loadingWidget!(bytes?.cumulativeBytesLoaded, bytes?.expectedTotalBytes) : defaultLoadingWidget, child: loadingWidget != null ? loadingWidget!(bytes?.cumulativeBytesLoaded, bytes?.expectedTotalBytes) : defaultLoadingWidget,
), ),
placeholderBuilder: (context) => loadingWidget != null ? loadingWidget!(null, null) : defaultLoadingWidget, placeholderBuilder: (BuildContext context) => loadingWidget != null ? loadingWidget!(null, null) : defaultLoadingWidget,
fadeInCurve: fadeInCurve, fadeInCurve: fadeInCurve,
fadeInDuration: fadeInDuration, fadeInDuration: fadeInDuration,
imageBuilder: (context, image) => Container( imageBuilder: (BuildContext context, Widget image) => Container(
width: size.width, width: size.width,
height: size.height, height: size.height,
padding: borderPadding ?? EdgeInsets.zero, padding: borderPadding ?? EdgeInsets.zero,
@@ -220,7 +220,6 @@ class AstromicImage extends StatelessWidget {
decoration: BoxDecoration( decoration: BoxDecoration(
border: borderWidth != null border: borderWidth != null
? Border.all( ? Border.all(
strokeAlign: BorderSide.strokeAlignInside,
width: borderWidth!, width: borderWidth!,
color: borderColor ?? const Color(0xff000000), color: borderColor ?? const Color(0xff000000),
) )
@@ -250,7 +249,7 @@ class AstromicImage extends StatelessWidget {
//!SECTION //!SECTION
//SECTION - Build Return //SECTION - Build Return
return LayoutBuilder(builder: (context, constraints) { return LayoutBuilder(builder: (BuildContext context, BoxConstraints constraints) {
Size size = _calculateSize(constraints); Size size = _calculateSize(constraints);
return SizedBox(width: size.width, height: size.height, child: buildImage(size)); return SizedBox(width: size.width, height: size.height, child: buildImage(size));
}); });