**1.0.0**

This commit is contained in:
2026-01-08 14:39:34 +02:00
parent be50a0d570
commit 0d688cedc8
23 changed files with 498 additions and 369 deletions

View File

@@ -17,19 +17,19 @@
"name": "flutter", "name": "flutter",
"rootUri": "file:///C:/Users/micwa/fvm/versions/stable/packages/flutter", "rootUri": "file:///C:/Users/micwa/fvm/versions/stable/packages/flutter",
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.7" "languageVersion": "3.8"
}, },
{ {
"name": "flutter_lints", "name": "flutter_lints",
"rootUri": "file:///C:/Users/micwa/AppData/Local/Pub/Cache/hosted/pub.dev/flutter_lints-5.0.0", "rootUri": "file:///C:/Users/micwa/AppData/Local/Pub/Cache/hosted/pub.dev/flutter_lints-6.0.0",
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.5" "languageVersion": "3.8"
}, },
{ {
"name": "lints", "name": "lints",
"rootUri": "file:///C:/Users/micwa/AppData/Local/Pub/Cache/hosted/pub.dev/lints-5.1.1", "rootUri": "file:///C:/Users/micwa/AppData/Local/Pub/Cache/hosted/pub.dev/lints-6.0.0",
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.6" "languageVersion": "3.8"
}, },
{ {
"name": "material_color_utilities", "name": "material_color_utilities",
@@ -39,33 +39,32 @@
}, },
{ {
"name": "meta", "name": "meta",
"rootUri": "file:///C:/Users/micwa/AppData/Local/Pub/Cache/hosted/pub.dev/meta-1.16.0", "rootUri": "file:///C:/Users/micwa/AppData/Local/Pub/Cache/hosted/pub.dev/meta-1.17.0",
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "2.12" "languageVersion": "3.5"
}, },
{ {
"name": "sky_engine", "name": "sky_engine",
"rootUri": "file:///C:/Users/micwa/fvm/versions/stable/bin/cache/pkg/sky_engine", "rootUri": "file:///C:/Users/micwa/fvm/versions/stable/bin/cache/pkg/sky_engine",
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.7" "languageVersion": "3.8"
}, },
{ {
"name": "vector_math", "name": "vector_math",
"rootUri": "file:///C:/Users/micwa/AppData/Local/Pub/Cache/hosted/pub.dev/vector_math-2.1.4", "rootUri": "file:///C:/Users/micwa/AppData/Local/Pub/Cache/hosted/pub.dev/vector_math-2.2.0",
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "2.14" "languageVersion": "3.1"
}, },
{ {
"name": "astromic_extensions", "name": "astromic_extensions",
"rootUri": "../", "rootUri": "../",
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.6" "languageVersion": "3.10"
} }
], ],
"generated": "2025-03-30T10:13:12.420517Z",
"generator": "pub", "generator": "pub",
"generatorVersion": "3.7.0", "generatorVersion": "3.10.1",
"flutterRoot": "file:///C:/Users/micwa/fvm/versions/stable", "flutterRoot": "file:///C:/Users/micwa/fvm/versions/stable",
"flutterVersion": "3.29.0", "flutterVersion": "3.38.3",
"pubCache": "file:///C:/Users/micwa/AppData/Local/Pub/Cache" "pubCache": "file:///C:/Users/micwa/AppData/Local/Pub/Cache"
} }

View File

@@ -0,0 +1,74 @@
{
"roots": [
"astromic_extensions"
],
"packages": [
{
"name": "astromic_extensions",
"version": "1.0.0",
"dependencies": [
"flutter"
],
"devDependencies": [
"flutter_lints"
]
},
{
"name": "flutter_lints",
"version": "6.0.0",
"dependencies": [
"lints"
]
},
{
"name": "flutter",
"version": "0.0.0",
"dependencies": [
"characters",
"collection",
"material_color_utilities",
"meta",
"sky_engine",
"vector_math"
]
},
{
"name": "lints",
"version": "6.0.0",
"dependencies": []
},
{
"name": "sky_engine",
"version": "0.0.0",
"dependencies": []
},
{
"name": "vector_math",
"version": "2.2.0",
"dependencies": []
},
{
"name": "meta",
"version": "1.17.0",
"dependencies": []
},
{
"name": "material_color_utilities",
"version": "0.11.1",
"dependencies": [
"collection"
]
},
{
"name": "collection",
"version": "1.19.1",
"dependencies": []
},
{
"name": "characters",
"version": "1.4.0",
"dependencies": []
}
],
"configVersion": 1
}

