HandyExtensions
Developed with π by Ngonidzashe Mangudya
Handy Extension is a comprehensive library with extensions to Dart's core types and Flutter's BuildContext to make development more efficient and code more readable.
I don't know how "deadly" this is but I just use it anyway.
Extensions On:
- BuildContext
- String
- int/num
- List
- DateTime
- Map
- Iterable
- Nullable types (String?, int?, List?, Iterable?)
- General extensions for any type
Getting started
Add as a dependency
dependencies:
handy_extensions: <version>
Usage
BuildContext
Get Screen Dimensions
// Get screen height
double screenHeight = context.height;
// Get screen width
double screenWidth = context.width;
String
Country Code to Emoji
String country = 'ZW';
String emoji = country.countryEmoji; // => πΏπΌ
Text Case Transformations
String title = 'hello world';
String titleCase = title.titleCase; // => Hello world
String headingCase = title.headingCase; // => Hello World
String Parsing
String number = '42.5';
// Check if string is numeric
bool isNum = number.isNumeric; // => true
// Parse to double or int safely
double? doubleValue = number.toDoubleOrNull; // => 42.5
int? intValue = '42'.toIntOrNull; // => 42
String Comparisons
String text = 'Hello';
// Case-insensitive matching
bool matches = text.matches('hello'); // => true
// Check if all uppercase
bool isUpper = 'HELLO'.isAllCaps; // => true
// Check if strings have same characters (different order)
bool sameChars = 'hello'.hasSameCharacters('olleh'); // => true
List
Partitioning
List<int> numbers = [1, 2, 3, 4, 5, 6];
// Split into chunks
List<List<int>> chunks = numbers.partition(chunkSize: 3);
// => [[1, 2, 3], [4, 5, 6]]
// Partition based on condition
List<List<int>> evenOdd = numbers.partitionWhere((n) => n.isEven);
// => [[2, 4, 6], [1, 3, 5]]
// Split into equal-sized sublists
List<List<int>> split = numbers.splitInto(chunkSize: 2);
// => [[1, 2, 3], [4, 5, 6]]
Random Selection
List<String> words = ["Hello", "World", "Dart"];
// Get random item
String randomWord = words.randomItem();
// Get multiple random items (no duplicates)
List<String> randomWords = words.randomItems(count: 2);
Safe Operations
List<String> items = ['a', 'b', 'c'];
// Safe first where operation
String? found = items.firstWhereOrNull((item) => item == 'a'); // => 'a'
// Safe index access
String? item = items.getAt(1); // => 'b'
String? invalid = items.getAt(10); // => null
// Check if index is valid
bool valid = items.isValidIndex(1); // => true
Grouping and Organization
List<Map<String, dynamic>> movies = [
{"title": "Avengers", "year": "2019"},
{"title": "Creed", "year": "2019"},
{"title": "Jumanji", "year": "2020"},
];
// Group by field
Map<String, List<Map<String, dynamic>>> grouped =
movies.groupBy((m) => m["year"]);
List Manipulation
List<int> numbers = [1, 2, 3, 4, 5];
// Swap elements
numbers.swap(0, 4); // [5, 2, 3, 4, 1]
// Swap ranges
numbers.swapRange(0, 2, 3); // [4, 5, 3, 1, 2]
// Check for duplicates
bool hasDups = [1, 2, 3, 2].hasDuplicates(); // => true
// Check if contains any of multiple items
bool containsAny = numbers.containsSome([6, 7, 8]); // => false
// Compare lists regardless of order
bool same = [1, 2, 3].same([3, 1, 2]); // => true
Update Operations
List<int> numbers = [1, 2, 3, 4, 5];
// Update elements matching condition
numbers.updateWhere(
(n) => n.isEven, // predicate
(n) => n * 2, // update function
);
// Result: [1, 4, 3, 8, 5]
// Update or create if no matches found
List<String> users = ['alice', 'bob'];
bool updated = users.updateWhereOrCreate(
(user) => user.startsWith('c'),
(user) => user.toUpperCase(),
() => 'charlie', // created if no 'c' names found
);
Map
Map Transformations
Map<String, int> original = {'a': 1, 'b': 2, 'c': 3};
// Swap keys and values
Map<int, String> swapped = original.swap; // {1: 'a', 2: 'b', 3: 'c'}
// Create a copy
Map<String, int> copied = original.copy;
// Remove null values
Map<String, int?> withNulls = {'a': 1, 'b': null, 'c': 3};
Map<String, int?> cleaned = withNulls.removeNulls; // {'a': 1, 'c': 3}
Map Operations
Map<String, int> map = {'a': 1, 'b': 2, 'c': 3, 'd': 4};
// Reorder entries
Map<String, int> reordered = map.adjustOrder(1, 3);
// Get value or default
int value = map.getOrDefault('e', 0); // => 0
DateTime
Readable Formats
DateTime date = DateTime(2022, 3, 15, 14, 30, 45);
// Various readable formats
String readable = date.readableDate; // => Tuesday 15 March 2022
String readableDateTime = date.readableDateTime; // => March 15, 2022 14:30:45
String time = date.readableTime; // => 14:30:45
String timeFormat = date.timeFormat; // => 02:30pm
String combined = date.readableDateTimeFormat; // => Tuesday 15 March 2022, 02:30pm
Date Components
DateTime date = DateTime(2022, 3, 15);
// Get components
String day = date.getDay; // => Tuesday
String shortDay = date.getShortDay; // => Tue
int dayOfMonth = date.getDate; // => 15
String month = date.getMonth; // => March
String shortMonth = date.getShortMonth; // => Mar
String year = date.getYear; // => 2022
Time Intelligence
DateTime now = DateTime.now();
DateTime past = now.subtract(Duration(hours: 2));
// Time ago
String ago = past.timeAgo; // => 2h
// Time of day
String timeOfDay = DateTime(2022, 1, 1, 9, 0).timeOfDayStr; // => Morning
String emoji = DateTime(2022, 1, 1, 21, 0).timeOfDayEmoji; // => π
// Smart description
String desc = past.describe; // => 02:30pm (for today) or Yesterday, etc.
Date Comparisons
DateTime date1 = DateTime(2022, 3, 15, 9, 0);
DateTime date2 = DateTime(2022, 3, 15, 18, 0);
DateTime date3 = DateTime(2022, 3, 16);
// Check if same day (ignoring time)
bool sameDay = date1.isSameDayForYear(date2); // => true
// Check if same day/month (ignoring year)
bool sameDayMonth = date1.isSameDay(DateTime(2023, 3, 15)); // => true
// Check if between dates
bool between = date1.isBetween(
DateTime(2022, 1, 1),
DateTime(2022, 12, 31)
); // => true
Num/Int
Duration Creation
// Create durations easily
Duration micro = 500.microseconds;
Duration milli = 1500.milliseconds; // or 1500.ms
Duration sec = 30.seconds;
Duration min = 5.minutes;
Duration hr = 2.hours;
Duration day = 3.days;
Duration week = 2.weeks;
Duration month = 1.months; // ~30.44 days
Duration year = 1.years; // calculated based on current date
// Combine durations
Duration total = 1.weeks + 2.days + 3.hours + 4.minutes;
Number Operations
// Check if number is in range
bool inRange = 5.isBetween(1, 10); // => true
Iterable
Interspersing Elements
List<String> words = ["Hello", "World", "Dart"];
// Insert separator between elements
Iterable<String> withCommas = words.intersperse(",");
// Result: [Hello, ,, World, ,, Dart]
// Insert separators conditionally
Iterable<int> numbers = [1, 2, 3, 4, 5];
Iterable<dynamic> conditional = numbers.intersperseWith(
(n) => n.isEven ? ':' : null
);
// Result: [1, 2, :, 3, 4, :, 5]
// Insert at specific index
Iterable<String> atIndex = words.intersperseAt(1, '-');
// Result: [Hello, World, -, Dart]
// Insert at end
Iterable<String> atEnd = words.intersperseAtLast('!');
// Result: [Hello, World, Dart, !]
Nullable Extensions
Nullable String
String? name = null;
String? greeting = 'Hello';
// Check if string (not null)
bool isString = name.isString; // => false
bool isGreeting = greeting.isString; // => true
// Get value or empty string
String safe = name.orEmpty; // => ''
String value = greeting.orEmpty; // => 'Hello'
// Check if not null and not empty/whitespace
bool hasContent = name.isNotReallyEmpty; // => false
bool greetingHasContent = greeting.isNotReallyEmpty; // => true
Nullable Int
int? number = null;
int? value = 42;
// Check if int (not null)
bool isInt = number.isInt; // => false
bool isValue = value.isInt; // => true
Nullable List
List<int?> numbers = [1, null, 3, 4];
// Find first element matching condition (handles nulls safely)
int? firstEven = numbers.firstOrNullWhere((n) => n != null && n.isEven); // => 4
int? firstNull = numbers.firstOrNullWhere((n) => n == null); // => null
Nullable Iterable
Iterable<String?> items = ['hello', null, 'world', null];
// Remove all null elements
Iterable<String> nonNull = items.withoutNullElements();
// Result: ['hello', 'world']
General Extensions
Available on any type:
// Apply a function to any value
int result = 5.let((it) => it * 2); // => 10
String processed = "hello".let((s) => s.toUpperCase()); // => "HELLO"
// Check if any value is null
bool isNull = someValue.isNull;
Utility Types
The library also includes utility enums:
enum HapticFeedbackType {
light,
medium,
heavy,
selection,
vibrate,
}
Additional Information
This library provides over 100 extension methods across Dart's core types and Flutter's BuildContext. All extensions are designed to be intuitive, well-documented, and thoroughly tested.
You can contribute additional extensions to help make Dart development even more efficient!
Libraries
- handy_extensions
- This library is a collection of handy extensions for Dart's core types.