flutter_shared_utilities 1.0.14 copy "flutter_shared_utilities: ^1.0.14" to clipboard
flutter_shared_utilities: ^1.0.14 copied to clipboard

A comprehensive Flutter utilities package with extensions, models, and utility functions.

flutter_shared_utilities #

pub package License: MIT Flutter

A comprehensive Flutter utilities package that provides essential extensions, models, and utility functions to streamline your Flutter development workflow. This package includes safe parsing utilities, string manipulation extensions, list operations, and more.

✨ Features #

  • πŸ”§ Safe Parsing: Robust JSON parsing with double-encoding prevention and error handling
  • πŸ“ String Extensions: Case-insensitive comparisons, JSON validation, type conversions, and utility methods
  • πŸ“‹ List Utilities: Smart list operations with duplicate prevention and safe parsing extensions
  • πŸ”’ Iterable Extensions: Safe element access and advanced operations
  • 🎨 Color Extensions: Enhanced color manipulation utilities with hex conversion
  • πŸ“… DateTime Extensions: Comprehensive date/time formatting, calculations, and comparisons
  • πŸ—ΊοΈ Map Extensions: Safe map parsing and utility functions for all data types
  • πŸ“Š Base Data Models: Abstract classes for consistent data handling with JSON serialization
  • ⚑ Safe SetState Extensions: Prevent setState calls on disposed widgets
  • 🌐 Safe URL Launcher: Comprehensive URL launching with fallback support and user feedback
  • πŸ”„ Object Serialization: Powerful serialization/deserialization for complex data types
  • πŸ›‘οΈ Type Safety: Full null safety support with comprehensive type checking
  • πŸ› Safe Debug Logging: Debug-safe logging utility
  • πŸ§ͺ Comprehensive Testing: Extensive test coverage including edge cases

πŸ“¦ Installation #

Add this to your package's pubspec.yaml file:

dependencies:
  flutter_shared_utilities: ^x.y.z

Then run:

flutter pub get

πŸš€ Quick Start #

import 'package:flutter_shared_utilities/flutter_shared_utilities.dart';

void main() {
  // String utilities
  String? text = "Hello World";
  bool isNullEmpty = text.isNullEmpty; // false
  bool startsWith = text.startsWithIgnoreCase("hello"); // true

  // Safe JSON parsing with double-encoding prevention
  String jsonString = '{"name": "John", "age": 30}';
  final parsed = SafeParser.safeDecodeJson(jsonString);

  // No double-encoding - already valid JSON preserved
  String alreadyEncoded = SafeParser.safeEncodeJson('"hello"');
  // β†’ '"hello"' (correct, not "\"hello\"")

  // DateTime utilities
  DateTime now = DateTime.now();
  DateTime birthday = DateTime(1990, 5, 15);

  String timeString = now.toTimeString();        // "14:30:25"
  String dateString = now.toDateString();        // "15/12/2023"
  String dateTime = now.toDateTimeString();      // "15/12/2023 14:30"
  String time12Hour = now.to12Hour();            // "2:30 PM"

  bool isToday = now.isToday;                    // true
  bool isWeekend = now.isWeekend;                // depends on day
  int age = birthday.ageInYears;                 // 33
  String relative = birthday.relativeTime;       // "33 years ago"

  // List utilities
  List<String> fruits = ['apple', 'banana'];
  fruits.addAllIfNotExists(['apple', 'orange']); // Only adds 'orange'

  // Safe URL launching
  bool launched = await SafeUrlLauncher.launch('https://example.com');

  // Launch with callbacks for success/failure handling
  await SafeUrlLauncher.launchWithFeedback(
    context,
    'https://example.com',
    errorMessage: 'Could not open website. Please try again.',
  );

  // Email with subject and body
  await SafeUrlLauncher.launchEmail(
    'support@example.com',
    subject: 'Help Request',
    body: 'I need assistance with...',
  );
}