View File

@@ -1 +1 @@
3.29.0 3.38.3

View File

@@ -1,8 +1,3 @@
## 0.1.2 # 1.0.0
- **FEAT** Added Quick widget extensions.
## 0.1.1 * **INIT**: Initial commit in the new repo.
- **FEAT** Added Map Extensions file and `MergeAllMaps` function.
## 0.1.0
- **INIT**: Initial commit in the new repo.

View File

@@ -1 +0,0 @@
This repository is Developed, Maintained, and is property of Michael W. Aziz (Micazi).

25
LICENSE Normal file
View File

@@ -0,0 +1,25 @@
# License Agreement
Copyright (c) 2026 Michael W. Aziz (Micazi). All rights reserved.
Proprietary and Confidential.
1. PERMITTED USE
This software is the exclusive property of Michael W. Aziz. Use of this
software is strictly limited to:
(a) Personal projects developed and maintained by Michael W. Aziz.
(b) Professional projects or client applications where Michael W. Aziz
is a direct contributor or the primary developer.
2. RESTRICTIONS
Unauthorized copying, modification, or distribution of this software
outside of the permitted uses defined in Section 1 is strictly prohibited.
Clients are granted a license to use the compiled output of this software
within their specific project but do not acquire ownership of the
underlying source code or the right to redistribute it as a standalone package.
3. WARRANTY & LIABILITY
THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES,
OR OTHER LIABILITY, ARISING FROM, OUT OF, OR IN CONNECTION WITH THE
SOFTWARE OR THE USE THEREOF.

113
README.md
View File

@@ -1,42 +1,77 @@
## Atromic Extensions # Astromic Extensions
The extensions module of the **Astromic** Presentation System **The Foundation of the Astromic Presentation System.**
Developed, Maintained, and is property of Michael W. Aziz (Micazi)
### Content A collection of high-performance Dart extensions designed to eliminate UI boilerplate and simplify RTL (Right-to-Left) layout logic.
- on _BorderDirectional_ ---
- **all()** : Generate a uniform border with one borderSide. ☑️
- on _EdgeInsetsGeometry_ ## 🛠 Features & API Reference
- **copyWith()** ☑️
- **resolveToDirectional()** : Automatically reverse the EdgeInsets based on the dynamic *TextDirection*. ☑️ ### Layout & Spacing
- on _List<E>_
- **containsAll()** : Checker to see if a list contains all of the other list. ☑️ * **.resolveToDirectional()** (`EdgeInsetsGeometry`): Automatically flips insets based on the current `TextDirection`.
- **getUnique()** : Get unique items only of a supplied list. ☑️
- on _List<Map<T,B>>_ * **.resolveToDirectional()** (`BorderRadiusGeometry`): Reverses corner radii (e.g., top-left to top-right) for RTL support.
- **mergeAllMaps()** : Merges a list of maps into one with a conditional functionality to approve the merge. ☑️
- on _TextAlignVertical_ * **.copyWith()** (`EdgeInsetsGeometry`): An additive copy method for combining geometries.
- **toAlignment()** : convert a `TextAlignVertical` to an `Alignment` object. ☑️
- on _BorderRadiusGeometry_ * **.padAll / .symH / .symV** (`num`): Quick-access padding generators directly from numbers.
- **copyWith()** ☑️
- **resolveToDirectional()** : Automatically reverse the BorderRadius based on the dynamic *TextDirection*. ☑️ ### Widget Wrappers (Fluent UI)
- on _String_
- **toColor()** : Parse a HexCode `String` into a `Color` object. ☑️ * **Layout**: `.center()`, `.align()`, `.positioned()`, `.sized()`, `.rotated()`
- **capitalize()** : Capitalize the word. ☑️
- **rich()** : Convert the string to a RichText Widget. ☑️ * **Transform**: `.flipH()`, `.flipV()`, `.opacity()`
- on _Widget_
- **center** * **Spacing**: `.padAll()`, `.padSymH()`, `.padSymV()`, `.padTop()`, `.padBot()`
- **circular**
- **align** * **Utility**: `.safeArea()`, `.circular()`
- **positioned**
- **sized** ### Data & Styling Utilities
- **rotated**
- **flipH** * **containsAll()** (`List<E>`): Optimized $O(n)$ check to see if a list contains all elements of another.
- **flipV**
- **safeArea** * **getUnique()** (`List<E>`): Returns a list with duplicates removed using high-performance Set hashing.
- **opacity**
- **padAll** * **mergeAllMaps()** (`List<Map>`): Performs a conditional deep merge of map collections.
- **padSymH**
- **padSymV** * **.toColor()** (`String`): Parses Hex strings into Flutter `Color` objects.
- **padTop**
- **padBot** * **.capitalize()** (`String`): Standardizes string casing.
* **.rich()** (`String`): Shorthand to convert a string directly into a `RichText` widget.
* **.toAlignment()** (`TextAlignVertical`): Converts vertical text alignment to an `Alignment` object.
---
## 📦 Installation
```yaml
dependencies:
astromic_extensions:
git:
url: git.micazi.dev/micazi/astromic_extensions.git
ref: main
```
---
## 🤝 Client Handoff & Continuity
To ensure project stability following the engagement, clients should follow these steps to secure a local version of this library:
1. Mirror Repository: Clone this repository and re-upload it to your internal Git organization.
2. Update Source: Update the pubspec.yaml in your application to point to your internal Git URL.
3. Versioning: Always use a specific Git ref (tag or commit hash) to ensure build reproducibility.
Note: Access to the Micazi master repository is strictly controlled. Unauthorized redistribution of this source code is prohibited under the included LICENSE terms.
---
## ⚖️ License
Developed, Maintained, and property of Michael W. Aziz (Micazi). Refer to the [LICENSE](LICENSE) file for permitted use in client projects.

