This commit is contained in:
2025-02-09 20:39:43 +02:00
parent 3641db54d3
commit 4a0ff120f7
47 changed files with 1273 additions and 1159 deletions

View File

@@ -1,7 +1,7 @@
# This is a generated file; do not edit or check into version control. # This is a generated file; do not edit or check into version control.
path_provider=/Users/micazi/.pub-cache/hosted/pub.dev/path_provider-2.1.3/ path_provider=C:\\Users\\micwa\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dev\\path_provider-2.1.3\\
path_provider_android=/Users/micazi/.pub-cache/hosted/pub.dev/path_provider_android-2.2.4/ path_provider_android=C:\\Users\\micwa\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dev\\path_provider_android-2.2.6\\
path_provider_foundation=/Users/micazi/.pub-cache/hosted/pub.dev/path_provider_foundation-2.3.2/ path_provider_foundation=C:\\Users\\micwa\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dev\\path_provider_foundation-2.4.0\\
path_provider_linux=/Users/micazi/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/ path_provider_linux=C:\\Users\\micwa\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dev\\path_provider_linux-2.2.1\\
path_provider_windows=/Users/micazi/.pub-cache/hosted/pub.dev/path_provider_windows-2.2.1/ path_provider_windows=C:\\Users\\micwa\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dev\\path_provider_windows-2.2.1\\
sqflite=/Users/micazi/.pub-cache/hosted/pub.dev/sqflite-2.3.3/ sqflite=C:\\Users\\micwa\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dev\\sqflite-2.3.3+1\\

View File