// Safe SetState in StatefulWidget
class MyWidget extends StatefulWidget {
  @override
  State<MyWidget> createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  int _counter = 0;

  void _incrementCounter() {
    // Safe setState - prevents calls on disposed widgets
    safeSetState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Text('Counter: $_counter');
  }
}

πŸ“š Complete API Reference #

πŸ“ String Extensions #

StringUtilExtensions

Provides utility methods for string manipulation and validation:

String? text = "Hello World";

// Case-insensitive operations
bool equals = text.compareWithoutCase("hello world"); // true
bool startsWith = text.startsWithIgnoreCase("hello"); // true
bool contains = text.containsWithoutCase("world"); // true
bool matchesAny = text.compareWithoutCaseAny(["hello world", "hi"]); // true

// Null/empty checks
bool isNull = text.isNullString; // false
bool isEmpty = text.isNullEmpty; // false

// JSON validation
bool isObject = '{"key": "value"}'.isJsonObject; // true
bool isArray = '[1, 2, 3]'.isJsonArray; // true
bool isPrimitive = '"string"'.isJsonPrimitive; // true

StringTypeConversionExtensions

Provides type conversion methods for strings:

String colorString = "#FF5733";
String enumString = "active";

// Enum conversion
enum Status { active, inactive }
Status? status = enumString.toEnum(Status.values); // Status.active

// Color conversion with multiple format support
Color? color = colorString.toColor(); // Color from hex

// Automatic format detection based on prefix
Color? argbColor = "0xFFFF5733".toColor(); // ARGB format (0x prefix)
Color? rgbaColor = "#FF5733FF".toColor(); // RGBA format (# prefix)
Color? shortColor = "#ABC".toColor(); // Short RGB format

// Complex type checking
bool isComplex = "List<String>".isComplexType; // true

πŸ“‹ List Extensions #

ListUtilExtensions

Smart list operations with duplicate prevention:

List<String> items = ['apple', 'banana'];

// Insert if not exists
bool inserted = items.insertIfNotExists('apple', index: 0); // false
bool inserted2 = items.insertIfNotExists('orange', index: 1); // true

// Add all if not exists
items.addAllIfNotExists(['apple', 'grape', 'banana']); // Only adds 'grape'

// Remove if exists
bool removed = items.removeIfExist('apple'); // true

// Custom equality checker
bool added = items.addAllIfNotExists(
  ['APPLE', 'GRAPE'],
  equalityChecker: (a, b) => a.toLowerCase() == b.toLowerCase(),
);

ListParserExtensions

Advanced list parsing and type conversion:

List<Object?> rawList = [1, "2", 3.0, true];

// Serialize list items
List<Object?> serialized = rawList.serializeListItems;

// Deserialize to specific types
List<int>? intList = rawList.deserializeListByType<int>(); // [1, 2, 3, 1]
List<String>? stringList = rawList.deserializeListByType<String>(); // ["1", "2", "3.0", "true"]

// Handle nested lists
List<List<String>>? nestedList = complexList.deserializeListItems<List<List<String>>>();

// Cast to specific types
List<Object?>? typedList = rawList.castListToTypes('int'); // [1, 2, 3, 1]

πŸ”’ Iterable Extensions #

IterableUtilExtensions

Safe element access and advanced operations:

List<String> items = ['apple', 'banana', 'cherry'];

// Safe access methods
String? first = items.safeFirst; // 'apple'
String? last = items.safeLast; // 'cherry'
String? atIndex = items.safeAt(10); // null (safe bounds checking)

// Existence checking with custom equality
bool exists = items.exists('APPLE',
  equalityChecker: (a, b) => a.toLowerCase() == b.toLowerCase()
); // true

// Enum handling
enum Color { red, green, blue }
List<Color> colors = Color.values;
Color? found = colors.byNameSafe('red'); // Color.red

πŸ—ΊοΈ Map Extensions #

MapParserExtensions

Safe map parsing with comprehensive type support:

Map<dynamic, dynamic> data = {
  'name': 'John',
  'age': '30',
  'isActive': 'true',
  'score': '95.5',
  'birthDate': '2023-01-01T00:00:00.000Z',
  'preferences': {'theme': 'dark'},
  'tags': ['developer', 'flutter']
};

// Safe parsing with automatic type conversion
String? name = data.parse<String>('name'); // 'John'
int? age = data.parse<int>('age'); // 30
bool? isActive = data.parse<bool>('isActive'); // true
double? score = data.parse<double>('score'); // 95.5
DateTime? birthDate = data.parse<DateTime>('birthDate'); // DateTime object
Map<String, Object?>? prefs = data.parse<Map<String, Object?>>('preferences');
List<String>? tags = data.parse<List<String>>('tags');

// Parse with default values
int age = data.parseDefault<int>('age', 0); // 30 or 0 if null/invalid
String status = data.parseDefault<String>('status', 'unknown'); // 'unknown'

🎨 Color Extensions #

ColorExtensions

Enhanced color manipulation utilities:

Color color = Color(0xFF5733FF);

// Hex conversion
String hex = color.toHex(); // '#5733FF'
String hexNoHash = color.toHex(leadingHashSign: false); // '5733FF'

// With alpha support
Color semiTransparent = Color(0x805733FF);
String hexWithAlpha = semiTransparent.toHex(); // '#5733FF80'

πŸ“… DateTime Extensions #

DateTimeExtensions

Comprehensive DateTime utility extensions providing formatting, calculations, and comparisons for Flutter apps:

DateTime now = DateTime.now();
DateTime birthday = DateTime(1990, 5, 15, 14, 30, 25);
DateTime meeting = DateTime.now().add(Duration(hours: 2));

// String conversion methods
String timeString = now.toTimeString();        // "14:30:25"
String timeShort = now.toTimeShort();          // "14:30"
String dateString = now.toDateString();        // "15/12/2023"
String dateUS = now.toDateUS();                // "12/15/2023"
String dateISO = now.toDateISO();              // "2023-12-15"
String dateTime = now.toDateTimeString();      // "15/12/2023 14:30"
String dateTimeFull = now.toDateTimeFull();    // "15/12/2023 14:30:25"
String time12Hour = now.to12Hour();            // "2:30 PM"

// Date comparison properties
bool isToday = now.isToday;                    // true
bool isYesterday = birthday.isYesterday;       // false
bool isTomorrow = meeting.isTomorrow;          // false
bool isThisWeek = now.isThisWeek;              // true
bool isThisMonth = birthday.isThisMonth;       // false
bool isThisYear = birthday.isThisYear;         // false
bool isWeekend = now.isWeekend;                // depends on current day
bool isWeekday = now.isWeekday;                // !isWeekend
bool isAM = now.isAM;                          // false (if 14:30)
bool isPM = now.isPM;                          // true (if 14:30)
bool isLeapYear = birthday.isLeapYear;         // depends on year

// Date boundaries
DateTime startDay = now.startOfDay;            // 2023-12-15 00:00:00.000
DateTime endDay = now.endOfDay;                // 2023-12-15 23:59:59.999
DateTime startWeek = now.startOfWeek;          // Monday 00:00:00
DateTime endWeek = now.endOfWeek;              // Sunday 23:59:59.999
DateTime startMonth = now.startOfMonth;        // 2023-12-01 00:00:00.000
DateTime endMonth = now.endOfMonth;            // 2023-12-31 23:59:59.999
DateTime startYear = now.startOfYear;          // 2023-01-01 00:00:00.000
DateTime endYear = now.endOfYear;              // 2023-12-31 23:59:59.999

// Date arithmetic with smart overflow handling
DateTime nextWeek = now.addDays(7);
DateTime lastMonth = now.subtractMonths(1);    // Handles month overflow properly
DateTime nextYear = now.addYears(1);
DateTime futureDate = now.addMonths(13);       // Smart month/year calculation