View File

@@ -1,50 +1,48 @@
include: package:lints/recommended.yaml include: package:flutter_lints/flutter.yaml
analyzer:
language:
# Ensures the compiler never implicitly assumes 'dynamic' when it cannot infer a type.
strict-inference: true
# Disallows the use of generic types without explicit type arguments (e.g., List instead of List<int>).
strict-raw-types: true
errors:
# Elevates missing required parameters from a warning to a hard compile error.
missing_required_param: error
# Elevates missing return statements in non-void functions to a hard compile error.
missing_return: error
linter: linter:
rules: rules:
# ==== Project Organization Rules ==== # Requires explicit return types for all functions and methods to ensure API clarity.
# Enforces relative imports to maintain project structure and avoid unnecessary long paths - always_declare_return_types
# Discourages redundant type annotations on closure parameters where inference is sufficient.
- avoid_types_on_closure_parameters
# Requires the @override annotation when a class member overrides a member from a superclass.
- annotate_overrides
# Enforces the use of relative imports for files within the same package to maintain portability.
- prefer_relative_imports - prefer_relative_imports
# Enables the use of the 'super.parameter' syntax in constructors to reduce boilerplate.
# Ensures that files are named in lowercase_with_underscores format - use_super_parameters
- file_names # Encourages 'const' constructors for classes to optimize memory and performance.
# ==== Best Practices ====
# Enforces the closing of streams and sinks to avoid memory leaks
- close_sinks
# Avoids empty 'else' blocks to reduce confusion and improve code readability
- avoid_empty_else
# Prefer using 'const' constructors wherever possible for better performance and immutability
- prefer_const_constructors - prefer_const_constructors
# Requires 'const' for variable declarations that are initialized with a constant value.
# Avoid leading underscores for local variable names to prevent conflicts and improve clarity - prefer_const_declarations
- no_leading_underscores_for_local_identifiers # Encourages declaring local variables as 'final' if they are not reassigned.
- prefer_final_locals
# ==== Code Consistency ==== # Encourages declaring private fields as 'final' if they are not reassigned.
# Avoids the use of 'print' statements in production code, encouraging proper logging instead
- avoid_print
# Encourages using 'final' for fields that are not reassigned to promote immutability
- prefer_final_fields - prefer_final_fields
# Triggers a warning when a future is not awaited or explicitly handled, preventing race conditions.
# Ensures that all types are explicitly specified for better readability and type safety - unawaited_futures
- always_specify_types # Prevents accessing BuildContext across asynchronous gaps to avoid runtime crashes.
- use_build_context_synchronously
# Ensures constructors are at the top of the class for better readability and consistency # Ensures that Sink and StreamController instances are properly closed to prevent memory leaks.
- sort_constructors_first - close_sinks
# Prevents the use of control flow statements (like return or throw) inside a finally block.
# Avoids redundant default argument values to keep the code clean - control_flow_in_finally
- avoid_redundant_argument_values # Standardizes string literals to use single quotes unless the string contains a single quote.
# Enforces consistency by preferring single quotes over double quotes for string literals
- prefer_single_quotes - prefer_single_quotes
# Requires constructors to be placed before other members in a class.
# ==== Documentation Rules ==== - sort_constructors_first
# Enforces documentation for all public classes, methods, and fields to improve API clarity # Disallows leading underscores for local variables to distinguish them from private class members.
# - public_member_api_docs - no_leading_underscores_for_local_identifiers
# ==== Null Safety ====
# Avoids unnecessary null checks and encourages the use of null-aware operators
- unnecessary_null_checks