@@ -1 +1 @@
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"path_provider_foundation","path":"/Users/micazi/.pub-cache/hosted/pub.dev/path_provider_foundation-2.3.2/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"sqflite","path":"/Users/micazi/.pub-cache/hosted/pub.dev/sqflite-2.3.3/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"android":[{"name":"path_provider_android","path":"/Users/micazi/.pub-cache/hosted/pub.dev/path_provider_android-2.2.4/","native_build":true,"dependencies":[]},{"name":"sqflite","path":"/Users/micazi/.pub-cache/hosted/pub.dev/sqflite-2.3.3/","native_build":true,"dependencies":[]}],"macos":[{"name":"path_provider_foundation","path":"/Users/micazi/.pub-cache/hosted/pub.dev/path_provider_foundation-2.3.2/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"sqflite","path":"/Users/micazi/.pub-cache/hosted/pub.dev/sqflite-2.3.3/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/Users/micazi/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"/Users/micazi/.pub-cache/hosted/pub.dev/path_provider_windows-2.2.1/","native_build":false,"dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"sqflite","dependencies":[]}],"date_created":"2024-09-17 12:51:18.099992","version":"3.24.1","swift_package_manager_enabled":false} {"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"path_provider_foundation","path":"C:\\\\Users\\\\micwa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\path_provider_foundation-2.4.0\\\\","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"sqflite","path":"C:\\\\Users\\\\micwa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\sqflite-2.3.3+1\\\\","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"android":[{"name":"path_provider_android","path":"C:\\\\Users\\\\micwa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\path_provider_android-2.2.6\\\\","native_build":true,"dependencies":[]},{"name":"sqflite","path":"C:\\\\Users\\\\micwa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\sqflite-2.3.3+1\\\\","native_build":true,"dependencies":[]}],"macos":[{"name":"path_provider_foundation","path":"C:\\\\Users\\\\micwa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\path_provider_foundation-2.4.0\\\\","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"sqflite","path":"C:\\\\Users\\\\micwa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\sqflite-2.3.3+1\\\\","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"C:\\\\Users\\\\micwa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\path_provider_linux-2.2.1\\\\","native_build":false,"dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"C:\\\\Users\\\\micwa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\path_provider_windows-2.2.1\\\\","native_build":false,"dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"sqflite","dependencies":[]}],"date_created":"2025-02-09 15:39:20.757997","version":"3.27.1","swift_package_manager_enabled":false}

View File

@@ -1,3 +1,21 @@
## 0.0.1 <!---
## Guidelines for changelog/git
**INIT**: Initial commit in a repo, only committed once.
**DOC**: Updates/Refactors in the documents.
**CHORE**: Minor fixes and/or architecture enhancements.
**DEPS**: Dependency updates and the resulting refactors.
**SYNC**: Regular sync commits to ensure perfect syncing of all the development devices (Describes the feature in the working).
**TEST**: Adding/Updating test files.
**FIX**: Fixing a bug/issue that prevents a functionality.
**FEAT**: Add a completely new functionality or extend an existing one in a non-breaking manner.
**BREAKING CHANGE**: A [FEAT] but with breaking changes (Is only proposed as FEAT in the git commit).
## Version Composition
x.y.z
* Update z on Deps and Fixes.
* Update y on Feat that are large enough.
* Update x on BREAKING CHANGE that are a must and to signal phases completed [Alpha - Beta - Stable].
-->
- Initial release with mostly all of the components of this module. ## 0.1.0
- **INIT**: Initial commit in the new repo.

View File

@@ -1,6 +1,6 @@
## Atromic Mobile: Elements ## Atromic Elements
The elements module of the **Astromic Mobile** Presentation System The elements module of the **Astromic** Presentation System
Developed, Maintained, and is property of Michael W. Aziz (Micazi) Developed, Maintained, and is property of Michael W. Aziz (Micazi)
### Content ### Content

View File

@@ -1,3 +0,0 @@
### Chip Selector
[-] Investigate how to detect last enabled chip and check it's status in consequent mode.

View File

@@ -1,4 +1,5 @@
include: package:flutter_lints/flutter.yaml include: package:lints/recommended.yaml
linter: linter:
rules: rules:
- prefer_relative_imports - prefer_relative_imports

View File

@@ -0,0 +1,67 @@
import 'package:flutter/widgets.dart';
class GradientBoxBorder extends Border {
const GradientBoxBorder({required this.gradient, this.width = 1.0, super.bottom, super.left, super.right, super.top});
final Gradient gradient;
final double width;
@override
EdgeInsetsGeometry get dimensions => EdgeInsets.all(width);
@override
void paint(
Canvas canvas,
Rect rect, {
TextDirection? textDirection,
BoxShape shape = BoxShape.rectangle,
BorderRadius? borderRadius,
}) {
switch (shape) {
case BoxShape.circle:
assert(
borderRadius == null,
'A borderRadius can only be given for rectangular boxes.',
);
_paintCircle(canvas, rect);
break;
case BoxShape.rectangle:
if (borderRadius != null) {
_paintRRect(canvas, rect, borderRadius);
return;
}
_paintRect(canvas, rect);
break;
}
}
void _paintRect(Canvas canvas, Rect rect) {
// canvas.drawRect(rect.deflate(width / 2), _getPaint(rect));
canvas.drawLine(rect.bottomLeft, rect.bottomRight, _getPaint(rect));
}
void _paintRRect(Canvas canvas, Rect rect, BorderRadius borderRadius) {
// final rrect = borderRadius.toRRect().deflate(width / 2);
canvas.drawLine(rect.bottomLeft, rect.bottomRight, _getPaint(rect));
}
void _paintCircle(Canvas canvas, Rect rect) {
final paint = _getPaint(rect);
final radius = (rect.shortestSide - width) / 2.0;
canvas.drawCircle(rect.center, radius, paint);
}
@override
Border scale(double t) {
return this;
}
Paint _getPaint(Rect rect) {
return Paint()
..strokeWidth = width
..shader = gradient.createShader(rect)
..style = PaintingStyle.stroke;
}
}

View File

@@ -0,0 +1,4 @@
library gradient_borders;
export 'box_borders/gradient_box_border.dart';
export 'input_borders/gradient_outline_input_border.dart';

View File

@@ -0,0 +1,176 @@
import 'dart:math' as math;
import 'dart:ui';
import 'package:flutter/material.dart';
class GradientOutlineInputBorder extends InputBorder {
const GradientOutlineInputBorder({
required this.gradient,
this.width = 1.0,
this.gapPadding = 4.0,
this.borderRadius = const BorderRadius.all(Radius.circular(4)),
});
final double width;
final BorderRadius borderRadius;
final Gradient gradient;
final double gapPadding;
@override
InputBorder copyWith({BorderSide? borderSide}) {
return this;
}
@override
bool get isOutline => true;
@override
EdgeInsetsGeometry get dimensions => EdgeInsets.all(width);
@override
Path getInnerPath(Rect rect, {TextDirection? textDirection}) {
return Path()
..addRRect(
borderRadius
.resolve(textDirection)
.toRRect(rect)
.deflate(borderSide.width),
);
}
@override
Path getOuterPath(Rect rect, {TextDirection? textDirection}) {
return Path()..addRRect(borderRadius.resolve(textDirection).toRRect(rect));
}
@override
void paint(
Canvas canvas,
Rect rect, {
double? gapStart,
double gapExtent = 0.0,
double gapPercentage = 0.0,
TextDirection? textDirection,
}) {
final paint = _getPaint(rect);
final outer = borderRadius.toRRect(rect);
final center = outer.deflate(borderSide.width / 2.0);
if (gapStart == null || gapExtent <= 0.0 || gapPercentage == 0.0) {
canvas.drawRRect(center, paint);
} else {
final extent =
lerpDouble(0.0, gapExtent + gapPadding * 2.0, gapPercentage)!;
switch (textDirection!) {
case TextDirection.rtl:
final path = _gapBorderPath(
canvas,
center,
math.max(0, gapStart + gapPadding - extent),
extent,
);
canvas.drawPath(path, paint);
break;
case TextDirection.ltr:
final path = _gapBorderPath(
canvas,
center,
math.max(0, gapStart - gapPadding),
extent,
);
canvas.drawPath(path, paint);
break;
}
}
}
@override
ShapeBorder scale(double t) {
return GradientOutlineInputBorder(
width: width * t,
borderRadius: borderRadius * t,
gradient: gradient,
);
}
Paint _getPaint(Rect rect) {
return Paint()
..strokeWidth = width
..shader = gradient.createShader(rect)
..style = PaintingStyle.stroke;
}
Path _gapBorderPath(
Canvas canvas,
RRect center,
double start,
double extent,
) {
// 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
// size of the width/height of the RRect.
final scaledRRect = center.scaleRadii();
final tlCorner = Rect.fromLTWH(
scaledRRect.left,
scaledRRect.top,
scaledRRect.tlRadiusX * 2.0,
scaledRRect.tlRadiusY * 2.0,
);
final trCorner = Rect.fromLTWH(
scaledRRect.right - scaledRRect.trRadiusX * 2.0,
scaledRRect.top,
scaledRRect.trRadiusX * 2.0,
scaledRRect.trRadiusY * 2.0,
);
final brCorner = Rect.fromLTWH(
scaledRRect.right - scaledRRect.brRadiusX * 2.0,
scaledRRect.bottom - scaledRRect.brRadiusY * 2.0,
scaledRRect.brRadiusX * 2.0,
scaledRRect.brRadiusY * 2.0,
);
final blCorner = Rect.fromLTWH(
scaledRRect.left,
scaledRRect.bottom - scaledRRect.blRadiusY * 2.0,
scaledRRect.blRadiusX * 2.0,
scaledRRect.blRadiusX * 2.0,
);
const cornerArcSweep = math.pi / 2.0;
final tlCornerArcSweep = start < scaledRRect.tlRadiusX
? math.asin((start / scaledRRect.tlRadiusX).clamp(-1.0, 1.0))
: math.pi / 2.0;
final path = Path()
..addArc(tlCorner, math.pi, tlCornerArcSweep)
..moveTo(scaledRRect.left + scaledRRect.tlRadiusX, scaledRRect.top);
if (start > scaledRRect.tlRadiusX) {
path.lineTo(scaledRRect.left + start, scaledRRect.top);
}
const trCornerArcStart = (3 * math.pi) / 2.0;
const trCornerArcSweep = cornerArcSweep;
if (start + extent < scaledRRect.width - scaledRRect.trRadiusX) {
path
..relativeMoveTo(extent, 0)
..lineTo(scaledRRect.right - scaledRRect.trRadiusX, scaledRRect.top)
..addArc(trCorner, trCornerArcStart, trCornerArcSweep);
} else if (start + extent < scaledRRect.width) {
final dx = scaledRRect.width - (start + extent);
final sweep = math.acos(dx / scaledRRect.trRadiusX);
path.addArc(trCorner, trCornerArcStart + sweep, trCornerArcSweep - sweep);
}
return path
..moveTo(scaledRRect.right, scaledRRect.top + scaledRRect.trRadiusY)
..lineTo(scaledRRect.right, scaledRRect.bottom - scaledRRect.brRadiusY)
..addArc(brCorner, 0, cornerArcSweep)
..lineTo(scaledRRect.left + scaledRRect.blRadiusX, scaledRRect.bottom)
..addArc(blCorner, math.pi / 2.0, cornerArcSweep)
..lineTo(scaledRRect.left, scaledRRect.top + scaledRRect.tlRadiusY);
}
}

View File

@@ -0,0 +1,75 @@
import 'dart:math' as math;
import 'dart:ui';
import 'package:flutter/material.dart';
class GradientUnderlineInputBorder extends InputBorder {
const GradientUnderlineInputBorder({
required this.gradient,
this.width = 1.0,
this.gapPadding = 4.0,
this.borderRadius = const BorderRadius.all(Radius.circular(4)),
});
final double width;
final BorderRadius borderRadius;
final Gradient gradient;
final double gapPadding;
@override
InputBorder copyWith({BorderSide? borderSide}) {
return this;
}
@override
bool get isOutline => true;
@override
EdgeInsetsGeometry get dimensions => EdgeInsets.all(width);
@override
Path getInnerPath(Rect rect, {TextDirection? textDirection}) {
return Path()
..addRRect(
borderRadius.resolve(textDirection).toRRect(rect).deflate(borderSide.width),
);
}
@override
Path getOuterPath(Rect rect, {TextDirection? textDirection}) {
return Path()..addRRect(borderRadius.resolve(textDirection).toRRect(rect));
}
@override
void paint(
Canvas canvas,
Rect rect, {
double? gapStart,
double gapExtent = 0.0,
double gapPercentage = 0.0,
TextDirection? textDirection,
}) {
final paint = _getPaint(rect);
Rect underlineRect = Rect.fromLTWH(rect.left, rect.height - width, rect.width, width);
canvas.drawRect(underlineRect, paint);
}
@override
ShapeBorder scale(double t) {
return GradientUnderlineInputBorder(
width: width * t,
borderRadius: borderRadius * t,
gradient: gradient,
);
}
Paint _getPaint(Rect rect) {
return Paint()
..strokeWidth = width
..shader = gradient.createShader(rect)
..style = PaintingStyle.stroke;
}
}

View File

@@ -1,7 +0,0 @@
import "package:flutter/painting.dart";
extension BorderExtension on BorderDirectional {
BorderDirectional all(BorderSide side) {
return BorderDirectional(top: side, bottom: side, start: side, end: side);
}
}

View File

@@ -1,7 +0,0 @@
export './border_extensions.dart';
export './insets_extension.dart';
export './list_extensions.dart';
export './misc_extensions.dart';
export './radius_extensions.dart';
export './string_extensions.dart';
export './transparent_image.dart';

View File

@@ -1,12 +0,0 @@
import 'package:flutter/widgets.dart';
extension InsetsExtension on EdgeInsetsGeometry {
copyWith(EdgeInsetsGeometry g) => add(g);
//
EdgeInsetsDirectional resolveToDirectional(TextDirection direction) {
//
return EdgeInsetsDirectional.fromSTEB(direction == TextDirection.ltr ? resolve(direction).left : resolve(direction).right, resolve(direction).top,
direction == TextDirection.ltr ? resolve(direction).right : resolve(direction).left, resolve(direction).bottom);
//
}
}

View File

@@ -1,20 +0,0 @@
extension ListExtension<E> on List<E> {
bool containsAll(List<E> otherList) {
List<bool> checks = [];
//
for (E thisElement in otherList) {
checks.add(contains(thisElement));
}
return !checks.contains(false);
}
List<E> getUnique() {
List<E> uniqueItems = [];
for (E thisElement in this) {
if (!uniqueItems.contains(thisElement)) {
uniqueItems.add(thisElement);
}
}
return uniqueItems;
}
}

View File

@@ -1,16 +0,0 @@
import 'package:flutter/material.dart';
extension TextAlignVerticalExtension on TextAlignVertical {
toAlignment() {
switch (this) {
case TextAlignVertical.top:
return Alignment.topCenter;
case TextAlignVertical.center:
return Alignment.center;
case TextAlignVertical.bottom:
return Alignment.bottomCenter;
default:
return Alignment.center;
}
}
}

View File

@@ -1,15 +0,0 @@
import 'package:flutter/widgets.dart';
extension RadiusExtension on BorderRadiusGeometry {
copyWith(BorderRadiusGeometry g) => add(g);
//
BorderRadiusDirectional resolveToDirectional(TextDirection direction) {
//
return BorderRadiusDirectional.only(
topStart: direction == TextDirection.ltr ? resolve(direction).topLeft : resolve(direction).topRight,
topEnd: direction == TextDirection.rtl ? resolve(direction).topLeft : resolve(direction).topRight,
bottomEnd: direction == TextDirection.rtl ? resolve(direction).bottomRight : resolve(direction).bottomRight,
bottomStart: direction == TextDirection.ltr ? resolve(direction).bottomLeft : resolve(direction).bottomRight,
);
}
}

View File

@@ -1,19 +0,0 @@
import 'package:flutter/material.dart';
extension StringExtensions on String {
/// Parse the HexCode to color
Color get toColor {
if (this == '') return const Color(0xFF000000);
String hexColor = replaceAll('#', '');
hexColor = hexColor.replaceAll('0x', '');
hexColor = hexColor.padLeft(6, '0');
hexColor = hexColor.padLeft(8, 'F');
final int length = hexColor.length;
return Color(int.tryParse('0x${hexColor.substring(length - 8, length)}') ?? 0xFF000000);
}
/// Capitalize the first letter in a string.
String get capitalize {
return (length > 1) ? this[0].toUpperCase() + substring(1) : toUpperCase();
}
}

View File

@@ -1,73 +0,0 @@
library transparent_image;
import 'dart:typed_data';
final Uint8List kTransparentImage = Uint8List.fromList(<int>[
0x89,
0x50,
0x4E,
0x47,
0x0D,
0x0A,
0x1A,
0x0A,
0x00,
0x00,
0x00,
0x0D,
0x49,
0x48,
0x44,
0x52,
0x00,
0x00,
0x00,
0x01,
0x00,
0x00,
0x00,
0x01,
0x08,
0x06,
0x00,
0x00,
0x00,
0x1F,
0x15,
0xC4,
0x89,
0x00,
0x00,
0x00,
0x0A,
0x49,
0x44,
0x41,
0x54,
0x78,
0x9C,
0x63,
0x00,
0x01,
0x00,
0x00,
0x05,
0x00,
0x01,
0x0D,
0x0A,
0x2D,
0xB4,
0x00,
0x00,
0x00,
0x00,
0x49,
0x45,
0x4E,
0x44,
0xAE,
0x42,
0x60,
0x82,
]);

View File

@@ -1,4 +1,4 @@
library astromic_mobile_elements; library astromic_elements;
export './src/Spacing/spacing.astromic.dart'; export './src/Spacing/spacing.astromic.dart';
export './src/Widgets/widgets.astromic.dart'; export './src/Widgets/widgets.astromic.dart';
@@ -6,6 +6,4 @@ export './src/Selectors/selectors.astromic.dart';
export './src/Toggles/toggles.astromic.dart'; export './src/Toggles/toggles.astromic.dart';
export './src/Buttons/buttons.astromic.dart'; export './src/Buttons/buttons.astromic.dart';
export './src/Fields/fields.astromic.dart'; export './src/Fields/fields.astromic.dart';
export './Infrastructure/infrastructure.exports.dart';
export 'package:flutter_svg/flutter_svg.dart' show SvgPicture, BytesLoader, SvgAssetLoader; //Needed for assets manipulation export 'package:flutter_svg/flutter_svg.dart' show SvgPicture, BytesLoader, SvgAssetLoader; //Needed for assets manipulation

View File

@@ -1,30 +1,34 @@
//s2 Core Packages Imports //s1 Imports
//s2 Core Package Imports
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
// //s2 1st-party Package Imports
//s2 3rd-party Package Imports
//s2 Dependancies Imports
//s3 Routes
//s3 Services
//s3 Models
import 'src/icon_button.dart'; import 'src/icon_button.dart';
import 'src/link_button.dart'; import 'src/link_button.dart';
import 'src/state_button.dart'; import 'src/state_button.dart';
// //
import 'src/sizing_strategy.enum.dart'; import 'src/enums/enums.exports.dart';
import 'src/style.dart'; import 'src/models/models.exports.dart';
// //s1 Exports
export 'src/sizing_strategy.enum.dart'; export 'src/enums/enums.exports.dart';
export 'src/style.dart'; export 'src/models/models.exports.dart';
/// A collection of the available Astromic buttons.
class AstromicButtons { class AstromicButtons {
//S1 -- State /// an `AstromicStateButton` is a button whoose style is affected by it's state.
static Widget state({ static Widget state({
// //
void Function(VoidCallback start, VoidCallback stop)? onTap, void Function(VoidCallback start, VoidCallback stop)? onTap,
Function(VoidCallback start, VoidCallback stop)? onHold, Function(VoidCallback start, VoidCallback stop)? onHold,
// //
bool? isEnabled, AstromicButtonConfiguration? configuration,
bool? withFeedback,
bool? withHighlightChange,
TextDirection? textDirection,
// //
SizingStrategy? widthSizingStrategy, AstromicSizingStrategy? widthSizingStrategy,
SizingStrategy? heightSizingStrategy, AstromicSizingStrategy? heightSizingStrategy,
InteractiveInkFeatureFactory? splashFactory, InteractiveInkFeatureFactory? splashFactory,
required AstromicButtonStyle Function(bool isEnabled, bool isHighlighted, bool isLoading) style, required AstromicButtonStyle Function(bool isEnabled, bool isHighlighted, bool isLoading) style,
// //
@@ -35,30 +39,23 @@ class AstromicButtons {
onTap: onTap, onTap: onTap,
onHold: onHold, onHold: onHold,
// //
isEnabled: isEnabled ?? true, configuration: configuration,
withFeedback: withFeedback ?? true,
withHighlightChange: withHighlightChange ?? true,
textDirection: textDirection ?? TextDirection.ltr,
// //
widthSizingStrategy: widthSizingStrategy, widthSizingStrategy: widthSizingStrategy,
heightSizingStrategy: heightSizingStrategy, heightSizingStrategy: heightSizingStrategy,
splashFactory: splashFactory,
style: style, style: style,
// //
loadingContent: loadingContent, loadingContent: loadingContent,
content: content, content: content,
); );
//S1 -- Icon /// an `AstromicIconButton` is a button specifically for mapping to an IconButton.
static Widget icon({ static Widget icon({
// //
void Function(VoidCallback start, VoidCallback stop)? onTap, void Function(VoidCallback start, VoidCallback stop)? onTap,
Function(VoidCallback start, VoidCallback stop)? onHold, Function(VoidCallback start, VoidCallback stop)? onHold,
// //
bool? isEnabled, AstromicButtonConfiguration? configuration,
bool? withFeedback,
bool? withHighlightChange,
TextDirection? textDirection,
// //
bool? isCircular, bool? isCircular,
InteractiveInkFeatureFactory? splashFactory, InteractiveInkFeatureFactory? splashFactory,
@@ -71,27 +68,22 @@ class AstromicButtons {
onTap: onTap, onTap: onTap,
onHold: onHold, onHold: onHold,
// //
isEnabled: isEnabled ?? true, configuration: configuration,
withFeedback: withFeedback ?? true,
withHighlightChange: withHighlightChange ?? true,
textDirection: textDirection ?? TextDirection.ltr,
// //
isCircular: isCircular ?? true, isCircular: isCircular ?? true,
splashFactory: splashFactory,
style: style, style: style,
// //
loadingContent: loadingContent, loadingContent: loadingContent,
icon: icon, icon: icon,
); );
//S1 -- Link /// an `AstromicLinkButton` is a button specifically for mapping to LinkButton.
static Widget link({ static Widget link({
// //
VoidCallback? onTap, VoidCallback? onTap,
VoidCallback? onHold, VoidCallback? onHold,
// //
bool? isEnabled, AstromicButtonConfiguration? configuration,
TextDirection? textDirection,
// //
bool Function(bool isEnabled)? isUnderlined, bool Function(bool isEnabled)? isUnderlined,
EdgeInsetsGeometry? contentPadding, EdgeInsetsGeometry? contentPadding,
@@ -106,8 +98,7 @@ class AstromicButtons {
onTap: onTap, onTap: onTap,
onHold: onHold, onHold: onHold,
// //
isEnabled: isEnabled ?? true, configuration: configuration,
textDirection: textDirection ?? TextDirection.ltr,
// //
isUnderlined: isUnderlined ?? (e) => e, isUnderlined: isUnderlined ?? (e) => e,
contentPadding: contentPadding, contentPadding: contentPadding,

View File

@@ -1,22 +1,15 @@
//SECTION - Imports //s1 Imports
// //s2 Core Package Imports
//s1 PACKAGES
//---------------
//s2 CORE
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
//s2 3RD-PARTY //s2 1st-party Package Imports
// import '../../../Dependencies/gradient_border/gradient_borders.dart';
//s1 DEPENDENCIES //s2 3rd-party Package Imports
//---------------- //s2 Dependancies Imports
//s2 SERVICES //s3 Routes
//s2 MODELS //s3 Services
import 'style.dart'; //s3 Models
//s2 MISC import 'models/models.exports.dart';
//!SECTION - Imports //s1 Exports
//
//SECTION - Exports
//!SECTION - Exports
//
class AstromicButtonBase extends StatefulWidget { class AstromicButtonBase extends StatefulWidget {
//SECTION - Widget Arguments //SECTION - Widget Arguments
@@ -24,13 +17,9 @@ class AstromicButtonBase extends StatefulWidget {
final VoidCallback? onTap; final VoidCallback? onTap;
final VoidCallback? onHold; final VoidCallback? onHold;
//s1 -- Configurations //s1 -- Configurations
final bool isEnabled; final AstromicButtonConfiguration? configuration;
final bool withFeedback;
final bool withHighlightChange;
final TextDirection textDirection;
//s1 -- Style //s1 -- Style
final InteractiveInkFeatureFactory? splashFactory; final AstromicButtonStyle Function(bool isEnabled, bool isHighlighted)? style;
final AstromicButtonStyle Function(bool isEnabled, bool isHighlighted) style;
//s1 -- Content //s1 -- Content
final Widget Function(bool isEnabled, bool isHighlighted) child; final Widget Function(bool isEnabled, bool isHighlighted) child;
//!SECTION //!SECTION
@@ -41,13 +30,9 @@ class AstromicButtonBase extends StatefulWidget {
this.onTap, this.onTap,
this.onHold, this.onHold,
// //
this.isEnabled = true, this.configuration,
this.withFeedback = true,
this.withHighlightChange = true,
required this.textDirection,
//s1 -- Style //s1 -- Style
this.splashFactory, this.style,
required this.style,
//s1 -- Content //s1 -- Content
required this.child, required this.child,
}) : super( }) : super(
@@ -66,6 +51,8 @@ class _AstromicButtonBaseState extends State<AstromicButtonBase> {
// //
//s1 --State //s1 --State
late bool _isHighlighted; late bool _isHighlighted;
late AstromicButtonConfiguration _config;
late AstromicButtonStyle _style;
//s1 --State //s1 --State
// //
//s1 --Constants //s1 --Constants
@@ -93,6 +80,8 @@ class _AstromicButtonBaseState extends State<AstromicButtonBase> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
//SECTION - Build Setup //SECTION - Build Setup
//s1 -Values //s1 -Values
_config = widget.configuration ?? AstromicButtonConfiguration(isEnabled: true, withFeedback: true, withHighlightChange: true, textDirection: TextDirection.ltr);
_style = widget.style?.call(_config.isEnabled, _isHighlighted) ?? const AstromicButtonStyle();
//s1 -Values //s1 -Values
// //
//s1 -Widgets //s1 -Widgets
@@ -101,30 +90,37 @@ class _AstromicButtonBaseState extends State<AstromicButtonBase> {
//SECTION - Build Return //SECTION - Build Return
return Material( return Material(
color: widget.style(widget.isEnabled, _isHighlighted).backgroundGradient != null ? Colors.transparent : widget.style(widget.isEnabled, _isHighlighted).backgroundColor, color: _style.backgroundGradient != null ? Colors.transparent : _style.backgroundColor,
shape: OutlineInputBorder( shape: _style.borderGradient != null
? GradientOutlineInputBorder(
gapPadding: 0,
gradient: _style.borderGradient!,
borderRadius: _style.borderRadius?.resolve(_config.textDirection) ?? BorderRadius.circular(0),
width: _style.borderWidth ?? 1,
)
: OutlineInputBorder(
borderSide: BorderSide( borderSide: BorderSide(
width: widget.style(widget.isEnabled, _isHighlighted).borderWidth ?? 1, width: _style.borderWidth ?? 1,
color: widget.style(widget.isEnabled, _isHighlighted).borderColor ?? Colors.black, color: _style.borderColor ?? Colors.black,
), ),
borderRadius: widget.style(widget.isEnabled, _isHighlighted).borderRadius?.resolve(widget.textDirection) ?? BorderRadius.circular(0), borderRadius: _style.borderRadius?.resolve(_config.textDirection) ?? BorderRadius.circular(0),
), ),
child: Ink( child: Ink(
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: widget.style(widget.isEnabled, _isHighlighted).borderRadius?.resolve(widget.textDirection) ?? BorderRadius.circular(0), borderRadius: _style.borderRadius?.resolve(_config.textDirection) ?? BorderRadius.circular(0),
gradient: widget.style(widget.isEnabled, _isHighlighted).backgroundGradient, gradient: _style.backgroundGradient,
), ),
child: InkWell( child: InkWell(
splashFactory: widget.splashFactory, splashFactory: _style.splashFactory,
splashColor: widget.withFeedback ? widget.style(widget.isEnabled, _isHighlighted).splashColor : Colors.transparent, splashColor: _config.withFeedback ? _style.splashColor : Colors.transparent,
hoverColor: widget.withFeedback ? widget.style(widget.isEnabled, _isHighlighted).hoverColor : Colors.transparent, hoverColor: _config.withFeedback ? _style.hoverColor : Colors.transparent,
highlightColor: widget.withFeedback ? widget.style(widget.isEnabled, _isHighlighted).highlightColor : Colors.transparent, highlightColor: _config.withFeedback ? _style.highlightColor : Colors.transparent,
// //
borderRadius: widget.style(widget.isEnabled, _isHighlighted).borderRadius?.resolve(widget.textDirection) ?? BorderRadius.circular(0), borderRadius: _style.borderRadius?.resolve(_config.textDirection) ?? BorderRadius.circular(0),
// //
onTap: widget.isEnabled && widget.onTap != null ? widget.onTap : null, onTap: _config.isEnabled && widget.onTap != null ? widget.onTap : null,
onLongPress: widget.isEnabled && widget.onHold != null ? widget.onHold : null, onLongPress: _config.isEnabled && widget.onHold != null ? widget.onHold : null,
onHighlightChanged: widget.withHighlightChange onHighlightChanged: _config.withHighlightChange
? (v) { ? (v) {
setState(() { setState(() {
_isHighlighted = v; _isHighlighted = v;
@@ -133,9 +129,9 @@ class _AstromicButtonBaseState extends State<AstromicButtonBase> {
: null, : null,
// //
child: Padding( child: Padding(
padding: widget.style(widget.isEnabled, _isHighlighted).contentPadding ?? EdgeInsets.zero, padding: _style.contentPadding ?? EdgeInsets.zero,
child: widget.child( child: widget.child(
widget.isEnabled, _config.isEnabled,
_isHighlighted, _isHighlighted,
), ),
), ),

View File

@@ -0,0 +1 @@
export './sizing_strategy.enum.dart';

View File

@@ -0,0 +1,6 @@
/// Sizing strategy for how the element is sized in it's bounds; Fill it, Hug it's content, or Fixed.
enum AstromicSizingStrategy {
hug,
fill,
fixed,
}

View File

@@ -1,23 +1,15 @@
//SECTION - Imports //s1 Imports
// //s2 Core Package Imports
//s1 PACKAGES
//---------------
//s2 CORE
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
//s2 1st-party Package Imports
//s2 3rd-party Package Imports
//s2 Dependancies Imports
//s3 Routes
//s3 Services
//s3 Models
import 'base.dart'; import 'base.dart';
import 'style.dart'; import 'models/models.exports.dart';
//s2 3RD-PARTY //s1 Exports
//
//s1 DEPENDENCIES
//---------------
//s2 SERVICES
//s2 MODELS
//s2 MISC
//!SECTION - Imports
//
//SECTION - Exports
//!SECTION - Exports
//
class AstromicIconButton extends StatefulWidget { class AstromicIconButton extends StatefulWidget {
//SECTION - Widget Arguments //SECTION - Widget Arguments
@@ -25,12 +17,8 @@ class AstromicIconButton extends StatefulWidget {
final void Function(VoidCallback start, VoidCallback stop)? onTap; final void Function(VoidCallback start, VoidCallback stop)? onTap;
final Function(VoidCallback start, VoidCallback stop)? onHold; final Function(VoidCallback start, VoidCallback stop)? onHold;
//s1 -- Configurations //s1 -- Configurations
final bool isEnabled; final AstromicButtonConfiguration? configuration;
final bool withFeedback;
final bool withHighlightChange;
final TextDirection textDirection;
//s1 -- Style //s1 -- Style
final InteractiveInkFeatureFactory? splashFactory;
final bool isCircular; final bool isCircular;
final AstromicButtonStyle Function(bool isEnabled, bool isHighlighted, bool isLoading)? style; final AstromicButtonStyle Function(bool isEnabled, bool isHighlighted, bool isLoading)? style;
//s1 -- Content //s1 -- Content
@@ -44,13 +32,9 @@ class AstromicIconButton extends StatefulWidget {
this.onTap, this.onTap,
this.onHold, this.onHold,
// //
required this.isEnabled, this.configuration,
required this.withFeedback,
required this.withHighlightChange,
required this.textDirection,
//s1 -- Style //s1 -- Style
this.splashFactory, this.isCircular = true,
required this.isCircular,
this.style, this.style,
//s1 -- Content //s1 -- Content
this.loadingContent, this.loadingContent,
@@ -103,10 +87,7 @@ class _AstromicIconButtonState extends State<AstromicIconButton> {
//s1 -Widgets //s1 -Widgets
//----- //-----
Widget baseChild = AstromicButtonBase( Widget baseChild = AstromicButtonBase(
isEnabled: widget.isEnabled, configuration: widget.configuration,
withFeedback: widget.withFeedback,
withHighlightChange: widget.withHighlightChange,
textDirection: widget.textDirection,
// //
onTap: !isLoading && context.mounted && widget.onTap != null onTap: !isLoading && context.mounted && widget.onTap != null
? () { ? () {
@@ -134,8 +115,9 @@ class _AstromicIconButtonState extends State<AstromicIconButton> {
}); });
} }
: null, : null,
splashFactory: widget.splashFactory, style: widget.style == null
style: (enabled, highlighted) => widget.style!(enabled, highlighted, isLoading).copyWith( ? null
: (enabled, 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: (enabled, highlighted) => isLoading && widget.loadingContent != null ? widget.loadingContent! : widget.icon(enabled, highlighted),

View File

@@ -1,32 +1,23 @@
//SECTION - Imports //s1 Imports
// //s2 Core Package Imports
//s1 PACKAGES
//---------------
//s2 CORE
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
//s2 3RD-PARTY //s2 1st-party Package Imports
// //s2 3rd-party Package Imports
//s1 DEPENDENCIES //s2 Dependancies Imports
//--------------- //s3 Routes
//s2 SERVICES //s3 Services
//s2 MODELS //s3 Models
//s2 MISC
import 'base.dart'; import 'base.dart';
import 'style.dart'; import 'models/models.exports.dart';
//s1 Exports
//!SECTION - Imports
//
//SECTION - Exports
//!SECTION - Exports
//
class AstromicLinkButton extends StatelessWidget { class AstromicLinkButton extends StatelessWidget {
//SECTION - Widget Arguments //SECTION - Widget Arguments
//s1 -- Functionality //s1 -- Functionality
final VoidCallback? onTap; final VoidCallback? onTap;
final VoidCallback? onHold; final VoidCallback? onHold;
//s1 -- Configurations //s1 -- Configurations
final bool isEnabled; final AstromicButtonConfiguration? configuration;
final TextDirection textDirection;
//s1 -- Style //s1 -- Style
final bool Function(bool isEnabled) isUnderlined; final bool Function(bool isEnabled) isUnderlined;
final EdgeInsetsGeometry? contentPadding; final EdgeInsetsGeometry? contentPadding;
@@ -45,8 +36,7 @@ class AstromicLinkButton extends StatelessWidget {
this.onTap, this.onTap,
this.onHold, this.onHold,
//s1 -- Configurations //s1 -- Configurations
required this.isEnabled, this.configuration,
required this.textDirection,
//s1 -- Style //s1 -- Style
required this.isUnderlined, required this.isUnderlined,
this.contentPadding, this.contentPadding,
@@ -76,16 +66,13 @@ class AstromicLinkButton extends StatelessWidget {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
textDirection: textDirection, textDirection: configuration?.textDirection,
children: [ children: [
AstromicButtonBase( AstromicButtonBase(
onTap: onTap, onTap: onTap,
onHold: onHold, onHold: onHold,
// //
isEnabled: isEnabled, configuration: configuration,
withFeedback: false,
withHighlightChange: false,
textDirection: textDirection,
// //
style: (isEnabled, isHighlighted) => AstromicButtonStyle( style: (isEnabled, isHighlighted) => AstromicButtonStyle(
contentPadding: contentPadding, contentPadding: contentPadding,

View File

@@ -0,0 +1,30 @@
// ignore_for_file: public_member_api_docs, sort_constructors_first
import 'package:flutter/widgets.dart';
/// Configuration model for the button element.
class AstromicButtonConfiguration {
final bool isEnabled;
final bool withFeedback;
final bool withHighlightChange;
final TextDirection textDirection;
AstromicButtonConfiguration({
required this.isEnabled,
required this.withFeedback,
required this.withHighlightChange,
required this.textDirection,
});
AstromicButtonConfiguration copyWith({
bool? isEnabled,
bool? withFeedback,
bool? withHighlightChange,
TextDirection? textDirection,
}) {
return AstromicButtonConfiguration(
isEnabled: isEnabled ?? this.isEnabled,
withFeedback: withFeedback ?? this.withFeedback,
withHighlightChange: withHighlightChange ?? this.withHighlightChange,
textDirection: textDirection ?? this.textDirection,
);
}
}

View File

@@ -0,0 +1,2 @@
export 'style.model.dart';
export 'configuration.model.dart';

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
/// Styling model for the button element.
class AstromicButtonStyle { class AstromicButtonStyle {
//s1 -- Colors //s1 -- Colors
final Color? backgroundColor; final Color? backgroundColor;
@@ -8,6 +9,7 @@ class AstromicButtonStyle {
final Color? splashColor; final Color? splashColor;
final Color? highlightColor; final Color? highlightColor;
final Color? borderColor; final Color? borderColor;
final Gradient? borderGradient;
// //
//s1 -- Spacing & Insets //s1 -- Spacing & Insets
final double? fixedHeight; final double? fixedHeight;
@@ -15,6 +17,8 @@ class AstromicButtonStyle {
final EdgeInsetsGeometry? contentPadding; final EdgeInsetsGeometry? contentPadding;
final BorderRadiusGeometry? borderRadius; final BorderRadiusGeometry? borderRadius;
final double? borderWidth; final double? borderWidth;
//s1 -- Interactions
final InteractiveInkFeatureFactory? splashFactory;
const AstromicButtonStyle({ const AstromicButtonStyle({
this.backgroundColor = Colors.transparent, this.backgroundColor = Colors.transparent,
this.backgroundGradient, this.backgroundGradient,
@@ -22,6 +26,7 @@ class AstromicButtonStyle {
this.splashColor, this.splashColor,
this.highlightColor, this.highlightColor,
this.borderColor, this.borderColor,
this.borderGradient,
// //
this.fixedHeight, this.fixedHeight,
this.fixedWidth, this.fixedWidth,
@@ -29,6 +34,8 @@ class AstromicButtonStyle {
this.borderRadius, this.borderRadius,
this.borderWidth, this.borderWidth,
// //
this.splashFactory,
//
}); });
AstromicButtonStyle copyWith({ AstromicButtonStyle copyWith({
@@ -38,11 +45,13 @@ class AstromicButtonStyle {
Color? splashColor, Color? splashColor,
Color? highlightColor, Color? highlightColor,
Color? borderColor, Color? borderColor,
Gradient? borderGradient,
double? fixedHeight, double? fixedHeight,
double? fixedWidth, double? fixedWidth,
EdgeInsetsGeometry? contentPadding, EdgeInsetsGeometry? contentPadding,
BorderRadiusGeometry? borderRadius, BorderRadiusGeometry? borderRadius,
double? borderWidth, double? borderWidth,
InteractiveInkFeatureFactory? splashFactory,
}) { }) {
return AstromicButtonStyle( return AstromicButtonStyle(
backgroundGradient: backgroundGradient ?? this.backgroundGradient, backgroundGradient: backgroundGradient ?? this.backgroundGradient,
@@ -51,11 +60,13 @@ class AstromicButtonStyle {
splashColor: splashColor ?? this.splashColor, splashColor: splashColor ?? this.splashColor,
highlightColor: highlightColor ?? this.highlightColor, highlightColor: highlightColor ?? this.highlightColor,
borderColor: borderColor ?? this.borderColor, borderColor: borderColor ?? this.borderColor,
borderGradient: borderGradient ?? this.borderGradient,
fixedHeight: fixedHeight == -1 ? null : fixedHeight ?? this.fixedHeight, fixedHeight: fixedHeight == -1 ? null : fixedHeight ?? this.fixedHeight,
fixedWidth: fixedWidth == -1 ? null : fixedWidth ?? this.fixedWidth, fixedWidth: fixedWidth == -1 ? null : fixedWidth ?? this.fixedWidth,
contentPadding: contentPadding ?? this.contentPadding, contentPadding: contentPadding ?? this.contentPadding,
borderRadius: borderRadius ?? this.borderRadius, borderRadius: borderRadius ?? this.borderRadius,
borderWidth: borderWidth ?? this.borderWidth, borderWidth: borderWidth ?? this.borderWidth,
splashFactory: splashFactory ?? this.splashFactory,
); );
} }
} }

View File

@@ -1,5 +0,0 @@
enum SizingStrategy {
hug,
fill,
fixed,
}

View File

@@ -1,24 +1,16 @@
//SECTION - Imports //s1 Imports
// //s2 Core Package Imports
//s1 PACKAGES
//---------------
//s2 CORE
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
//s2 1st-party Package Imports
//s2 3rd-party Package Imports
//s2 Dependancies Imports
//s3 Routes
//s3 Services
//s3 Models
import 'base.dart'; import 'base.dart';
//s2 3RD-PARTY import 'enums/enums.exports.dart';
// import 'models/models.exports.dart';
//s1 DEPENDENCIES //s1 Exports
//---------------
//s2 SERVICES
//s2 MODELS
import 'sizing_strategy.enum.dart';
import 'style.dart';
//s2 MISC
//!SECTION - Imports
//
//SECTION - Exports
//!SECTION - Exports
//
class AstromicStateButton extends StatefulWidget { class AstromicStateButton extends StatefulWidget {
//SECTION - Widget Arguments //SECTION - Widget Arguments
@@ -26,14 +18,11 @@ class AstromicStateButton extends StatefulWidget {
final void Function(VoidCallback start, VoidCallback stop)? onTap; final void Function(VoidCallback start, VoidCallback stop)? onTap;
final Function(VoidCallback start, VoidCallback stop)? onHold; final Function(VoidCallback start, VoidCallback stop)? onHold;
//s1 -- Configurations //s1 -- Configurations
final bool isEnabled; final AstromicButtonConfiguration? configuration;
final bool withFeedback;
final bool withHighlightChange;
final TextDirection textDirection;
//s1 -- Style //s1 -- Style
final SizingStrategy? widthSizingStrategy; final AstromicSizingStrategy? widthSizingStrategy;
final SizingStrategy? heightSizingStrategy; final AstromicSizingStrategy? heightSizingStrategy;
final InteractiveInkFeatureFactory? splashFactory;
final AstromicButtonStyle Function(bool isEnabled, bool isHighlighted, bool isLoading)? style; final AstromicButtonStyle Function(bool isEnabled, bool isHighlighted, bool isLoading)? style;
//s1 -- Content //s1 -- Content
final Widget? loadingContent; final Widget? loadingContent;
@@ -46,19 +35,15 @@ class AstromicStateButton extends StatefulWidget {
this.onTap, this.onTap,
this.onHold, this.onHold,
// //
required this.isEnabled, this.configuration,
required this.withFeedback,
required this.withHighlightChange,
required this.textDirection,
//s1 -- Style //s1 -- Style
this.widthSizingStrategy = SizingStrategy.hug, this.widthSizingStrategy = AstromicSizingStrategy.hug,
this.heightSizingStrategy = SizingStrategy.hug, this.heightSizingStrategy = AstromicSizingStrategy.hug,
this.splashFactory,
this.style, this.style,
//s1 -- Content //s1 -- Content
this.loadingContent, this.loadingContent,
required this.content, required this.content,
}) : assert(heightSizingStrategy != SizingStrategy.fill, 'Height strategy cannot be fill'); }) : assert(heightSizingStrategy != AstromicSizingStrategy.fill, 'Height strategy cannot be fill');
@override @override
State<AstromicStateButton> createState() => _AstromicStateButtonState(); State<AstromicStateButton> createState() => _AstromicStateButtonState();
@@ -106,10 +91,7 @@ class _AstromicStateButtonState extends State<AstromicStateButton> {
//s1 -Widgets //s1 -Widgets
//----- //-----
Widget baseChild = AstromicButtonBase( Widget baseChild = AstromicButtonBase(
isEnabled: widget.isEnabled, configuration: widget.configuration,
withFeedback: widget.withFeedback,
withHighlightChange: widget.withHighlightChange,
textDirection: widget.textDirection,
// //
onTap: !isLoading && context.mounted && widget.onTap != null onTap: !isLoading && context.mounted && widget.onTap != null
? () { ? () {
@@ -137,16 +119,15 @@ class _AstromicStateButtonState extends State<AstromicStateButton> {
}); });
} }
: null, : null,
splashFactory: widget.splashFactory,
style: (enabled, highlighted) => widget.style!(enabled, highlighted, isLoading).copyWith( style: (enabled, highlighted) => widget.style!(enabled, highlighted, isLoading).copyWith(
contentPadding: widget.heightSizingStrategy == SizingStrategy.fixed && widget.widthSizingStrategy == SizingStrategy.fixed contentPadding: widget.heightSizingStrategy == AstromicSizingStrategy.fixed && widget.widthSizingStrategy == AstromicSizingStrategy.fixed
? EdgeInsets.zero ? EdgeInsets.zero
: widget.heightSizingStrategy == SizingStrategy.fixed && widget.widthSizingStrategy != SizingStrategy.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, vertical: 0,
) )
: widget.widthSizingStrategy == SizingStrategy.fixed && widget.heightSizingStrategy != SizingStrategy.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, horizontal: 0,
@@ -161,18 +142,24 @@ class _AstromicStateButtonState extends State<AstromicStateButton> {
//SECTION - Build Return //SECTION - Build Return
return Row( return Row(
mainAxisSize: widget.widthSizingStrategy == SizingStrategy.hug ? MainAxisSize.min : MainAxisSize.max, mainAxisSize: widget.widthSizingStrategy == AstromicSizingStrategy.hug ? MainAxisSize.min : MainAxisSize.max,
children: [ children: [
widget.widthSizingStrategy == SizingStrategy.fill widget.widthSizingStrategy == AstromicSizingStrategy.fill
? Expanded( ? Expanded(
child: SizedBox( child: SizedBox(
height: widget.heightSizingStrategy == SizingStrategy.fixed && widget.style != null ? widget.style!(widget.isEnabled, isHighlighted, isLoading).fixedHeight : null, height: widget.heightSizingStrategy == AstromicSizingStrategy.fixed && widget.style != null
? widget.style!(widget.configuration?.isEnabled ?? true, isHighlighted, isLoading).fixedHeight
: null,
child: baseChild, child: baseChild,
), ),
) )
: SizedBox( : SizedBox(
width: widget.widthSizingStrategy == SizingStrategy.fixed && widget.style != null ? widget.style!(widget.isEnabled, isHighlighted, isLoading).fixedWidth : null, width: widget.widthSizingStrategy == AstromicSizingStrategy.fixed && widget.style != null
height: widget.heightSizingStrategy == SizingStrategy.fixed && widget.style != null ? widget.style!(widget.isEnabled, isHighlighted, isLoading).fixedHeight : null, ? widget.style!(widget.configuration?.isEnabled ?? true, isHighlighted, isLoading).fixedWidth
: null,
height: widget.heightSizingStrategy == AstromicSizingStrategy.fixed && widget.style != null
? widget.style!(widget.configuration?.isEnabled ?? true, isHighlighted, isLoading).fixedHeight
: null,
child: baseChild, child: baseChild,
), ),
], ],

View File

@@ -1,16 +1,14 @@
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
// //
import 'src/action_field.dart';
import 'src/text_field.dart'; import 'src/text_field.dart';
import 'src/configuration.dart'; import 'src/action_field.dart';
import 'src/style.dart'; import 'src/models/models.exports.dart';
// //
export 'src/configuration.dart'; export 'src/models/models.exports.dart';
export 'src/style.dart'; export 'src/enums/enums.exports.dart';
class AstromicFields { class AstromicFields {
//S1 -- Text Field /// Astromic TextField element.
static Widget text({ static Widget text({
required TextEditingController controller, required TextEditingController controller,
Key? stateKey, Key? stateKey,
@@ -18,15 +16,9 @@ class AstromicFields {
void Function(String v)? onChanged, void Function(String v)? onChanged,
void Function(String v)? onSubmited, void Function(String v)? onSubmited,
// //
required AstromicFieldConfiguration configuration, AstromicFieldConfiguration? configuration,
// //
AutovalidateMode? validatingMode, AstromicFieldStyle Function(bool isEnabled, bool isFocused)? style,
String? Function(bool isEnabled, bool isFocused, String? text)? validator,
List<TextInputFormatter>? inputFormatters,
bool? obscureText,
//
//
required AstromicFieldStyle Function(bool isEnabled, bool isFocused) style,
// //
String? hint, String? hint,
// //
@@ -44,10 +36,6 @@ class AstromicFields {
onChanged: onChanged, onChanged: onChanged,
onSubmited: onSubmited, onSubmited: onSubmited,
configuration: configuration, configuration: configuration,
validatingMode: validatingMode,
validator: validator,
inputFormatters: inputFormatters,
obscureText: obscureText,
style: style, style: style,
hint: hint, hint: hint,
prefixWidget: prefixWidget, prefixWidget: prefixWidget,
@@ -58,7 +46,7 @@ class AstromicFields {
], ],
); );
//S1 -- Action Field /// Astromic ActionField element.
static Widget action<T>( static Widget action<T>(
{Key? stateKey, {Key? stateKey,
(T item, String label)? initialValue, (T item, String label)? initialValue,
@@ -66,15 +54,13 @@ class AstromicFields {
// //
Future<(T item, String label)?> Function((T item, String label)? currentValue)? onTap, Future<(T item, String label)?> Function((T item, String label)? currentValue)? onTap,
Future<(T item, String label)?> Function((T item, String label)? currentValue)? onHold, Future<(T item, String label)?> Function((T item, String label)? currentValue)? onHold,
required String Function(String? oldValue, String newValue) textFieldMapper,
/// Map the old controller value and the new selected value to how it will look in the field. e.g Adding a new choosen value as a list in the field.
required String Function(String? oldValue, String newValue) onValueChangedMapper,
// //
required AstromicFieldConfiguration configuration, AstromicFieldConfiguration? configuration,
// //
AutovalidateMode? validatingMode, AstromicFieldStyle Function(bool isEnabled)? style,
String? Function(bool isEnabled, String? text)? validator,
List<TextInputFormatter>? inputFormatters,
//
required AstromicFieldStyle Function(bool isEnabled) style,
// //
String? hint, String? hint,
// //
@@ -89,11 +75,8 @@ class AstromicFields {
initialValue: initialValue, initialValue: initialValue,
onTap: onTap, onTap: onTap,
onHold: onHold, onHold: onHold,
textFieldMapper: textFieldMapper, onValueChangedMapper: onValueChangedMapper,
configuration: configuration, configuration: configuration,
validatingMode: validatingMode,
validator: validator,
inputFormatters: inputFormatters,
style: style, style: style,
hint: hint, hint: hint,
prefixWidget: prefixWidget, prefixWidget: prefixWidget,

View File

@@ -1,51 +1,31 @@
// ignore_for_file: depend_on_referenced_packages //s1 Imports
//SECTION - Imports //s2 Core Package Imports
//
//s1 PACKAGES
//---------------
//s2 CORE
import '../../../Infrastructure/insets_extension.dart';
import '../../../Infrastructure/misc_extensions.dart';
import '../../../astromic_mobile_elements.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; //s2 1st-party Package Imports
import 'package:intl/intl.dart' as intl; //s2 3rd-party Package Imports
import 'dart:ui' as ui; //s2 Dependancies Imports
//s3 Routes
//s3 Services
//s3 Models
import 'base.dart';
import 'models/models.exports.dart';
//s1 Exports
//s2 3RD-PARTY
//
//s1 DEPENDENCIES
//---------------
//s2 SERVICES
//s2 MODELS
//s2 MISC
//!SECTION - Imports
//
//SECTION - Exports
//!SECTION - Exports
//
class AstromicActionField<T> extends StatefulWidget { class AstromicActionField<T> extends StatefulWidget {
//SECTION - Widget Arguments //SECTION - Widget Arguments
//s1 -- Functionality //s1 -- Functionality
final Key? stateKey; final Key? stateKey;
final (T item, String label)? initialValue;
final TextEditingController textController; final TextEditingController textController;
final (T item, String label)? initialValue;
final Future<(T item, String label)?> Function((T item, String label)? currentValue)? onTap; final Future<(T item, String label)?> Function((T item, String label)? currentValue)? onTap;
final Future<(T item, String label)?> Function((T item, String label)? currentValue)? onHold; final Future<(T item, String label)?> Function((T item, String label)? currentValue)? onHold;
final String Function(String? oldValue, String newValue) textFieldMapper; final String Function(String? oldValue, String newValue) onValueChangedMapper;
// //
//s1 -- Configurations //s1 -- Configurations
final AstromicFieldConfiguration configuration; final AstromicFieldConfiguration? configuration;
//
final AutovalidateMode? validatingMode;
final String? Function(bool isEnabled, String? text)? validator;
final List<TextInputFormatter>? inputFormatters;
final bool? obscureText;
// //
//s1 -- Style //s1 -- Style
final AstromicFieldStyle Function(bool isEnabled) style; final AstromicFieldStyle Function(bool isEnabled)? style;
// //
//s1 -- Content //s1 -- Content
final String? hint; final String? hint;
@@ -61,18 +41,12 @@ class AstromicActionField<T> extends StatefulWidget {
this.initialValue, this.initialValue,
this.stateKey, this.stateKey,
required this.textController, required this.textController,
required this.textFieldMapper, required this.onValueChangedMapper,
this.onTap, this.onTap,
this.onHold, this.onHold,
// //
required this.configuration, this.configuration,
// this.style,
this.validatingMode,
this.validator,
this.inputFormatters,
this.obscureText,
//
required this.style,
// //
this.hint, this.hint,
this.prefixWidget, this.prefixWidget,
@@ -87,15 +61,14 @@ class AstromicActionField<T> extends StatefulWidget {
class _AstromicActionFieldState<T> extends State<AstromicActionField<T>> { class _AstromicActionFieldState<T> extends State<AstromicActionField<T>> {
// //
//SECTION - State Variables //SECTION - State Variables
//s1 --State
(T item, String label)? _currentValue;
//s1 --State
//
//s1 --Controllers //s1 --Controllers
late TextEditingController _textController; late TextEditingController _textController;
//s1 --Controllers //s1 --Controllers
// //
//s1 --State
(T item, String label)? _currentValue;
//
//s1 --State
//
//s1 --Constants //s1 --Constants
//s1 --Constants //s1 --Constants
//!SECTION //!SECTION
@@ -105,15 +78,15 @@ class _AstromicActionFieldState<T> extends State<AstromicActionField<T>> {
super.initState(); super.initState();
// //
//SECTION - State Variables initializations & Listeners //SECTION - State Variables initializations & Listeners
//s1 --State
//s1 --State
//
//s1 --Controllers & Listeners //s1 --Controllers & Listeners
_currentValue = widget.initialValue; _currentValue = widget.initialValue;
_textController = widget.textController; _textController = widget.textController;
_textController.text = widget.initialValue?.$2 ?? ''; _textController.text = _currentValue?.$2 ?? '';
//s1 --Controllers & Listeners //s1 --Controllers & Listeners
// //
//s1 --State
//s1 --State
//
//s1 --Late & Async Initializers //s1 --Late & Async Initializers
//s1 --Late & Async Initializers //s1 --Late & Async Initializers
//!SECTION //!SECTION
@@ -126,6 +99,10 @@ class _AstromicActionFieldState<T> extends State<AstromicActionField<T>> {
//SECTION - State Variables initializations & Listeners //SECTION - State Variables initializations & Listeners
//s1 --State //s1 --State
//s1 --State //s1 --State
//
//s1 --Controllers & Listeners
//s1 --Controllers & Listeners
//
//!SECTION //!SECTION
} }
@@ -133,81 +110,6 @@ class _AstromicActionFieldState<T> extends State<AstromicActionField<T>> {
//!SECTION //!SECTION
//SECTION - Stateless functions //SECTION - Stateless functions
getTextHeight(String text, TextStyle style, ui.TextDirection direction) {
final span = TextSpan(text: text, style: style);
final tp = TextPainter(text: span, textDirection: direction);
tp.layout(maxWidth: double.infinity);
return tp.height;
}
//-
//----------------------------------------------------------------
//-
ui.TextDirection finalTextDirection() {
ui.TextDirection fromLocale = intl.Bidi.isRtlLanguage(Localizations.localeOf(context).languageCode) ? ui.TextDirection.rtl : ui.TextDirection.ltr;
//
if (widget.configuration.textDirection != null) {
// Get form Style
return widget.configuration.textDirection!;
} else {
// Detect form Text
return _textController.text != ''
? widget.configuration.withAutomaticDirectionalitySwitching
? intl.Bidi.startsWithLtr(_textController.text)
? ui.TextDirection.ltr
: ui.TextDirection.rtl
: fromLocale
: fromLocale;
}
}
//-
//----------------------------------------------------------------
//-
EdgeInsetsGeometry finalVerticalPadding(
AstromicFieldStyle style, {
bool forceRespectBorder = false,
}) {
double desiredFixedHeight = style.fixedHeight ?? 0;
//
double providedPadding = style.contentPadding.vertical;
//
double borderOffset = widget.configuration.respectBorderWidthPadding || forceRespectBorder ? style.border?.borderSide.strokeInset ?? 0.0 : 0.0;
//
double fontOffset = getTextHeight(
widget.textController.text.isNotEmpty
? widget.textController.text
: (widget.hint?.isNotEmpty ?? false)
? widget.hint!
: "",
widget.textController.text.isNotEmpty && widget.style(widget.configuration.isEnabled).textStyle != null
? widget.style(widget.configuration.isEnabled).textStyle!
: widget.style(widget.configuration.isEnabled).hintStyle != null
? widget.style(widget.configuration.isEnabled).hintStyle!
: const TextStyle(),
finalTextDirection(),
);
//
double finalVertical =
//-
widget.configuration.isFixedHeight
?
//-
widget.configuration.isTextArea
?
//s1 Fixed Height with Text Area
borderOffset + providedPadding
:
//s1 Fixed Height and not Text Area
desiredFixedHeight - (fontOffset + borderOffset)
//s1 - Not Fixed Height
: providedPadding + (borderOffset / 2);
//
return EdgeInsets.symmetric(
vertical: finalVertical / 2,
);
}
//!SECTION //!SECTION
//SECTION - Action Callbacks //SECTION - Action Callbacks
@@ -222,147 +124,26 @@ class _AstromicActionFieldState<T> extends State<AstromicActionField<T>> {
//s1 --Values //s1 --Values
// //
//s1 --Contexted Widgets //s1 --Contexted Widgets
InputDecoration inputDecoration = InputDecoration(
//s1 -- Functionality
enabled: widget.configuration.isEnabled,
//s1 -- Configurations
isDense: true,
hintTextDirection: widget.configuration.hintDirection ?? finalTextDirection(),
//s1 -- Style
filled: widget.style(widget.configuration.isEnabled).isFilled,
fillColor: widget.style(widget.configuration.isEnabled).fillColor,
//
hintStyle: widget.style(widget.configuration.isEnabled).hintStyle,
//
enabledBorder: widget.style(widget.configuration.isEnabled).border,
focusedBorder: widget.style(widget.configuration.isEnabled).border,
disabledBorder: widget.style(widget.configuration.isEnabled).border,
errorBorder: widget.style(widget.configuration.isEnabled).border,
focusedErrorBorder: widget.style(widget.configuration.isEnabled).border,
//
errorStyle: const TextStyle(height: 0),
contentPadding: finalVerticalPadding(widget.style(widget.configuration.isEnabled)),
//s1 -- Content
hintText: widget.hint,
//
prefixIcon: widget.prefixWidget != null &&
widget.prefixWidget!(widget.configuration.isEnabled, () {
setState(() {});
}) !=
null
? Container(
margin: EdgeInsetsDirectional.fromSTEB(
widget.style(widget.configuration.isEnabled).prefixSpacing, 0, widget.style(widget.configuration.isEnabled).contentPadding.resolveToDirectional(finalTextDirection()).start, 0),
child: widget.prefixWidget!(widget.configuration.isEnabled, () {
setState(() {});
}),
)
: SizedBox(width: widget.style(widget.configuration.isEnabled).contentPadding.resolveToDirectional(finalTextDirection()).start),
//
prefixIconConstraints: widget.prefixWidget != null &&
widget.prefixWidget!(widget.configuration.isEnabled, () {
setState(() {});
}) !=
null
? widget.style(widget.configuration.isEnabled).prefixSize != 0
? BoxConstraints.expand(
width: widget.style(widget.configuration.isEnabled).prefixSize +
widget.style(widget.configuration.isEnabled).prefixSpacing +
widget.style(widget.configuration.isEnabled).contentPadding.resolveToDirectional(finalTextDirection()).start,
height: widget.style(widget.configuration.isEnabled).prefixSize,
)
: const BoxConstraints.tightForFinite()
: BoxConstraints.tightForFinite(width: widget.style(widget.configuration.isEnabled).contentPadding.resolveToDirectional(finalTextDirection()).start),
//
suffixIcon: widget.suffixWidget != null &&
widget.suffixWidget!(widget.configuration.isEnabled, () {
setState(() {});
}) !=
null
? Container(
margin: EdgeInsetsDirectional.fromSTEB(
widget.style(widget.configuration.isEnabled).contentPadding.resolveToDirectional(finalTextDirection()).end, 0, widget.style(widget.configuration.isEnabled).suffixSpacing, 0),
child: widget.suffixWidget!(widget.configuration.isEnabled, () {
setState(() {});
}),
)
: SizedBox(width: widget.style(widget.configuration.isEnabled).contentPadding.resolveToDirectional(finalTextDirection()).end),
suffixIconConstraints: widget.suffixWidget != null &&
widget.suffixWidget != null &&
widget.suffixWidget!(widget.configuration.isEnabled, () {
setState(() {});
}) !=
null
? widget.style(widget.configuration.isEnabled).suffixSize != 0
? BoxConstraints.expand(
width: widget.style(widget.configuration.isEnabled).suffixSize +
widget.style(widget.configuration.isEnabled).suffixSpacing +
widget.style(widget.configuration.isEnabled).contentPadding.resolveToDirectional(finalTextDirection()).end,
height: widget.style(widget.configuration.isEnabled).suffixSize,
)
: const BoxConstraints.tightForFinite()
: BoxConstraints.tightForFinite(width: widget.style(widget.configuration.isEnabled).contentPadding.resolveToDirectional(finalTextDirection()).end),
);
//s1 --Contexted Widgets //s1 --Contexted Widgets
//!SECTION //!SECTION
//
//SECTION - Build Return
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Directionality(
textDirection: finalTextDirection(),
child: Container(
height: widget.configuration.isFixedHeight
? !widget.configuration.isTextArea
? null
: widget.style(widget.configuration.isEnabled).fixedHeight
: null,
alignment: widget.style(widget.configuration.isEnabled).textAlignVertical.toAlignment(),
child: Stack(
children: [
TextFormField(
//s1 -- Functionality
key: widget.stateKey,
controller: _textController,
textInputAction: widget.configuration.inputAction,
//
//s1 -- Configurations
autovalidateMode: widget.validatingMode,
autofocus: widget.configuration.withAutofocus,
keyboardType: widget.configuration.inputType,
textDirection: finalTextDirection(),
obscureText: widget.configuration.withObscurity ? (widget.obscureText ?? false) : false,
inputFormatters: widget.inputFormatters,
//
minLines: widget.configuration.isFixedHeight && widget.configuration.isTextArea ? null : widget.style(widget.configuration.isEnabled).minLines,
maxLines: widget.configuration.isFixedHeight
? widget.configuration.isTextArea
? null
: widget.style(widget.configuration.isEnabled).maxLines
: widget.style(widget.configuration.isEnabled).maxLines,
// //SECTION - Build Return
maxLength: widget.style(widget.configuration.isEnabled).maxLength,
maxLengthEnforcement: widget.configuration.maxLengthEnforcement, return AstromicFieldBase(
// key: widget.key,
expands: widget.configuration.isFixedHeight && widget.configuration.isTextArea ? true : false, textController: _textController,
// - Validation stateKey: widget.stateKey,
validator: widget.validator != null ? (s) => widget.validator!(widget.configuration.isEnabled, s) : null, // onChanged: (v) {},
// - Validation // onSubmited: (v) {},
//s1 -- Style configuration: widget.configuration,
style: widget.style(widget.configuration.isEnabled).textStyle, style: widget.style == null ? null : (enabled, focused) => widget.style!(enabled),
cursorColor: widget.style(widget.configuration.isEnabled).cursorColor, hint: widget.hint,
textAlign: widget.style(widget.configuration.isEnabled).textAlign, prefixWidget: widget.prefixWidget == null ? null : (enabled, focused, stateSetter) => widget.prefixWidget!(enabled, stateSetter),
textAlignVertical: widget.style(widget.configuration.isEnabled).textAlignVertical, suffixWidget: widget.suffixWidget == null ? null : (enabled, focused, stateSetter) => widget.suffixWidget!(enabled, stateSetter),
// messageBuilder: widget.messageBuilder == null ? null : (enabled, focused) => widget.messageBuilder!(enabled),
//s1 -- Input Decoration fieldStackedWidget: (finalHeight, border) => SizedBox(
decoration: inputDecoration,
),
SizedBox(
width: double.infinity, width: double.infinity,
height: finalVerticalPadding(widget.style(widget.configuration.isEnabled), forceRespectBorder: true).vertical * 2, height: finalHeight,
child: Material( child: Material(
type: MaterialType.transparency, type: MaterialType.transparency,
child: InkWell( child: InkWell(
@@ -373,7 +154,7 @@ class _AstromicActionFieldState<T> extends State<AstromicActionField<T>> {
if (newValue != null) { if (newValue != null) {
setState(() { setState(() {
_currentValue = newValue; _currentValue = newValue;
_textController.text = widget.textFieldMapper(c?.$2, newValue.$2); _textController.text = widget.onValueChangedMapper(c?.$2, newValue.$2);
}); });
} }
} }
@@ -386,31 +167,16 @@ class _AstromicActionFieldState<T> extends State<AstromicActionField<T>> {
if (newValue != null) { if (newValue != null) {
setState(() { setState(() {
_currentValue = newValue; _currentValue = newValue;
_textController.text = widget.textFieldMapper(c?.$2, newValue.$2); _textController.text = widget.onValueChangedMapper(c?.$2, newValue.$2);
}); });
} }
} }
}, },
customBorder: widget.style(widget.configuration.isEnabled).border, customBorder: border,
highlightColor: Colors.transparent, highlightColor: Colors.transparent,
), ),
), ),
)
],
), ),
),
),
widget.messageBuilder != null &&
widget.messageBuilder!(
widget.configuration.isEnabled,
) !=
null
? Padding(
padding: widget.style(widget.configuration.isEnabled).messagePadding,
child: widget.messageBuilder!(widget.configuration.isEnabled) ?? Container(),
)
: Container()
],
); );
//!SECTION //!SECTION
} }

View File

@@ -0,0 +1,450 @@
//s1 Imports
//s2 Core Package Imports
import 'package:flutter/material.dart';
import 'package:intl/intl.dart' as intl;
import 'dart:ui' as ui;
//s2 1st-party Package Imports
import 'package:astromic_extensions/astromic_extensions.dart';
//s2 3rd-party Package Imports
//s2 Dependancies Imports
//s3 Routes
//s3 Services
//s3 Models
import '../../../Dependencies/gradient_border/gradient_borders.dart';
import '../../../Dependencies/gradient_border/input_borders/gradient_underline_input_border.dart';
import 'enums/enums.exports.dart';
import 'models/models.exports.dart';
//s1 Exports
class AstromicFieldBase extends StatefulWidget {
//SECTION - Widget Arguments
//s1 -- Functionality
final TextEditingController textController;
final Key? stateKey;
//
final void Function(String v)? onChanged;
final void Function(String v)? onSubmited;
//
//s1 -- Configurations
final AstromicFieldConfiguration? configuration;
//
//s1 -- Style
final AstromicFieldStyle Function(bool isEnabled, bool isFocused)? style;
//
//s1 -- Content
final Widget Function(double finalHeight, ShapeBorder? border)? fieldStackedWidget;
final String? hint;
//
final Widget? Function(bool isEnabled, bool isFocused, VoidCallback stateSetter)? prefixWidget;
final Widget? Function(bool isEnabled, bool isFocused, VoidCallback stateSetter)? suffixWidget;
final Widget? Function(bool isEnabled, bool isFocused)? messageBuilder;
//
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
State<AstromicFieldBase> createState() => _AstromicFieldBaseState();
}
class _AstromicFieldBaseState extends State<AstromicFieldBase> {
//
//SECTION - State Variables
//s1 --Controllers
late TextEditingController _textController;
//s1 --Controllers
//
//s1 --State
// late bool widget.configuration.isEnabled;
final FocusNode _focusNode = FocusNode();
late bool _isFocused;
//
late AstromicFieldStyle Function([bool isFocused]) _style;
late AstromicFieldConfiguration _config;
//
//s1 --State
//
//s1 --Constants
//s1 --Constants
//!SECTION
@override
void initState() {
super.initState();
//
//SECTION - State Variables initializations & Listeners
//s1 --Controllers & Listeners
_textController = widget.textController;
//s1 --Controllers & Listeners
//
//s1 --State
// widget.configuration.isEnabled = widget.configuration.isEnabled;
_isFocused = false;
//s1 --State
//
//s1 --Late & Async Initializers
//s1 --Late & Async Initializers
//!SECTION
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
//
//SECTION - State Variables initializations & Listeners
//s1 --State
_focusNode.addListener(() {
if (mounted) {
setState(() {
_isFocused = _focusNode.hasFocus;
});
}
});
//s1 --State
//!SECTION
}
//SECTION - Dumb Widgets
//!SECTION
//SECTION - Stateless functions
_getTextHeight(String text, TextStyle style, ui.TextDirection direction) {
final span = TextSpan(text: text, style: style);
final tp = TextPainter(text: span, textDirection: direction);
tp.layout(maxWidth: double.infinity);
return tp.height;
}
ui.TextDirection _finalTextDirection() {
ui.TextDirection fromLocale = intl.Bidi.isRtlLanguage(Localizations.localeOf(context).languageCode) ? ui.TextDirection.rtl : ui.TextDirection.ltr;
//
if (_config.textDirection != null) {
// Get form Style
return _config.textDirection!;
} else {
// Detect form Text
return _textController.text != ''
? _config.withAutomaticDirectionalitySwitching
? intl.Bidi.startsWithLtr(_textController.text)
? ui.TextDirection.ltr
: ui.TextDirection.rtl
: fromLocale
: fromLocale;
}
}
EdgeInsetsGeometry _finalVerticalPadding(
AstromicFieldStyle style, {
bool? forceRespectBorder,
}) {
double desiredFixedHeight = style.fixedHeight ?? 0;
//
double providedPadding = style.contentPadding.vertical;
//
double borderOffset = (forceRespectBorder ?? _config.respectBorderWidthPadding) ? _finalBorderShape(style)?.borderSide.strokeInset ?? 0.0 : 0.0;
//
double fontOffset = _getTextHeight(
widget.textController.text.isNotEmpty
? widget.textController.text
: (widget.hint?.isNotEmpty ?? false)
? widget.hint!
: "",
widget.textController.text.isNotEmpty && _style().textStyle != null
? _style().textStyle!
: _style().hintStyle != null
? _style().hintStyle!
: const TextStyle(),
_finalTextDirection(),
);
//
double finalVertical =
//-
_config.isFixedHeight
?
//-
_config.isTextArea
?
//s1 Fixed Height with Text Area
borderOffset + providedPadding
:
//s1 Fixed Height and not Text Area
desiredFixedHeight - (fontOffset + borderOffset)
//s1 - Not Fixed Height
: providedPadding + borderOffset;
//
return EdgeInsets.symmetric(
vertical: finalVertical / 2,
);
}
InputBorder? _finalBorderShape(AstromicFieldStyle style) {
InputBorder defaultBorder = const UnderlineInputBorder(borderSide: BorderSide(color: Colors.grey, width: 2));
switch (style.borderType) {
case AstromicFieldBorderType.cusotm:
return style.customBorder ?? defaultBorder;
case AstromicFieldBorderType.outlined:
return style.borderGradient != null
? GradientOutlineInputBorder(
gradient: style.borderGradient!,
gapPadding: 0,
width: style.borderWidth ?? 2.0,
borderRadius: style.borderRadius?.resolve(
_config.textDirection,
) ??
BorderRadius.circular(0))
: OutlineInputBorder(
borderSide: BorderSide(color: style.borderColor ?? Colors.grey, width: style.borderWidth ?? 2.0, style: BorderStyle.solid),
borderRadius: style.borderRadius?.resolve(
_config.textDirection,
) ??
BorderRadius.circular(0));
case AstromicFieldBorderType.underlined:
return style.borderGradient != null
? GradientUnderlineInputBorder(
gradient: style.borderGradient!,
gapPadding: 0,
width: style.borderWidth ?? 2.0,
borderRadius: style.borderRadius?.resolve(
_config.textDirection,
) ??
BorderRadius.circular(0))
: UnderlineInputBorder(
borderSide: BorderSide(color: style.borderColor ?? Colors.grey, width: style.borderWidth ?? 2.0, style: BorderStyle.solid),
borderRadius: style.borderRadius?.resolve(
_config.textDirection,
) ??
BorderRadius.circular(0));
}
}
//!SECTION
//SECTION - Action Callbacks
//!SECTION
@override
Widget build(BuildContext context) {
//SECTION - Build Setup
//s1 --Values
//double w = MediaQuery.of(context).size.width;
//double h = MediaQuery.of(context).size.height;
_config = widget.configuration ?? const AstromicFieldConfiguration();
_style = ([bool? isFocused]) => widget.style?.call(_config.isEnabled, isFocused ?? _isFocused) ?? const AstromicFieldStyle();
//s1 --Values
//
//s1 --Contexted Widgets
InputDecoration inputDecoration = InputDecoration(
//s1 -- Functionality
enabled: _config.isEnabled,
//s1 -- Configurations
isDense: true,
hintTextDirection: _config.hintDirection ?? _finalTextDirection(),
//s1 -- Style
filled: _style().isFilled,
fillColor: _style().fillColor,
//
hintStyle: _style().hintStyle,
//
enabledBorder: _finalBorderShape(_style(false)),
focusedBorder: _finalBorderShape(_style(true)),
disabledBorder: _finalBorderShape(_style()),
errorBorder: _finalBorderShape(_style(false)),
focusedErrorBorder: _finalBorderShape(_style(true)),
//
errorStyle: const TextStyle(height: 0),
contentPadding: _finalVerticalPadding(_style()),
//s1 -- Content
hintText: widget.hint,
//
prefixIcon: widget.prefixWidget != null &&
widget.prefixWidget!(_config.isEnabled, _isFocused, () {
setState(() {});
}) !=
null
? Container(
margin: EdgeInsetsDirectional.fromSTEB(_style().prefixSpacing, 0, _style().contentPadding.resolveToDirectional(_finalTextDirection()).start, 0),
child: widget.prefixWidget!(_config.isEnabled, _isFocused, () {
setState(() {});
}),
)
: SizedBox(width: _style().contentPadding.resolveToDirectional(_finalTextDirection()).start),
//
prefixIconConstraints: widget.prefixWidget != null &&
widget.prefixWidget!(_config.isEnabled, _isFocused, () {
setState(() {});
}) !=
null
? _style().prefixSize != 0
? BoxConstraints.expand(
width: _style().prefixSize + _style().prefixSpacing + _style().contentPadding.resolveToDirectional(_finalTextDirection()).start,
height: _style().prefixSize,
)
: const BoxConstraints.tightForFinite()
: BoxConstraints.tightForFinite(width: _style().contentPadding.resolveToDirectional(_finalTextDirection()).start),
//
suffixIcon: widget.suffixWidget != null &&
widget.suffixWidget!(_config.isEnabled, _isFocused, () {
setState(() {});
}) !=
null
? Container(
margin: EdgeInsetsDirectional.fromSTEB(_style().contentPadding.resolveToDirectional(_finalTextDirection()).end, 0, _style().suffixSpacing, 0),
child: widget.suffixWidget!(_config.isEnabled, _isFocused, () {
setState(() {});
}),
)
: SizedBox(width: _style().contentPadding.resolveToDirectional(_finalTextDirection()).end),
suffixIconConstraints: widget.suffixWidget != null &&
widget.suffixWidget != null &&
widget.suffixWidget!(_config.isEnabled, _isFocused, () {
setState(() {});
}) !=
null
? _style().suffixSize != 0
? BoxConstraints.expand(
width: _style().suffixSize + _style().suffixSpacing + _style().contentPadding.resolveToDirectional(_finalTextDirection()).end,
height: _style().suffixSize,
)
: const BoxConstraints.tightForFinite()
: BoxConstraints.tightForFinite(width: _style().contentPadding.resolveToDirectional(_finalTextDirection()).end),
);
//s1 --Contexted Widgets
//!SECTION
//
//SECTION - Build Return
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Directionality(
textDirection: _finalTextDirection(),
child: Container(
height: _config.isFixedHeight
? !_config.isTextArea
? null
: _style().fixedHeight
: null,
alignment: _style().textAlignVertical.toAlignment(),
child: Stack(
children: [
TextFormField(
//s1 -- Functionality
key: widget.stateKey,
controller: _textController,
focusNode: _focusNode,
textInputAction: _config.inputAction,
//
onChanged: (v) {
setState(() {
if (widget.onChanged != null) {
widget.onChanged!(v);
}
});
},
//
onFieldSubmitted: (v) {
//
if (_config.inputAction == TextInputAction.next) {
_focusNode.nextFocus();
}
if (widget.onSubmited != null) {
widget.onSubmited!(v);
}
},
//
onTapOutside: (tapEvent) {
if (_config.unfocusOnTapOutside) {
_focusNode.unfocus();
}
},
//
//s1 -- Configurations
autovalidateMode: _config.validatingMode,
autofocus: _config.withAutofocus,
keyboardType: _config.inputType,
textDirection: _finalTextDirection(),
obscureText: _config.withObscurity ? (_config.isTextObscured ?? false) : false,
inputFormatters: _config.inputFormatters,
//
minLines: _config.isFixedHeight && _config.isTextArea ? null : _style().minLines,
maxLines: _config.isFixedHeight
? _config.isTextArea
? null
: _style().maxLines
: _style().maxLines,
//
maxLength: _style().maxLength,
maxLengthEnforcement: _config.maxLengthEnforcement,
//
expands: _config.isFixedHeight && _config.isTextArea ? true : false,
// - Validation
validator: _config.validator != null ? (s) => _config.validator!(_config.isEnabled, _isFocused, s) : null,
// - Validation
//s1 -- Style
style: _style().textStyle,
cursorColor: _style().cursorColor,
textAlign: _style().textAlign,
textAlignVertical: _style().textAlignVertical,
//
//s1 -- Input Decoration
decoration: inputDecoration,
//s1 -- Content
contextMenuBuilder: (_, state) {
List<ContextMenuButtonItem> baseContextButtons = state.contextMenuButtonItems;
if (widget.contextButtons != null) {
baseContextButtons.addAll(widget.contextButtons!);
}
return AdaptiveTextSelectionToolbar.buttonItems(
buttonItems: baseContextButtons,
anchors: state.contextMenuAnchors,
);
},
),
widget.fieldStackedWidget != null ? widget.fieldStackedWidget!(_finalVerticalPadding(_style(), forceRespectBorder: true).vertical * 2, _finalBorderShape(_style())) : Container(),
],
),
),
),
widget.messageBuilder != null &&
widget.messageBuilder!(
_config.isEnabled,
_isFocused,
) !=
null
? Padding(
padding: _style().messagePadding,
child: widget.messageBuilder!(_config.isEnabled, _isFocused) ?? Container(),
)
: Container()
],
);
//!SECTION
}
@override
void dispose() {
//SECTION - Disposable variables
//!SECTION
super.dispose();
}
}

View File

@@ -0,0 +1,5 @@
enum AstromicFieldBorderType {
outlined,
underlined,
cusotm,
}

View File

@@ -0,0 +1 @@
export './border_type.enum.dart';

View File

@@ -1,11 +1,13 @@
// ignore_for_file: public_member_api_docs, sort_constructors_first
import 'dart:ui' as ui; import 'dart:ui' as ui;
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.
class AstromicFieldConfiguration { class AstromicFieldConfiguration {
// //
final bool isEnabled; final bool isEnabled;
final bool? isTextObscured;
final bool isFixedHeight; final bool isFixedHeight;
final bool isTextArea; final bool isTextArea;
// //
@@ -24,8 +26,13 @@ class AstromicFieldConfiguration {
// //
final MaxLengthEnforcement maxLengthEnforcement; 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,
this.isTextObscured = false,
this.respectBorderWidthPadding = false, this.respectBorderWidthPadding = false,
this.isFixedHeight = false, this.isFixedHeight = false,
this.isTextArea = false, this.isTextArea = false,
@@ -41,11 +48,17 @@ class AstromicFieldConfiguration {
this.inputType = TextInputType.text, this.inputType = TextInputType.text,
this.inputAction = TextInputAction.done, this.inputAction = TextInputAction.done,
this.maxLengthEnforcement = MaxLengthEnforcement.none, this.maxLengthEnforcement = MaxLengthEnforcement.none,
//
this.validatingMode,
this.validator,
this.inputFormatters,
//
}); });
// //
AstromicFieldConfiguration copyWith({ AstromicFieldConfiguration copyWith({
bool? isEnabled, bool? isEnabled,
bool? isTextObscured,
bool? isFixedHeight, bool? isFixedHeight,
bool? isTextArea, bool? isTextArea,
bool? withAutofocus, bool? withAutofocus,
@@ -60,9 +73,13 @@ class AstromicFieldConfiguration {
TextInputAction? inputAction, TextInputAction? inputAction,
TextCapitalization? capitalizationMode, TextCapitalization? capitalizationMode,
MaxLengthEnforcement? maxLengthEnforcement, MaxLengthEnforcement? maxLengthEnforcement,
AutovalidateMode? validatingMode,
String? Function(bool isEnabled, bool isFocused, String? text)? validator,
List<TextInputFormatter>? inputFormatters,
}) { }) {
return AstromicFieldConfiguration( return AstromicFieldConfiguration(
isEnabled: isEnabled ?? this.isEnabled, isEnabled: isEnabled ?? this.isEnabled,
isTextObscured: isTextObscured ?? this.isTextObscured,
isFixedHeight: isFixedHeight ?? this.isFixedHeight, isFixedHeight: isFixedHeight ?? this.isFixedHeight,
isTextArea: isTextArea ?? this.isTextArea, isTextArea: isTextArea ?? this.isTextArea,
withAutofocus: withAutofocus ?? this.withAutofocus, withAutofocus: withAutofocus ?? this.withAutofocus,
@@ -76,6 +93,9 @@ class AstromicFieldConfiguration {
inputType: inputType ?? this.inputType, inputType: inputType ?? this.inputType,
inputAction: inputAction ?? this.inputAction, inputAction: inputAction ?? this.inputAction,
maxLengthEnforcement: maxLengthEnforcement ?? this.maxLengthEnforcement, maxLengthEnforcement: maxLengthEnforcement ?? this.maxLengthEnforcement,
validatingMode: validatingMode ?? this.validatingMode,
validator: validator ?? this.validator,
inputFormatters: inputFormatters ?? this.inputFormatters,
); );
} }
} }

View File

@@ -0,0 +1,2 @@
export './style.model.dart';
export './configuration.model.dart';

View File

@@ -1,6 +1,7 @@
// ignore_for_file: public_member_api_docs, sort_constructors_first
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../enums/border_type.enum.dart';
/// Styling model for the field element.
class AstromicFieldStyle { class AstromicFieldStyle {
//s1 - Styling Configs //s1 - Styling Configs
final bool isFilled; final bool isFilled;
@@ -16,6 +17,11 @@ class AstromicFieldStyle {
/// Only works when it's a Text Area. /// Only works when it's a Text Area.
final TextAlignVertical textAlignVertical; final TextAlignVertical textAlignVertical;
// //
final BorderRadiusGeometry? borderRadius;
final double? borderWidth;
final AstromicFieldBorderType borderType;
final InputBorder? customBorder;
//
final EdgeInsetsGeometry contentPadding; final EdgeInsetsGeometry contentPadding;
final EdgeInsetsGeometry messagePadding; final EdgeInsetsGeometry messagePadding;
// //
@@ -27,11 +33,11 @@ class AstromicFieldStyle {
//s1 - Colors //s1 - Colors
final Color fillColor; final Color fillColor;
final Color? cursorColor; final Color? cursorColor;
final Color? borderColor;
final Gradient? borderGradient;
//s1 - Styling //s1 - Styling
final TextStyle? hintStyle; final TextStyle? hintStyle;
final TextStyle? textStyle; final TextStyle? textStyle;
//s1 - MISC
final InputBorder? border;
const AstromicFieldStyle({ const AstromicFieldStyle({
this.isFilled = true, this.isFilled = true,
@@ -43,6 +49,12 @@ class AstromicFieldStyle {
this.textAlignVertical = TextAlignVertical.center, this.textAlignVertical = TextAlignVertical.center,
// //
this.fixedHeight, this.fixedHeight,
//
this.borderRadius,
this.borderWidth,
this.borderType = AstromicFieldBorderType.underlined,
this.customBorder,
//
this.contentPadding = EdgeInsets.zero, this.contentPadding = EdgeInsets.zero,
this.messagePadding = EdgeInsets.zero, this.messagePadding = EdgeInsets.zero,
this.prefixSpacing = 4, this.prefixSpacing = 4,
@@ -51,11 +63,11 @@ class AstromicFieldStyle {
this.suffixSize = 24, this.suffixSize = 24,
// //
this.fillColor = const Color(0xffffffff), this.fillColor = const Color(0xffffffff),
this.borderColor,
this.borderGradient,
this.cursorColor, this.cursorColor,
this.hintStyle, this.hintStyle,
this.textStyle, this.textStyle,
//
this.border,
}); });
// //
AstromicFieldStyle copyWith({ AstromicFieldStyle copyWith({
@@ -66,6 +78,10 @@ class AstromicFieldStyle {
int? maxLength, int? maxLength,
TextAlign? textAlign, TextAlign? textAlign,
TextAlignVertical? textAlignVertical, TextAlignVertical? textAlignVertical,
BorderRadiusGeometry? borderRadius,
double? borderWidth,
AstromicFieldBorderType? borderType,
InputBorder? customBorder,
EdgeInsetsGeometry? contentPadding, EdgeInsetsGeometry? contentPadding,
EdgeInsetsGeometry? messagePadding, EdgeInsetsGeometry? messagePadding,
double? prefixSpacing, double? prefixSpacing,
@@ -76,9 +92,10 @@ class AstromicFieldStyle {
CrossAxisAlignment? suffixAlignment, CrossAxisAlignment? suffixAlignment,
Color? fillColor, Color? fillColor,
Color? cursorColor, Color? cursorColor,
Color? borderColor,
Gradient? borderGradient,
TextStyle? hintStyle, TextStyle? hintStyle,
TextStyle? textStyle, TextStyle? textStyle,
InputBorder? border,
}) { }) {
return AstromicFieldStyle( return AstromicFieldStyle(
isFilled: isFilled ?? this.isFilled, isFilled: isFilled ?? this.isFilled,
@@ -88,6 +105,10 @@ class AstromicFieldStyle {
maxLength: maxLength ?? this.maxLength, maxLength: maxLength ?? this.maxLength,
textAlign: textAlign ?? this.textAlign, textAlign: textAlign ?? this.textAlign,
textAlignVertical: textAlignVertical ?? this.textAlignVertical, textAlignVertical: textAlignVertical ?? this.textAlignVertical,
borderRadius: borderRadius ?? this.borderRadius,
borderWidth: borderWidth ?? this.borderWidth,
borderType: borderType ?? this.borderType,
customBorder: customBorder ?? this.customBorder,
contentPadding: contentPadding ?? this.contentPadding, contentPadding: contentPadding ?? this.contentPadding,
messagePadding: messagePadding ?? this.messagePadding, messagePadding: messagePadding ?? this.messagePadding,
prefixSpacing: prefixSpacing ?? this.prefixSpacing, prefixSpacing: prefixSpacing ?? this.prefixSpacing,
@@ -96,9 +117,10 @@ class AstromicFieldStyle {
suffixSize: suffixSize ?? this.suffixSize, suffixSize: suffixSize ?? this.suffixSize,
fillColor: fillColor ?? this.fillColor, fillColor: fillColor ?? this.fillColor,
cursorColor: cursorColor ?? this.cursorColor, cursorColor: cursorColor ?? this.cursorColor,
borderColor: borderColor ?? this.borderColor,
borderGradient: borderGradient ?? this.borderGradient,
hintStyle: hintStyle ?? this.hintStyle, hintStyle: hintStyle ?? this.hintStyle,
textStyle: textStyle ?? this.textStyle, textStyle: textStyle ?? this.textStyle,
border: border ?? this.border,
); );
} }
// //

View File

@@ -1,32 +1,17 @@
// ignore_for_file: depend_on_referenced_packages //s1 Imports
//SECTION - Imports //s2 Core Package Imports
//
//s1 PACKAGES
//---------------
//s2 CORE
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; //s2 1st-party Package Imports
import 'package:intl/intl.dart' as intl; //s2 3rd-party Package Imports
import 'dart:ui' as ui; //s2 Dependancies Imports
//s3 Routes
//s3 Services
//s3 Models
import 'base.dart';
import 'models/models.exports.dart';
//s1 Exports
//s2 3RD-PARTY class AstromicTextField extends StatelessWidget {
//
//s1 DEPENDENCIES
//---------------
//s2 SERVICES
//s2 MODELS
import 'configuration.dart';
import 'style.dart';
//s2 MISC
import '../../../Infrastructure/insets_extension.dart';
import '../../../Infrastructure/misc_extensions.dart';
//!SECTION - Imports
//
//SECTION - Exports
//!SECTION - Exports
//
class AstromicTextField extends StatefulWidget {
//SECTION - Widget Arguments //SECTION - Widget Arguments
//s1 -- Functionality //s1 -- Functionality
final TextEditingController textController; final TextEditingController textController;
@@ -36,15 +21,10 @@ class AstromicTextField extends StatefulWidget {
final void Function(String v)? onSubmited; final void Function(String v)? onSubmited;
// //
//s1 -- Configurations //s1 -- Configurations
final AstromicFieldConfiguration configuration; final AstromicFieldConfiguration? configuration;
//
final AutovalidateMode? validatingMode;
final String? Function(bool isEnabled, bool isFocused, String? text)? validator;
final List<TextInputFormatter>? inputFormatters;
final bool? obscureText;
// //
//s1 -- Style //s1 -- Style
final AstromicFieldStyle Function(bool isEnabled, bool isFocused) style; final AstromicFieldStyle Function(bool isEnabled, bool isFocused)? style;
// //
//s1 -- Content //s1 -- Content
final String? hint; final String? hint;
@@ -64,14 +44,9 @@ class AstromicTextField extends StatefulWidget {
this.onChanged, this.onChanged,
this.onSubmited, this.onSubmited,
// //
required this.configuration, this.configuration,
// //
this.validatingMode, this.style,
this.validator,
this.inputFormatters,
this.obscureText,
//
required this.style,
// //
this.hint, this.hint,
this.prefixWidget, this.prefixWidget,
@@ -80,350 +55,33 @@ class AstromicTextField extends StatefulWidget {
this.contextButtons, this.contextButtons,
}); });
@override
State<AstromicTextField> createState() => _AstromicTextFieldState();
}
class _AstromicTextFieldState extends State<AstromicTextField> {
//
//SECTION - State Variables
//s1 --Controllers
late TextEditingController _textController;
//s1 --Controllers
//
//s1 --State
// late bool widget.configuration.isEnabled;
final FocusNode _focusNode = FocusNode();
late bool _isFocused;
//
//s1 --State
//
//s1 --Constants
//s1 --Constants
//!SECTION
@override
void initState() {
super.initState();
//
//SECTION - State Variables initializations & Listeners
//s1 --Controllers & Listeners
_textController = widget.textController;
//s1 --Controllers & Listeners
//
//s1 --State
// widget.configuration.isEnabled = widget.configuration.isEnabled;
_isFocused = false;
//s1 --State
//
//s1 --Late & Async Initializers
//s1 --Late & Async Initializers
//!SECTION
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
//
//SECTION - State Variables initializations & Listeners
//s1 --State
_focusNode.addListener(() {
if (mounted) {
setState(() {
_isFocused = _focusNode.hasFocus;
});
}
});
//s1 --State
//!SECTION
}
//SECTION - Dumb Widgets
//!SECTION
//SECTION - Stateless functions
getTextHeight(String text, TextStyle style, ui.TextDirection direction) {
final span = TextSpan(text: text, style: style);
final tp = TextPainter(text: span, textDirection: direction);
tp.layout(maxWidth: double.infinity);
return tp.height;
}
//-
//----------------------------------------------------------------
//-
ui.TextDirection finalTextDirection() {
ui.TextDirection fromLocale = intl.Bidi.isRtlLanguage(Localizations.localeOf(context).languageCode) ? ui.TextDirection.rtl : ui.TextDirection.ltr;
//
if (widget.configuration.textDirection != null) {
// Get form Style
return widget.configuration.textDirection!;
} else {
// Detect form Text
return _textController.text != ''
? widget.configuration.withAutomaticDirectionalitySwitching
? intl.Bidi.startsWithLtr(_textController.text)
? ui.TextDirection.ltr
: ui.TextDirection.rtl
: fromLocale
: fromLocale;
}
}
//-
//----------------------------------------------------------------
//-
EdgeInsetsGeometry finalVerticalPadding(
AstromicFieldStyle style,
) {
double desiredFixedHeight = style.fixedHeight ?? 0;
//
double providedPadding = style.contentPadding.vertical;
//
double borderOffset = widget.configuration.respectBorderWidthPadding ? style.border?.borderSide.strokeInset ?? 0.0 : 0.0;
//
double fontOffset = getTextHeight(
widget.textController.text.isNotEmpty
? widget.textController.text
: (widget.hint?.isNotEmpty ?? false)
? widget.hint!
: "",
widget.textController.text.isNotEmpty && widget.style(widget.configuration.isEnabled, _isFocused).textStyle != null
? widget.style(widget.configuration.isEnabled, _isFocused).textStyle!
: widget.style(widget.configuration.isEnabled, _isFocused).hintStyle != null
? widget.style(widget.configuration.isEnabled, _isFocused).hintStyle!
: const TextStyle(),
finalTextDirection(),
);
//
double finalVertical =
//-
widget.configuration.isFixedHeight
?
//-
widget.configuration.isTextArea
?
//s1 Fixed Height with Text Area
borderOffset + providedPadding
:
//s1 Fixed Height and not Text Area
desiredFixedHeight - (fontOffset + borderOffset)
//s1 - Not Fixed Height
: providedPadding + borderOffset;
//
return EdgeInsets.symmetric(
vertical: finalVertical / 2,
);
}
//!SECTION
//SECTION - Action Callbacks
//!SECTION
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
//SECTION - Build Setup //SECTION - Build Setup
//s1 --Values //s1 -Values
//double w = MediaQuery.of(context).size.width; //double w = MediaQuery.of(context).size.width;
//double h = MediaQuery.of(context).size.height; //double h = MediaQuery.of(context).size.height;
//s1 --Values //s1 -Values
// //
//s1 --Contexted Widgets //s1 -Widgets
InputDecoration inputDecoration = InputDecoration( //s1 -Widgets
//s1 -- Functionality
enabled: widget.configuration.isEnabled,
//s1 -- Configurations
isDense: true,
hintTextDirection: widget.configuration.hintDirection ?? finalTextDirection(),
//s1 -- Style
filled: widget.style(widget.configuration.isEnabled, _isFocused).isFilled,
fillColor: widget.style(widget.configuration.isEnabled, _isFocused).fillColor,
//
hintStyle: widget.style(widget.configuration.isEnabled, _isFocused).hintStyle,
//
enabledBorder: widget.style(widget.configuration.isEnabled, false).border,
focusedBorder: widget.style(widget.configuration.isEnabled, true).border,
disabledBorder: widget.style(widget.configuration.isEnabled, _isFocused).border,
errorBorder: widget.style(widget.configuration.isEnabled, false).border,
focusedErrorBorder: widget.style(widget.configuration.isEnabled, true).border,
//
errorStyle: const TextStyle(height: 0),
contentPadding: finalVerticalPadding(widget.style(widget.configuration.isEnabled, _isFocused)),
//s1 -- Content
hintText: widget.hint,
//
prefixIcon: widget.prefixWidget != null &&
widget.prefixWidget!(widget.configuration.isEnabled, _isFocused, () {
setState(() {});
}) !=
null
? Container(
margin: EdgeInsetsDirectional.fromSTEB(widget.style(widget.configuration.isEnabled, _isFocused).prefixSpacing, 0,
widget.style(widget.configuration.isEnabled, _isFocused).contentPadding.resolveToDirectional(finalTextDirection()).start, 0),
child: widget.prefixWidget!(widget.configuration.isEnabled, _isFocused, () {
setState(() {});
}),
)
: SizedBox(width: widget.style(widget.configuration.isEnabled, _isFocused).contentPadding.resolveToDirectional(finalTextDirection()).start),
//
prefixIconConstraints: widget.prefixWidget != null &&
widget.prefixWidget!(widget.configuration.isEnabled, _isFocused, () {
setState(() {});
}) !=
null
? widget.style(widget.configuration.isEnabled, _isFocused).prefixSize != 0
? BoxConstraints.expand(
width: widget.style(widget.configuration.isEnabled, _isFocused).prefixSize +
widget.style(widget.configuration.isEnabled, _isFocused).prefixSpacing +
widget.style(widget.configuration.isEnabled, _isFocused).contentPadding.resolveToDirectional(finalTextDirection()).start,
height: widget.style(widget.configuration.isEnabled, _isFocused).prefixSize,
)
: const BoxConstraints.tightForFinite()
: BoxConstraints.tightForFinite(width: widget.style(widget.configuration.isEnabled, _isFocused).contentPadding.resolveToDirectional(finalTextDirection()).start),
//
suffixIcon: widget.suffixWidget != null &&
widget.suffixWidget!(widget.configuration.isEnabled, _isFocused, () {
setState(() {});
}) !=
null
? Container(
margin: EdgeInsetsDirectional.fromSTEB(widget.style(widget.configuration.isEnabled, _isFocused).contentPadding.resolveToDirectional(finalTextDirection()).end, 0,
widget.style(widget.configuration.isEnabled, _isFocused).suffixSpacing, 0),
child: widget.suffixWidget!(widget.configuration.isEnabled, _isFocused, () {
setState(() {});
}),
)
: SizedBox(width: widget.style(widget.configuration.isEnabled, _isFocused).contentPadding.resolveToDirectional(finalTextDirection()).end),
suffixIconConstraints: widget.suffixWidget != null &&
widget.suffixWidget != null &&
widget.suffixWidget!(widget.configuration.isEnabled, _isFocused, () {
setState(() {});
}) !=
null
? widget.style(widget.configuration.isEnabled, _isFocused).suffixSize != 0
? BoxConstraints.expand(
width: widget.style(widget.configuration.isEnabled, _isFocused).suffixSize +
widget.style(widget.configuration.isEnabled, _isFocused).suffixSpacing +
widget.style(widget.configuration.isEnabled, _isFocused).contentPadding.resolveToDirectional(finalTextDirection()).end,
height: widget.style(widget.configuration.isEnabled, _isFocused).suffixSize,
)
: const BoxConstraints.tightForFinite()
: BoxConstraints.tightForFinite(width: widget.style(widget.configuration.isEnabled, _isFocused).contentPadding.resolveToDirectional(finalTextDirection()).end),
);
//s1 --Contexted Widgets
//!SECTION //!SECTION
//
//SECTION - Build Return //SECTION - Build Return
return Column( return AstromicFieldBase(
mainAxisSize: MainAxisSize.min, key: key,
crossAxisAlignment: CrossAxisAlignment.start, textController: textController,
children: [ stateKey: stateKey,
Directionality( onChanged: onChanged,
textDirection: finalTextDirection(), onSubmited: onSubmited,
child: Container( configuration: configuration,
height: widget.configuration.isFixedHeight style: style,
? !widget.configuration.isTextArea hint: hint,
? null prefixWidget: prefixWidget,
: widget.style(widget.configuration.isEnabled, _isFocused).fixedHeight suffixWidget: suffixWidget,
: null, messageBuilder: messageBuilder,
alignment: widget.style(widget.configuration.isEnabled, _isFocused).textAlignVertical.toAlignment(), contextButtons: contextButtons,
child: TextFormField(
//s1 -- Functionality
key: widget.stateKey,
controller: _textController,
focusNode: _focusNode,
textInputAction: widget.configuration.inputAction,
//
onChanged: (v) {
setState(() {
if (widget.onChanged != null) {
widget.onChanged!(v);
}
});
},
//
onFieldSubmitted: (v) {
//
if (widget.configuration.inputAction == TextInputAction.next) {
_focusNode.nextFocus();
}
if (widget.onSubmited != null) {
widget.onSubmited!(v);
}
},
//
onTapOutside: (tapEvent) {
if (widget.configuration.unfocusOnTapOutside) {
_focusNode.unfocus();
}
},
//
//s1 -- Configurations
autovalidateMode: widget.validatingMode,
autofocus: widget.configuration.withAutofocus,
keyboardType: widget.configuration.inputType,
textDirection: finalTextDirection(),
obscureText: widget.configuration.withObscurity ? (widget.obscureText ?? false) : false,
inputFormatters: widget.inputFormatters,
//
minLines: widget.configuration.isFixedHeight && widget.configuration.isTextArea ? null : widget.style(widget.configuration.isEnabled, _isFocused).minLines,
maxLines: widget.configuration.isFixedHeight
? widget.configuration.isTextArea
? null
: widget.style(widget.configuration.isEnabled, _isFocused).maxLines
: widget.style(widget.configuration.isEnabled, _isFocused).maxLines,
//
maxLength: widget.style(widget.configuration.isEnabled, _isFocused).maxLength,
maxLengthEnforcement: widget.configuration.maxLengthEnforcement,
//
expands: widget.configuration.isFixedHeight && widget.configuration.isTextArea ? true : false,
// - Validation
validator: widget.validator != null ? (s) => widget.validator!(widget.configuration.isEnabled, _isFocused, s) : null,
// - Validation
//s1 -- Style
style: widget.style(widget.configuration.isEnabled, _isFocused).textStyle,
cursorColor: widget.style(widget.configuration.isEnabled, _isFocused).cursorColor,
textAlign: widget.style(widget.configuration.isEnabled, _isFocused).textAlign,
textAlignVertical: widget.style(widget.configuration.isEnabled, _isFocused).textAlignVertical,
//
//s1 -- Input Decoration
decoration: inputDecoration,
//s1 -- Content
contextMenuBuilder: (_, state) {
List<ContextMenuButtonItem> baseContextButtons = state.contextMenuButtonItems;
if (widget.contextButtons != null) {
baseContextButtons.addAll(widget.contextButtons!);
}
return AdaptiveTextSelectionToolbar.buttonItems(
buttonItems: baseContextButtons,
anchors: state.contextMenuAnchors,
);
},
),
),
),
widget.messageBuilder != null &&
widget.messageBuilder!(
widget.configuration.isEnabled,
_isFocused,
) !=
null
? Padding(
padding: widget.style(widget.configuration.isEnabled, _isFocused).messagePadding,
child: widget.messageBuilder!(widget.configuration.isEnabled, _isFocused) ?? Container(),
)
: Container()
],
); );
//!SECTION //!SECTION
} }
@override
void dispose() {
//SECTION - Disposable variables
//!SECTION
super.dispose();
}
} }

View File

@@ -2,11 +2,11 @@
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'src/Radio/radio.selector.dart'; import 'src/Radio/radio.selector.dart';
import 'src/Chip/chip.selector.dart'; import 'src/Chip/chip.selector.dart';
import 'src/Radio/configuration.dart'; import 'src/Radio/models/configuration.model.dart';
import 'src/Chip/configuration.dart'; import 'src/Chip/models/configuration.model.dart';
// //
export 'src/Radio/configuration.dart'; export 'src/Radio/models/configuration.model.dart';
export 'src/Chip/configuration.dart'; export 'src/Chip/models/configuration.model.dart';
class AstromicSelectors { class AstromicSelectors {
//S1 -- Radio //S1 -- Radio

View File

@@ -3,6 +3,7 @@
//s1 PACKAGES //s1 PACKAGES
//--------------- //---------------
//s2 CORE //s2 CORE
import 'package:astromic_extensions/astromic_extensions.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
//s2 3RD-PARTY //s2 3RD-PARTY
// //
@@ -10,8 +11,7 @@ import 'package:flutter/material.dart';
//--------------- //---------------
//s2 SERVICES //s2 SERVICES
//s2 MODELS //s2 MODELS
import '../../../../Infrastructure/list_extensions.dart'; import 'models/configuration.model.dart';
import 'configuration.dart';
//s2 MISC //s2 MISC
//!SECTION - Imports //!SECTION - Imports

View File

@@ -11,7 +11,7 @@ import 'package:flutter/widgets.dart';
//s2 SERVICES //s2 SERVICES
//s2 MODELS //s2 MODELS
import '../../../Spacing/spacing.astromic.dart'; import '../../../Spacing/spacing.astromic.dart';
import 'configuration.dart'; import 'models/configuration.model.dart';
//s2 MISC //s2 MISC
//!SECTION - Imports //!SECTION - Imports
// //

View File

@@ -4,7 +4,6 @@ import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:octo_image/octo_image.dart'; import 'package:octo_image/octo_image.dart';
import '../../../Infrastructure/transparent_image.dart';
Widget astromicImage( Widget astromicImage(
BuildContext context, { BuildContext context, {
@@ -214,3 +213,73 @@ Widget astromicImage(
), ),
); );
} }
final Uint8List kTransparentImage = Uint8List.fromList(<int>[
0x89,
0x50,
0x4E,
0x47,
0x0D,
0x0A,
0x1A,
0x0A,
0x00,
0x00,
0x00,
0x0D,
0x49,
0x48,
0x44,
0x52,
0x00,
0x00,
0x00,
0x01,
0x00,
0x00,
0x00,
0x01,
0x08,
0x06,
0x00,
0x00,
0x00,
0x1F,
0x15,
0xC4,
0x89,
0x00,
0x00,
0x00,
0x0A,
0x49,
0x44,
0x41,
0x54,
0x78,
0x9C,
0x63,
0x00,
0x01,
0x00,
0x00,
0x05,
0x00,
0x01,
0x0D,
0x0A,
0x2D,
0xB4,
0x00,
0x00,
0x00,
0x00,
0x49,
0x45,
0x4E,
0x44,
0xAE,
0x42,
0x60,
0x82,
]);

View File

@@ -1,49 +1,28 @@
##SECTION --Project Information name: astromic_elements
name: astromic_mobile_elements description: The elements module of the Astromic Presentation System
description: The elements module of the Astromic Mobile Presentation System
publish_to: "none" publish_to: "none"
## App Version scheme: Major.Feature.Fixes+Build version: 0.1.0
version: 0.0.1+2
##!SECTION --Project Information
#
#
##SECTION --Environment Constraints
environment: environment:
sdk: ">=3.1.1 <4.0.0" sdk: ">=3.6.0"
flutter: ">3.10.0" flutter: ">3.27.0"
##!SECTION --Environment Constraints
#
#
##SECTION -- Dependencies Overrides
# dependency_overrides:
# intl: ^0.18.1
##!SECTION -- Dependencies Overrides
#
#
##SECTION --Development Dependencies
dev_dependencies: dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^2.0.3 flutter_lints: ^2.0.3
##
##!SECTION --Development Dependencies
#
#
##SECTION --Dependencies
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
##S1 -- Widgets astromic_extensions:
git:
url: https://git.micazi.dev/astromic_extensions.git
cached_network_image: ^3.3.1 cached_network_image: ^3.3.1
flutter_svg: ^2.0.10+1 flutter_svg: ^2.0.10+1
octo_image: ^2.0.0 octo_image: ^2.0.0
flutter_switch: ^0.3.2 flutter_switch: ^0.3.2
intl: ^0.19.0 intl: ^0.19.0
#
##!SECTION --Dependencies
#
#
##SECTION --App Assets
flutter: flutter:
uses-material-design: true uses-material-design: true
##!SECTION --App Assets

4
pubspec_overrides.yaml Normal file
View File

@@ -0,0 +1,4 @@
dependency_overrides:
astromic_extensions:
git:
url: https://git.prox/micazi/astromic_extensions.git