// Utility properties
int age = birthday.ageInYears;                 // 33 (if 2023)
int daysFromNow = birthday.daysFromNow;        // Positive number (past)
int daysToNow = meeting.daysToNow;             // Negative number (future)
String relative = birthday.relativeTime;       // "33 years ago"
String futureRelative = meeting.relativeTime;  // "in 2 hours"
String monthName = now.monthName;              // "December"
String monthShort = now.monthNameShort;        // "Dec"
String weekdayName = now.weekdayName;          // "Friday"
String weekdayShort = now.weekdayNameShort;    // "Fri"
int daysInMonth = now.daysInMonth;             // 31 (for December)
int quarter = now.quarter;                     // 4 (for December)

// Date comparisons with other DateTime objects
DateTime other = DateTime(2023, 12, 15, 10, 0);
bool sameDay = now.isSameDay(other);           // true (same calendar day)
bool sameWeek = now.isSameWeek(other);         // true (same week)
bool sameMonth = now.isSameMonth(other);       // true (both December 2023)
bool sameYear = now.isSameYear(other);         // true (both 2023)

Available String Conversion Methods:

  • toTimeString() - HH:MM:SS format with leading zeros
  • toTimeShort() - HH:MM format with leading zeros
  • toDateString() - DD/MM/YYYY format
  • toDateUS() - MM/DD/YYYY US format
  • toDateISO() - YYYY-MM-DD ISO format
  • toDateTimeString() - DD/MM/YYYY HH:MM format
  • toDateTimeFull() - DD/MM/YYYY HH:MM:SS format
  • to12Hour() - 12-hour format with AM/PM

Available Comparison Properties:

  • isToday, isYesterday, isTomorrow - Relative to current date
  • isThisWeek, isThisMonth, isThisYear - Current time period checks
  • isWeekend, isWeekday - Day type classification
  • isAM, isPM - Time period classification
  • isLeapYear - Leap year validation

Available Boundary Properties:

  • startOfDay, endOfDay - Day boundaries (00:00:00 to 23:59:59.999)
  • startOfWeek, endOfWeek - Week boundaries (Monday to Sunday)
  • startOfMonth, endOfMonth - Month boundaries
  • startOfYear, endOfYear - Year boundaries

Available Arithmetic Methods:

  • addDays(int), subtractDays(int) - Day arithmetic
  • addMonths(int), subtractMonths(int) - Smart month arithmetic with overflow handling
  • addYears(int), subtractYears(int) - Year arithmetic

Available Utility Properties:

  • ageInYears - Calculate age from birthdate
  • daysFromNow, daysToNow - Days difference calculations
  • relativeTime - Human-readable relative time strings
  • monthName, monthNameShort - Month name properties
  • weekdayName, weekdayNameShort - Weekday name properties
  • daysInMonth - Days count in current month
  • quarter - Quarter of the year (1-4)

Available Comparison Methods:

  • isSameDay(DateTime) - Same calendar day comparison
  • isSameWeek(DateTime) - Same week comparison
  • isSameMonth(DateTime) - Same month comparison
  • isSameYear(DateTime) - Same year comparison

Key Features:

  • πŸ•’ Multiple Time Formats - 24-hour, 12-hour, short and full formats
  • πŸ“… Various Date Formats - International, US, and ISO formats
  • πŸ” Smart Comparisons - Intuitive date and time period comparisons
  • πŸ“Š Boundary Calculations - Precise start/end of periods
  • βž• Safe Arithmetic - Proper month overflow handling (Jan 31 + 1 month = Feb 28/29)
  • 🌍 Human-Readable - Relative time strings like "2 hours ago", "tomorrow"
  • πŸ“ Rich Information - Month names, weekday names, quarter information
  • πŸ›‘οΈ Error Safety - Safe array access with fallback values for edge cases

πŸ”„ Object Serialization Extensions #

SerializationExtensions