View File

@@ -1,2 +0,0 @@
[0330/121753.404:ERROR:crashpad_client_win.cc(811)] not connected
[0330/121753.573:ERROR:crashpad_client_win.cc(811)] not connected

View File

@@ -1,10 +1,5 @@
library; library;
export './src/border_extensions.dart'; export './src/data_and_logic.dart';
export './src/insets_extension.dart'; export './src/layout_and_spacing.dart';
export './src/list_extensions.dart'; export './src/widget_wrappers.dart';
export './src/map_extensions.dart';
export 'src/alignment_extensions.dart';
export './src/radius_extensions.dart';
export './src/string_extensions.dart';
export './src/widget_extensions.dart';

View File

@@ -1,16 +0,0 @@
import 'package:flutter/material.dart';
extension TextAlignVerticalExtension on TextAlignVertical {
Alignment 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,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

@@ -0,0 +1,95 @@
import 'dart:math';
import 'package:flutter/material.dart';
extension StringExtensions on String {
/// Parses a HexCode string into a [Color] object.
/// Supports formats like '#FFFFFF', 'FFFFFF', or '0xFFFFFFFF'.
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);
}
/// Capitalizes the first letter of the string.
String get capitalize => (length > 1) ? this[0].toUpperCase() + substring(1) : toUpperCase();
/// Converts CamelCase strings to a space-separated Title Case string.
/// Example: "myVariableName" -> "My Variable Name"
String get camelCaseToTitle {
final String spaced = replaceAllMapped(
RegExp(r'([a-z])([A-Z])'),
(match) => '${match.group(1)} ${match.group(2)}',
);
return spaced.split(' ').map((word) => word[0].toUpperCase() + word.substring(1)).join(' ');
}
/// Returns [anotherString] if the current string is empty or contains only whitespace.
String replaceIfEmpty(String anotherString) => trim().isEmpty ? anotherString : this;
}
extension NullableStringExtensions on String? {
/// Returns [anotherString] if the current string is null, empty, or only whitespace.
String replaceIfEmptyOrNull(String anotherString) => (this == null || this!.trim().isEmpty) ? anotherString : this!;
}
extension ListEx<E> on List<E>? {
/// Returns true if the list contains all elements of [otherList]. Optimized $O(n)$.
bool containsAll(List<E> otherList) {
if (this == null || this!.isEmpty) return false;
if (otherList.isEmpty) return true;
final thisSet = this!.toSet();
return otherList.every(thisSet.contains);
}
/// Returns a new list containing only unique elements from the current list.
List<E> getUnique() => this?.toSet().toList() ?? <E>[];
/// Returns a list containing only non-null elements.
List<E> get nonNulls => this?.whereType<E>().toList() ?? [];
/// Safely attempts to reduce the list to a single value. Returns null if empty.
E? tryReduce(E Function(E a, E b) reducer) {
if (this == null || this!.isEmpty) return null;
final filtered = nonNulls;
return filtered.isNotEmpty ? filtered.reduce(reducer) : null;
}
/// Returns a sublist limited to the first [limit] items.
List<E>? limit(int limit) => (this?.length ?? 0) > limit ? this?.sublist(0, limit) : this;
}
extension MapListExtensions<T, B> on List<Map<T, B>> {
/// Merges a list of maps into a single map.
/// An optional [repeatingKeysValueComparer] can handle logic when keys collide.
Map<T, B> mergeAllMaps({void Function(T key, B value1, B value2)? repeatingKeysValueComparer}) {
final Map<T, B> r = <T, B>{};
for (var m in this) {
m.forEach((key, value) {
if (!r.containsKey(key)) {
r[key] = value;
} else {
repeatingKeysValueComparer?.call(key, r[key] as B, value);
}
});
}
return r;
}
}
extension IntExtensions on int {
/// Generates a random numeric pin code with a length equal to the integer value.
int get generatePinCode {
if (this <= 0) return 0;
final min = pow(10, this - 1).toInt();
final max = pow(10, this).toInt() - 1;
return Random().nextInt(max - min + 1) + min;
}
}
extension DoubleExtensions on double {
/// Clamps the double value between [min] and [max].
double clampDouble(double min, double max) => this < min ? min : (this > max ? max : this);
}