Powerful serialization and deserialization for complex data types:

// Serialization - converts any object to JSON-safe format
Map<String, dynamic> complexData = {
  'name': 'John',
  'birthDate': DateTime.now(),
  'tags': ['developer', 'flutter'],
  'settings': {'theme': 'dark', 'notifications': true}
};

Object? serialized = complexData.toSerializable;

// Deserialization with comprehensive type support
Object? rawValue = '{"name": "John", "age": 30}';

// Basic types
String? name = rawValue.fromSerializable<String>();
int? age = rawValue.fromSerializable<int>();
double? score = rawValue.fromSerializable<double>();
bool? isActive = rawValue.fromSerializable<bool>();
DateTime? date = rawValue.fromSerializable<DateTime>();
Duration? duration = rawValue.fromSerializable<Duration>();
Uri? website = rawValue.fromSerializable<Uri>();

// Collections
List<String>? tags = rawValue.fromSerializable<List<String>>();
List<int>? numbers = rawValue.fromSerializable<List<int>>();
Map<String, Object?>? data = rawValue.fromSerializable<Map<String, Object?>>();
Map<String, String>? stringMap = rawValue.fromSerializable<Map<String, String>>();

// Complex nested types
List<Map<String, Object?>>? listOfMaps = rawValue.fromSerializable<List<Map<String, Object?>>>();

// With default values
String name = rawValue.fromSerializableDefault<String>('Unknown');
int age = rawValue.fromSerializableDefault<int>(0);

// Safe conversions
Map<String, Object?>? asMap = rawValue.toMap();
List<Object?>? asList = rawValue.toList();

Supported Types:

  • Primitives: String, int, double, bool, DateTime, Duration, Uri, Uint8List
  • Collections: List<T>, Set<T>, Map<String, T> where T is any supported type
  • Nested Collections: List<List<T>>, List<Map<String, T>>, etc.
  • Special Types: Enums, custom objects implementing BaseDataModel

πŸ“Š Base Data Model #

BaseDataModel

Abstract class for consistent data model implementation with automatic JSON handling:

class User extends BaseDataModel<User> {
  final String name;
  final int age;
  final List<String> hobbies;
  final Map<String, dynamic> metadata;

  const User({
    required this.name,
    required this.age,
    required this.hobbies,
    required this.metadata,
  });

  @override
  User fromMap(Map<String, dynamic> map) {
    return User(
      name: map['name'] as String,
      age: map['age'] as int,
      hobbies: List<String>.from(map['hobbies'] as List),
      metadata: Map<String, dynamic>.from(map['metadata'] as Map),
    );
  }

  @override
  Map<String, dynamic> toMap() {
    return {
      'name': name,
      'age': age,
      'hobbies': hobbies,
      'metadata': metadata,
    };
  }

  @override
  List<Object?> get props => [name, age, hobbies, metadata];
}

// Usage
final user = User(
  name: 'John',
  age: 30,
  hobbies: ['coding', 'reading'],
  metadata: {'role': 'developer'}
);

// Automatic JSON serialization/deserialization
String json = user.toJson();
User fromJson = user.fromJson(json);
Map<String, dynamic> map = user.toMap();
User fromMap = user.fromMap(map);

⚑ Safe SetState Extensions #

StateExtensions

Prevent setState calls on disposed widgets:

class MyWidget extends StatefulWidget {
  @override
  State<MyWidget> createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  bool _isLoading = false;
  int _counter = 0;

  void _updateCounter() {
    // Safe setState - checks if widget is mounted
    bool success = safeSetState(() {
      _counter++;
    });
    // Returns true if setState was called, false if widget was disposed
  }

  Future<void> _loadData() async {
    safeSetState(() {
      _isLoading = true;
    });

    // Simulate async work
    await Future.delayed(Duration(seconds: 2));

    // Safe setState after async operation
    safeSetState(() {
      _isLoading = false;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text('Counter: $_counter'),
        if (_isLoading) CircularProgressIndicator(),
      ],
    );
  }
}

Available Methods:

  • safeSetState(VoidCallback fn) - Basic safe setState with mounted check

Returns bool indicating success/failure and prevents the common error: "setState() called after dispose()".

🌐 Safe URL Launcher #

SafeUrlLauncher

Comprehensive URL launching utility with fallback support, validation, and user feedback:

// Basic URL launch with automatic fallback
bool success = await SafeUrlLauncher.launch('https://example.com');

// Custom launch modes with fallback
bool launched = await SafeUrlLauncher.launch(
  'https://example.com',
  preferredMode: LaunchMode.inAppWebView,
  fallbackMode: LaunchMode.externalApplication,
  webOnlyWindowName: 'myWindow',
);

// Launch with user feedback (shows SnackBar on failure)
await SafeUrlLauncher.launchWithFeedback(
  context,
  'https://example.com',
  errorMessage: 'Could not open website. Please try again.',
  preferredMode: LaunchMode.externalApplication,
  fallbackMode: LaunchMode.inAppWebView,
);

// Specific URL types
bool webLaunched = await SafeUrlLauncher.launchWebUrl('https://flutter.cn');

// Email with pre-filled content
bool emailSent = await SafeUrlLauncher.launchEmail(
  'support@example.com',
  subject: 'Bug Report',
  body: 'I found an issue with...',
);

// Phone dialer
bool phoneOpened = await SafeUrlLauncher.launchPhone('+1234567890');

// SMS with pre-filled message
bool smsOpened = await SafeUrlLauncher.launchSms(
  '+1234567890',
  message: 'Hello from my app!',
);

// URL validation and capability checking
bool isValid = SafeUrlLauncher.isValidUrl('https://example.com'); // true
bool canOpen = await SafeUrlLauncher.canLaunch('tel:+1234567890'); // true

Available Methods:

  • launch(String url, {...}) - Launch any URL with fallback support
  • launchWithFeedback(BuildContext context, String url, {...}) - Launch with SnackBar feedback
  • launchWebUrl(String url, {...}) - Launch web URLs specifically
  • launchEmail(String email, {subject, body}) - Launch email client
  • launchPhone(String phoneNumber) - Launch phone dialer
  • launchSms(String phoneNumber, {message}) - Launch SMS client
  • canLaunch(String url) - Check if URL can be launched
  • isValidUrl(String url) - Validate URL format

Key Features:

  • πŸ”„ Fallback Support - Tries preferred mode, falls back automatically
  • πŸ“± User Feedback - Built-in SnackBar integration for error handling
  • 🌐 Multiple Schemes - Supports HTTP/HTTPS, mailto, tel, sms URLs
  • πŸ›‘οΈ Safe Validation - Comprehensive URL format validation
  • πŸ“§ Email Support - Pre-filled subject, body, and recipient
  • πŸ“ž Phone Integration - Direct dialer launching with number cleaning
  • πŸ’¬ SMS Support - Pre-filled SMS messages
  • 🚨 Error Handling - Graceful failures with detailed logging
  • 🎯 Context Safety - Handles disposed widgets and null contexts

πŸ”§ Safe Parser #

SafeParser

Robust JSON parsing with error handling and intelligent double-encoding prevention:

// Safe JSON encoding - prevents double-encoding
String encoded = SafeParser.safeEncodeJson({'name': 'John', 'age': 30});
// β†’ '{"name":"John","age":30}'

// Already encoded JSON is preserved (no double-encoding)
String alreadyEncoded = SafeParser.safeEncodeJson('"hello"');
// β†’ '"hello"' (NOT "\"hello\"")

String jsonObject = SafeParser.safeEncodeJson('{"existing": "json"}');
// β†’ '{"existing": "json"}' (preserves valid JSON)

// Safe JSON decoding with fallback handling
Object? decoded = SafeParser.safeDecodeJson('{"name": "John", "age": 30}');
// β†’ Map<String, dynamic>