View File

@@ -1,20 +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);
//
}
}
extension InsetsNumExtension on num {
EdgeInsets get symH => EdgeInsets.symmetric(horizontal: toDouble());
EdgeInsets get symV => EdgeInsets.symmetric(vertical: toDouble());
EdgeInsets get padAll => EdgeInsets.all(toDouble());
EdgeInsets get padTop => EdgeInsets.only(top: toDouble());
EdgeInsets get padBot => EdgeInsets.only(bottom: toDouble());
}

View File

@@ -0,0 +1,61 @@
import 'package:flutter/widgets.dart';
extension InsetsExtension on EdgeInsetsGeometry {
/// Combines two [EdgeInsetsGeometry] objects by adding them together.
EdgeInsetsGeometry copyWith(EdgeInsetsGeometry g) => add(g);
/// Converts [EdgeInsetsGeometry] to [EdgeInsetsDirectional] based on [direction].
EdgeInsetsDirectional resolveToDirectional(TextDirection direction) {
final res = resolve(direction);
final isLtr = direction == TextDirection.ltr;
return EdgeInsetsDirectional.fromSTEB(
isLtr ? res.left : res.right, res.top,
isLtr ? res.right : res.left, res.bottom
);
}
}
extension InsetsNumExtension on num {
/// Returns [EdgeInsets] with symmetric horizontal spacing.
EdgeInsets get symH => EdgeInsets.symmetric(horizontal: toDouble());
/// Returns [EdgeInsets] with symmetric vertical spacing.
EdgeInsets get symV => EdgeInsets.symmetric(vertical: toDouble());
/// Returns [EdgeInsets] with uniform spacing on all sides.
EdgeInsets get padAll => EdgeInsets.all(toDouble());
/// Returns [EdgeInsets] with spacing only on the top.
EdgeInsets get padTop => EdgeInsets.only(top: toDouble());
/// Returns [EdgeInsets] with spacing only on the bottom.
EdgeInsets get padBot => EdgeInsets.only(bottom: toDouble());
/// Returns [EdgeInsetsDirectional] with spacing only at the start.
EdgeInsetsDirectional get padStart => EdgeInsetsDirectional.only(start: toDouble());
/// Returns [EdgeInsetsDirectional] with spacing only at the end.
EdgeInsetsDirectional get padEnd => EdgeInsetsDirectional.only(end: toDouble());
/// Returns a width value equal to a percentage of the screen width.
double ofSW(BuildContext c) => MediaQuery.sizeOf(c).width * toDouble() / 100;
/// Returns a height value equal to a percentage of the screen height.
double ofSH(BuildContext c) => MediaQuery.sizeOf(c).height * toDouble() / 100;
}
extension RadiusExtension on BorderRadiusGeometry {
/// Combines two [BorderRadiusGeometry] objects by adding them together.
BorderRadiusGeometry copyWith(BorderRadiusGeometry g) => add(g);
/// Resolves [BorderRadiusGeometry] to [BorderRadiusDirectional] based on [direction].
BorderRadiusDirectional resolveToDirectional(TextDirection direction) {
final res = resolve(direction);
return BorderRadiusDirectional.only(
topStart: direction == TextDirection.ltr ? res.topLeft : res.topRight,
topEnd: direction == TextDirection.rtl ? res.topLeft : res.topRight,
bottomEnd: direction == TextDirection.rtl ? res.bottomLeft : res.bottomRight,
bottomStart: direction == TextDirection.ltr ? res.bottomLeft : res.bottomRight,
);
}
}

View File

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

View File

@@ -1,19 +0,0 @@
extension MapExtensions<B, T> on Map<B, T> {}
extension MapListExtensions<T, B> on List<Map<T, B>> {
Map<T, B> mergeAllMaps({Function(T key, B value1, B value2)? repeatingKeysValueComparer}) {
Map<T, B> r = <T, B>{};
//
for (Map<T, B> m in this) {
m.forEach((T key, B value) {
if (!r.containsKey(key)) {
r.addEntries(<MapEntry<T, B>>[MapEntry<T, B>(key, value)]);
} else {
repeatingKeysValueComparer?.call(key, r[key] as B, value);
}
});
}
//
return r;
}
}

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,29 +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();
}
/// Convert CamelCase to a capitalized space separated title.
String get camelCaseToTitle {
final String spaced = replaceAllMapped(
RegExp(r'([a-z])([A-Z])'),
(Match match) => '${match.group(1)} ${match.group(2)}',
);
return spaced.split(' ').map((String word) => word[0].toUpperCase() + word.substring(1)).join(' ');
}
}

View File

@@ -1,113 +0,0 @@
import 'dart:math' as math;
import 'package:flutter/gestures.dart';
import 'package:flutter/widgets.dart';
import 'insets_extension.dart';
extension StringWidgetExtensions on String {
/// Convert this text into a RichText with custom quick styles and tap gestures.
RichText rich(TextStyle masterStyle, {Map<int, TextStyle>? styles, Map<int, VoidCallback>? tapCallbacks, TextAlign textAlign = TextAlign.center}) {
Map<String, TextStyle> mappedStyles = <String, TextStyle>{};
Map<String, VoidCallback> mappedCallbacks = <String, VoidCallback>{};
// Getting string pieces.
List<String> stringPieces = RegExp(r'`([^`]*)`').allMatches(this).map((RegExpMatch m) => m.group(1)).whereType<String>().toList();
// Looping on the pieces...
for (String stringPiece in stringPieces) {
String textAfter = split('`$stringPiece`')[1];
String textBeforeNext = textAfter.split('`')[0];
if (RegExp(r'{(\d+)}').hasMatch(textBeforeNext)) {
// The current piece has an index
int? itemIndex = int.tryParse(RegExp(r'{(\d+)}').allMatches(textBeforeNext).map((RegExpMatch m) => m.group(1)).whereType<String>().first);
if (itemIndex != null) {
// Styles
if (styles != null && styles.isNotEmpty && styles.keys.contains(itemIndex)) {
// Custom Style
mappedStyles.addEntries(<MapEntry<String, TextStyle>>[MapEntry<String, TextStyle>(stringPiece, styles[itemIndex]!)]);
} else {
// Master
mappedStyles.addEntries(<MapEntry<String, TextStyle>>[MapEntry<String, TextStyle>(stringPiece, masterStyle)]);
}
// Callbacks
if (tapCallbacks != null && tapCallbacks.isNotEmpty && tapCallbacks.keys.contains(itemIndex)) {
// Add tap callbak
mappedCallbacks.addEntries(<MapEntry<String, VoidCallback>>[MapEntry<String, VoidCallback>(stringPiece, tapCallbacks[itemIndex]!)]);
}
} else {
debugPrint('Something wrong with applying custom indexing in QuickRichText. $itemIndex');
}
} else {
mappedStyles.addEntries(<MapEntry<String, TextStyle>>[MapEntry<String, TextStyle>(stringPiece, masterStyle)]);
}
}
// Adding styles to the children
List<InlineSpan> children = mappedStyles.entries
.toList()
.sublist(1)
.map((MapEntry<String, TextStyle> entry) => TextSpan(
text: entry.key,
style: entry.value,
recognizer: mappedCallbacks.containsKey(entry.key) ? (TapGestureRecognizer()..onTap = mappedCallbacks[entry.key]) : null,
))
.toList();
return RichText(
text: TextSpan(
text: stringPieces[0],
style: masterStyle,
children: children,
),
textAlign: textAlign,
);
}
}
extension QuickSimpleWidgets on Widget {
/// Center the widget
Widget get center => Center(child: this);
/// Make the widget circular with RRect
Widget get circular => ClipRRect(borderRadius: BorderRadius.circular(10000000), child: this);
/// Wrap with a SizedBox
Widget sized({num? w, num? h}) => SizedBox(width: w?.toDouble(), height: h?.toDouble(), child: this);
/// Wrap with a Positioned
Widget positioned({num? bottom, num? top}) => Positioned(bottom: bottom?.toDouble(), top: top?.toDouble(), child: this);
/// Rotate the widget in quarter turns
Widget rotated({int quarterTurns = 0}) => Transform.rotate(angle: (math.pi * 22.5) * quarterTurns, child: this);
//TODO - Make it directional
/// Align
Widget align(Alignment a) => Align(alignment: a, child: this);
/// Flip the widget horizontally
Widget get flipH => Transform.flip(flipX: true, child: this);
/// Flip the widget vertically
Widget get flipV => Transform.flip(flipY: true, child: this);
/// Wrap with a SafeArea
Widget get safeArea => SafeArea(child: this);
/// Quick Opacity Adjustment
Widget opacity(num o) => Opacity(opacity: o.toDouble(), child: this);
/// Padding padAll
Widget padAll(num p) => Padding(padding: p.padAll, child: this);
/// Padding Symmetric Horizontally
Widget padSymH(num p) => Padding(padding: p.symH, child: this);
/// Padding Symmetric Vertically
Widget padSymV(num p) => Padding(padding: p.symV, child: this);
//
/// Padding Only Top
Widget padTop(num p) => Padding(padding: p.padTop, child: this);
/// Padding Only Bottom
Widget padBot(num p) => Padding(padding: p.padBot, child: this);
}