// Handles malformed JSON gracefully
Object? fallback = SafeParser.safeDecodeJson('{invalid json}');
// β†’ '{invalid json}' (returns original string as fallback)

// Round-trip consistency guaranteed
String original = 'Hello, δΈ–η•Œ! πŸš€';
String encoded = SafeParser.safeEncodeJson(original);
Object? decoded = SafeParser.safeDecodeJson(encoded);
// original == decoded βœ…

Key Features:

  • πŸ›‘οΈ Double-encoding prevention - Intelligently detects already-encoded JSON
  • 🌐 Unicode support - Handles special characters and emojis correctly
  • πŸ”„ Round-trip consistency - Encode β†’ Decode operations are symmetric
  • 🚨 Graceful error handling - Never crashes, provides sensible fallbacks
  • πŸ“ Comprehensive logging - Debug-friendly error reporting

πŸ› Safe Debug Logging #

safeDebugLog

Debug-safe logging utility that only logs in debug mode:

// Basic logging
safeDebugLog('Debug message');

// With stack trace
safeDebugLog('Error occurred', stackTrace: StackTrace.current);

// Any object can be logged
safeDebugLog({'key': 'value', 'number': 123});
safeDebugLog(['item1', 'item2', 'item3']);

Features:

  • Only logs in debug mode (kDebugMode)
  • Supports any object type
  • Optional stack trace logging
  • Uses dart:developer log function for better debugging

πŸ§ͺ Testing #

The package includes comprehensive tests for all functionality with 180+ total tests covering every feature:

Test Coverage #

  • βœ… SafeParser Tests (26 tests) - Complete coverage including double-encoding prevention
  • βœ… MapParserExtensions Tests (52 tests) - All type conversions and edge cases
  • βœ… SafeUrlLauncher Tests (12+ tests) - URL validation, scheme handling, and safety checks
  • βœ… Serialization Extensions Tests - Complex type handling and validation
  • βœ… String Utility Tests - Case-insensitive operations and JSON validation
  • βœ… List Utility Tests - Duplicate prevention and smart operations
  • βœ… Iterable Utility Tests - Safe access and advanced operations
  • βœ… Color Extension Tests - Hex conversion and color manipulation
  • βœ… Base Data Model Tests - Model conversion and serialization
  • βœ… Widget State Tests - Safe setState functionality

Test Quality Standards #

  • πŸ›‘οΈ Safe Type Checking - No null force operators (!) or unsafe casting (as)
  • πŸ” Bounds Checking - All array access is bounds-checked
  • 🌐 Unicode Testing - Special characters, emojis, and international text
  • πŸ”„ Round-trip Verification - Encode/decode consistency validation
  • 🚨 Error Handling - Graceful failure and fallback behavior testing
  • πŸ“Š Edge Cases - Empty data, null values, malformed inputs, large datasets

Running Tests #

# Run all tests
flutter test

# Run specific test files
flutter test test/utils/safe_parser_test.dart
flutter test test/extensions/map/map_parser_extensions_test.dart

# Run with coverage
flutter test --coverage

Test Results #

180+/180+ tests passing βœ…
100% test coverage on critical functionality

🀝 Contributing #

Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

πŸ“„ License #

This project is licensed under the MIT License - see the LICENSE file for details.

πŸ› Issues and Feedback #

Please file issues and feature requests on the GitHub repository.

πŸ“ˆ Version History #

See CHANGELOG.md for a detailed version history.


Made with ❀️ for the Flutter community

1
likes
160
points
525
downloads

Publisher

unverified uploader

Weekly Downloads

A comprehensive Flutter utilities package with extensions, models, and utility functions.

Repository (GitHub)
View/report issues

Topics

#utilities #extensions #utils #base #helpers

Documentation

API reference

License

MIT (license)

Dependencies

collection, equatable, flutter, url_launcher

More

Packages that depend on flutter_shared_utilities