View File

@@ -0,0 +1,94 @@
import 'dart:math' as math;
import 'package:flutter/gestures.dart';
import 'package:flutter/widgets.dart';
import 'layout_and_spacing.dart';
extension ContextExtensions on BuildContext {
/// Shortcut to get the current screen width.
double get sw => MediaQuery.sizeOf(this).width;
/// Shortcut to get the current screen height.
double get sh => MediaQuery.sizeOf(this).height;
}
extension QuickSimpleWidgets on Widget {
/// Wraps the widget in a [Center].
Widget get center => Center(child: this);
/// Clips the widget into a circular shape.
Widget get circular => ClipRRect(borderRadius: BorderRadius.circular(1e6), child: this);
/// Flips the widget horizontally.
Widget get flipH => Transform.flip(flipX: true, child: this);
/// Flips the widget vertically.
Widget get flipV => Transform.flip(flipY: true, child: this);
/// Wraps the widget in a [SafeArea].
Widget get safeArea => SafeArea(child: this);
/// Wraps the widget in a [SizedBox] with specified dimensions.
Widget sized({num? w, num? h}) => SizedBox(width: w?.toDouble(), height: h?.toDouble(), child: this);
/// Wraps the widget in a [Positioned] for use within a [Stack].
Widget positioned({num? bottom, num? top}) => Positioned(bottom: bottom?.toDouble(), top: top?.toDouble(), child: this);
/// Rotates the widget by [quarterTurns] (90 degree increments).
Widget rotated({int quarterTurns = 0}) => Transform.rotate(angle: (math.pi / 2) * quarterTurns, child: this);
/// Wraps the widget in an [Align] widget.
Widget align(Alignment a, {TextDirection? textDirection}) => Align(alignment: textDirection != null ? a.resolve(textDirection) : a, child: this);
/// Changes the [opacity] of the widget.
Widget opacity(num o) => Opacity(opacity: o.toDouble(), child: this);
/// Applies uniform padding around the widget.
Widget padAll(num p) => Padding(padding: p.padAll, child: this);
/// Applies symmetric horizontal padding.
Widget padSymH(num p) => Padding(padding: p.symH, child: this);
/// Applies symmetric vertical padding.
Widget padSymV(num p) => Padding(padding: p.symV, child: this);
/// Applies padding only to the top.
Widget padTop(num p) => Padding(padding: p.padTop, child: this);
/// Applies padding only to the bottom.
Widget padBot(num p) => Padding(padding: p.padBot, child: this);
/// Applies padding to the start (RTL friendly).
Widget padStart(num p) => Padding(padding: p.padStart, child: this);
/// Applies padding to the end (RTL friendly).
Widget padEnd(num p) => Padding(padding: p.padEnd, child: this);
/// Returns the widget if [condition] is true, otherwise returns an empty [SizedBox].
Widget visibleIf(bool condition) => condition ? this : const SizedBox.shrink();
}
extension StringWidgetExtensions on String {
/// Converts a string into a [RichText] using a custom markup: `Text`{index}.
/// [masterStyle] is the default; [styles] and [tapCallbacks] map to the bracketed index.
RichText rich(TextStyle masterStyle, {Map<int, TextStyle>? styles, Map<int, VoidCallback>? tapCallbacks, TextAlign textAlign = TextAlign.center}) {
final List<InlineSpan> spans = [];
final pattern = RegExp(r'`([^`]*)`(?:\{(\d+)\})?');
int lastMatchEnd = 0;
for (final Match match in pattern.allMatches(this)) {
if (match.start > lastMatchEnd) {
spans.add(TextSpan(text: substring(lastMatchEnd, match.start), style: masterStyle));
}
final int? index = int.tryParse(match.group(2) ?? '');
spans.add(TextSpan(
text: match.group(1) ?? '',
style: (index != null && styles?[index] != null) ? styles![index] ?? masterStyle : masterStyle,
recognizer: (index != null && tapCallbacks?[index] != null) ? (TapGestureRecognizer()..onTap = tapCallbacks![index]) : null,
));
lastMatchEnd = match.end;
}
if (lastMatchEnd < length) spans.add(TextSpan(text: substring(lastMatchEnd), style: masterStyle));
return RichText(textAlign: textAlign, text: TextSpan(children: spans));
}
}

View File

@@ -26,18 +26,18 @@ packages:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: flutter_lints name: flutter_lints
sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1" sha256: "3105dc8492f6183fb076ccf1f351ac3d60564bff92e20bfc4af9cc1651f4e7e1"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "5.0.0" version: "6.0.0"
lints: lints:
dependency: transitive dependency: transitive
description: description:
name: lints name: lints
sha256: c35bb79562d980e9a453fc715854e1ed39e24e7d0297a880ef54e17f9874a9d7 sha256: a5e2b223cb7c9c8efdc663ef484fdd95bb243bff242ef5b13e26883547fce9a0
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "5.1.1" version: "6.0.0"
material_color_utilities: material_color_utilities:
dependency: transitive dependency: transitive
description: description:
@@ -50,10 +50,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: meta name: meta
sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.16.0" version: "1.17.0"
sky_engine: sky_engine:
dependency: transitive dependency: transitive
description: flutter description: flutter
@@ -63,10 +63,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: vector_math name: vector_math
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.4" version: "2.2.0"
sdks: sdks:
dart: ">=3.7.0-0 <4.0.0" dart: ">=3.10.0 <4.0.0"
flutter: ">3.27.0" flutter: ">3.38.0"

View File

@@ -1,14 +1,14 @@
name: astromic_extensions name: astromic_extensions
description: The extensions module of the Astromic Presentation System. description: A collection of high-performance Dart extensions designed to eliminate UI boilerplate and simplify RTL (Right-to-Left) layout logic.
publish_to: "none" publish_to: "none"
version: 0.1.2 version: 1.0.0
environment: environment:
sdk: ">=3.6.0" sdk: ">=3.10.0"
flutter: ">3.27.0" flutter: ">3.38.0"
dev_dependencies: dev_dependencies:
flutter_lints: ^5.0.0 flutter_lints: ^6.0.0
dependencies: dependencies:
flutter: flutter: