Added int, gmaps and context extensions
This commit is contained in:
parent
fad2c2e73b
commit
59540a9e04
8 changed files with 133 additions and 88 deletions
|
@ -2,15 +2,21 @@ import 'package:flutter/material.dart';
|
||||||
|
|
||||||
extension OpenColorExtensions on Color {
|
extension OpenColorExtensions on Color {
|
||||||
static Color fromHex(String hexString) {
|
static Color fromHex(String hexString) {
|
||||||
|
final cleanedHex = hexString.replaceFirst('#', '');
|
||||||
final buffer = StringBuffer();
|
final buffer = StringBuffer();
|
||||||
if (hexString.length == 6 || hexString.length == 7) buffer.write('ff');
|
if (cleanedHex.length == 6) buffer.write('ff');
|
||||||
buffer.write(hexString.replaceFirst('#', ''));
|
buffer.write(cleanedHex);
|
||||||
return Color(int.parse(buffer.toString(), radix: 16));
|
return Color(int.parse(buffer.toString(), radix: 16));
|
||||||
}
|
}
|
||||||
|
|
||||||
String toHex({bool leadingHashSign = true}) => '${leadingHashSign ? '#' : ''}'
|
String toHex({bool leadingHashSign = true}) {
|
||||||
'${alpha.toRadixString(16).padLeft(2, '0')}'
|
final hex = [
|
||||||
'${red.toRadixString(16).padLeft(2, '0')}'
|
alpha.toRadixString(16).padLeft(2, '0'),
|
||||||
'${green.toRadixString(16).padLeft(2, '0')}'
|
red.toRadixString(16).padLeft(2, '0'),
|
||||||
'${blue.toRadixString(16).padLeft(2, '0')}';
|
green.toRadixString(16).padLeft(2, '0'),
|
||||||
|
blue.toRadixString(16).padLeft(2, '0'),
|
||||||
|
].join();
|
||||||
|
|
||||||
|
return '${leadingHashSign ? '#' : ''}$hex';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,43 +1,30 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
extension OpenContextExtensions on BuildContext {
|
extension OpenContextExtensions on BuildContext {
|
||||||
bool get isMobile => MediaQuery.of(this).size.width <= 500.0;
|
// Screen size properties
|
||||||
|
double get width => mediaQuery.size.width;
|
||||||
|
double get height => mediaQuery.size.height;
|
||||||
|
Size get size => mediaQuery.size;
|
||||||
|
|
||||||
bool get isTablet =>
|
// Screen type properties
|
||||||
MediaQuery.of(this).size.width < 1024.0 &&
|
bool get isMobile => width <= 500.0;
|
||||||
MediaQuery.of(this).size.width >= 650.0;
|
bool get isTablet => width >= 650.0 && width < 1024.0;
|
||||||
|
bool get isSmallTablet => width > 500.0 && width < 650.0;
|
||||||
bool get isSmallTablet =>
|
bool get isDesktop => width >= 1024.0;
|
||||||
MediaQuery.of(this).size.width < 650.0 &&
|
bool get isSmall => width >= 560.0 && width < 850.0;
|
||||||
MediaQuery.of(this).size.width > 500.0;
|
|
||||||
|
|
||||||
bool get isDesktop => MediaQuery.of(this).size.width >= 1024.0;
|
|
||||||
|
|
||||||
bool get isSmall =>
|
|
||||||
MediaQuery.of(this).size.width < 850.0 &&
|
|
||||||
MediaQuery.of(this).size.width >= 560.0;
|
|
||||||
|
|
||||||
double get width => MediaQuery.of(this).size.width;
|
|
||||||
|
|
||||||
double get height => MediaQuery.of(this).size.height;
|
|
||||||
|
|
||||||
Size get size => MediaQuery.of(this).size;
|
|
||||||
|
|
||||||
|
// Theme and styling
|
||||||
ThemeData get theme => Theme.of(this);
|
ThemeData get theme => Theme.of(this);
|
||||||
|
|
||||||
TextTheme get textTheme => theme.textTheme;
|
TextTheme get textTheme => theme.textTheme;
|
||||||
|
|
||||||
ColorScheme get colorScheme => theme.colorScheme;
|
ColorScheme get colorScheme => theme.colorScheme;
|
||||||
|
|
||||||
DefaultTextStyle get defaultTextStyle => DefaultTextStyle.of(this);
|
DefaultTextStyle get defaultTextStyle => DefaultTextStyle.of(this);
|
||||||
|
|
||||||
|
// Media query data
|
||||||
MediaQueryData get mediaQuery => MediaQuery.of(this);
|
MediaQueryData get mediaQuery => MediaQuery.of(this);
|
||||||
|
|
||||||
|
// Widget-related properties
|
||||||
NavigatorState get navigator => Navigator.of(this);
|
NavigatorState get navigator => Navigator.of(this);
|
||||||
|
|
||||||
FocusScopeNode get focusScope => FocusScope.of(this);
|
FocusScopeNode get focusScope => FocusScope.of(this);
|
||||||
|
|
||||||
ScaffoldState get scaffold => Scaffold.of(this);
|
ScaffoldState get scaffold => Scaffold.of(this);
|
||||||
|
|
||||||
ScaffoldMessengerState get scaffoldMessenger => ScaffoldMessenger.of(this);
|
ScaffoldMessengerState get scaffoldMessenger => ScaffoldMessenger.of(this);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,30 +1,38 @@
|
||||||
extension OpenDatetimeExtensions on DateTime {
|
extension OpenDatetimeExtensions on DateTime {
|
||||||
static final DateTime _now = DateTime.now();
|
/// Returns the current UTC time as an ISO 8601 string.
|
||||||
|
String nowString() => DateTime.now().toUtc().toIso8601String();
|
||||||
|
|
||||||
String nowString() => _now.toUtc().toIso8601String();
|
/// Checks if the date is today.
|
||||||
|
bool get isToday => _isSameDay(this, DateTime.now());
|
||||||
|
|
||||||
bool isToday() => _isSameDay(this, _now);
|
/// Checks if the date is yesterday.
|
||||||
|
bool get isYesterday =>
|
||||||
|
_isSameDay(this, DateTime.now().subtract(const Duration(days: 1)));
|
||||||
|
|
||||||
bool isYesterday() =>
|
/// Checks if the date is tomorrow.
|
||||||
_isSameDay(this, _now.subtract(const Duration(days: 1)));
|
bool get isTomorrow =>
|
||||||
|
_isSameDay(this, DateTime.now().add(const Duration(days: 1)));
|
||||||
|
|
||||||
bool isTomorrow() => _isSameDay(this, _now.add(const Duration(days: 1)));
|
/// Time of day checks.
|
||||||
|
bool get isMorning => hour >= 4 && hour < 12;
|
||||||
bool isMorning() => hour >= 4 && hour < 12;
|
bool get isAfternoon => hour >= 12 && hour < 18;
|
||||||
bool isAfternoon() => hour >= 12 && hour < 18;
|
bool get isEvening => hour < 4 || hour >= 18;
|
||||||
bool isEvening() => hour < 4 || hour >= 18;
|
|
||||||
|
|
||||||
|
/// Returns the time of day as a string.
|
||||||
String get timeOfDay {
|
String get timeOfDay {
|
||||||
if (isMorning()) return 'morning';
|
if (isMorning) return 'morning';
|
||||||
if (isAfternoon()) return 'afternoon';
|
if (isAfternoon) return 'afternoon';
|
||||||
return 'evening';
|
return 'evening';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the first date of the current week.
|
||||||
DateTime get firstDateOfTheWeek => subtract(Duration(days: weekday - 1));
|
DateTime get firstDateOfTheWeek => subtract(Duration(days: weekday - 1));
|
||||||
|
|
||||||
|
/// Returns the last date of the current week.
|
||||||
DateTime get lastDateOfTheWeek =>
|
DateTime get lastDateOfTheWeek =>
|
||||||
add(Duration(days: DateTime.daysPerWeek - weekday));
|
add(Duration(days: DateTime.daysPerWeek - weekday));
|
||||||
|
|
||||||
|
/// Formats a duration (in seconds) into "HH:mm:ss".
|
||||||
String formatSeconds(int value) {
|
String formatSeconds(int value) {
|
||||||
final hours = (value ~/ 3600).toString().padLeft(2, '0');
|
final hours = (value ~/ 3600).toString().padLeft(2, '0');
|
||||||
final minutes = ((value % 3600) ~/ 60).toString().padLeft(2, '0');
|
final minutes = ((value % 3600) ~/ 60).toString().padLeft(2, '0');
|
||||||
|
@ -32,15 +40,19 @@ extension OpenDatetimeExtensions on DateTime {
|
||||||
return "$hours:$minutes:$seconds";
|
return "$hours:$minutes:$seconds";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Formats a duration (in minutes) into "HH:mm".
|
||||||
|
/// If `allowZero` is false, replaces "HH:00" with "HH:01".
|
||||||
String formatMinutes(int value, {bool allowZero = false}) {
|
String formatMinutes(int value, {bool allowZero = false}) {
|
||||||
final hours = (value ~/ 60).toString().padLeft(2, '0');
|
final hours = (value ~/ 60).toString().padLeft(2, '0');
|
||||||
final minutes = (value % 60).toString().padLeft(2, '0');
|
final minutes = (value % 60).toString().padLeft(2, '0');
|
||||||
return minutes == '00' && !allowZero ? "$hours:01" : "$hours:$minutes";
|
return minutes == '00' && !allowZero ? "$hours:01" : "$hours:$minutes";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the last day of the current month.
|
||||||
DateTime get lastDayOfMonth =>
|
DateTime get lastDayOfMonth =>
|
||||||
(month < 12) ? DateTime(year, month + 1, 0) : DateTime(year + 1, 1, 0);
|
(month < 12) ? DateTime(year, month + 1, 0) : DateTime(year + 1, 1, 0);
|
||||||
|
|
||||||
|
/// Private helper method to check if two dates fall on the same calendar day.
|
||||||
static bool _isSameDay(DateTime date1, DateTime date2) {
|
static bool _isSameDay(DateTime date1, DateTime date2) {
|
||||||
return date1.year == date2.year &&
|
return date1.year == date2.year &&
|
||||||
date1.month == date2.month &&
|
date1.month == date2.month &&
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
extension OpenDurationExtensions on Duration {
|
extension OpenDurationExtensions on Duration {
|
||||||
/// Converts the duration into a readable string in the format "HH:MM"
|
/// Converts the duration into a readable string in the format "HH:MM".
|
||||||
String toHoursMinutes() {
|
String toHoursMinutes() =>
|
||||||
return "${inHours.toString().padLeft(2, '0')}:${inMinutes.remainder(60).toString().padLeft(2, '0')}";
|
"${inHours.toString().padLeft(2, '0')}:${(inMinutes % 60).toString().padLeft(2, '0')}";
|
||||||
}
|
|
||||||
|
|
||||||
/// Converts the duration into a readable string in the format "HH:MM:SS"
|
/// Converts the duration into a readable string in the format "HH:MM:SS".
|
||||||
String toHoursMinutesSeconds() {
|
String toHoursMinutesSeconds() =>
|
||||||
return "${toHoursMinutes()}:${inSeconds.remainder(60).toString().padLeft(2, '0')}";
|
"${toHoursMinutes()}:${(inSeconds % 60).toString().padLeft(2, '0')}";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,36 +3,43 @@ import 'dart:math';
|
||||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||||
|
|
||||||
extension OpenGoogleMapsExtensions on GoogleMap {
|
extension OpenGoogleMapsExtensions on GoogleMap {
|
||||||
LatLngBounds getBoundsFromLatLngList(List<LatLng> list) {
|
/// Calculates the bounding box (LatLngBounds) from a list of LatLng points.
|
||||||
assert(list.isNotEmpty, 'The list cannot be empty');
|
LatLngBounds getBoundsFromLatLngList(List<LatLng> points) {
|
||||||
|
assert(points.isNotEmpty, 'The points list cannot be empty.');
|
||||||
|
|
||||||
// Initialize bounds to the first point
|
double minLat = points.first.latitude;
|
||||||
double x0 = list[0].latitude;
|
double maxLat = points.first.latitude;
|
||||||
double x1 = x0;
|
double minLng = points.first.longitude;
|
||||||
double y0 = list[0].longitude;
|
double maxLng = points.first.longitude;
|
||||||
double y1 = y0;
|
|
||||||
|
|
||||||
// Update bounds based on each point in the list
|
for (final point in points) {
|
||||||
for (var point in list.skip(1)) {
|
minLat = min(minLat, point.latitude);
|
||||||
x0 = min(x0, point.latitude);
|
maxLat = max(maxLat, point.latitude);
|
||||||
x1 = max(x1, point.latitude);
|
minLng = min(minLng, point.longitude);
|
||||||
y0 = min(y0, point.longitude);
|
maxLng = max(maxLng, point.longitude);
|
||||||
y1 = max(y1, point.longitude);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return LatLngBounds(northeast: LatLng(x1, y1), southwest: LatLng(x0, y0));
|
return LatLngBounds(
|
||||||
|
northeast: LatLng(maxLat, maxLng),
|
||||||
|
southwest: LatLng(minLat, minLng),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Calculates the geographical center of a list of LatLng points.
|
||||||
LatLng calculateCenter(List<LatLng> points) {
|
LatLng calculateCenter(List<LatLng> points) {
|
||||||
assert(points.isNotEmpty, 'The points list cannot be empty.');
|
assert(points.isNotEmpty, 'The points list cannot be empty.');
|
||||||
|
|
||||||
final total = points.fold(
|
final total = points.fold<LatLng>(
|
||||||
const LatLng(0.0, 0.0),
|
const LatLng(0.0, 0.0),
|
||||||
(LatLng acc, LatLng point) => LatLng(
|
(acc, point) => LatLng(
|
||||||
acc.latitude + point.latitude, acc.longitude + point.longitude),
|
acc.latitude + point.latitude,
|
||||||
|
acc.longitude + point.longitude,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
return LatLng(
|
return LatLng(
|
||||||
total.latitude / points.length, total.longitude / points.length);
|
total.latitude / points.length,
|
||||||
|
total.longitude / points.length,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,35 @@
|
||||||
import 'package:open_exts/open_exts.dart';
|
import 'package:open_exts/open_exts.dart';
|
||||||
|
|
||||||
extension OpenIntExtensions on int {
|
extension OpenIntExtensions on int {
|
||||||
|
Iterable<int> to(int other, [bool inclusive = true]) sync* {
|
||||||
|
if (this == other) {
|
||||||
|
if (inclusive) yield this;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final step = this < other ? 1 : -1;
|
||||||
|
for (int i = this;
|
||||||
|
inclusive ? (i != other + step) : (i != other);
|
||||||
|
i += step) {
|
||||||
|
yield i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts the integer to a binary string with optional padding, grouping, and separation.
|
||||||
|
/// - [length]: Total length of the binary string, padded with zeros if needed.
|
||||||
|
/// - [groupSize]: Number of binary digits per group for separation.
|
||||||
|
/// - [separator]: String used to separate binary groups.
|
||||||
String toBinary(
|
String toBinary(
|
||||||
int len, {
|
int length, {
|
||||||
int separateAtLength = 4,
|
int groupSize = 4,
|
||||||
String separator = ',',
|
String separator = ',',
|
||||||
}) =>
|
}) {
|
||||||
toRadixString(2)
|
assert(length > 0, 'Length must be greater than zero.');
|
||||||
.padLeft(len, '0')
|
assert(groupSize > 0, 'Group size must be greater than zero.');
|
||||||
.splitByLength(separateAtLength)
|
|
||||||
.join(separator);
|
return toRadixString(2)
|
||||||
|
.padLeft(length, '0')
|
||||||
|
.splitByLength(groupSize)
|
||||||
|
.join(separator);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,36 +1,49 @@
|
||||||
extension OpenStringExtension on String {
|
extension OpenStringExtension on String {
|
||||||
|
/// Removes all occurrences of [rhs] from the string.
|
||||||
String operator -(String rhs) => replaceAll(rhs, '');
|
String operator -(String rhs) => replaceAll(rhs, '');
|
||||||
|
|
||||||
String truncateTo(int maxLength) =>
|
/// Truncates the string to [maxLength] and appends '...' if truncated.
|
||||||
(length <= maxLength) ? this : '${substring(0, maxLength - 3)}...';
|
String truncateTo(int maxLength) {
|
||||||
|
if (maxLength <= 0) return '';
|
||||||
|
return length <= maxLength ? this : '${substring(0, maxLength - 3)}...';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Shortens the string to [maxLength] characters, preserving whole words.
|
||||||
String shortenByWords(int maxLength) =>
|
String shortenByWords(int maxLength) =>
|
||||||
shortenByDelimiterWithCount(maxLength);
|
shortenByDelimiterWithCount(maxLength);
|
||||||
|
|
||||||
|
/// Shortens the string to [maxLength] characters using [delimiter] as a word boundary.
|
||||||
String shortenByDelimiterWithCount(int maxLength, [String delimiter = ' ']) {
|
String shortenByDelimiterWithCount(int maxLength, [String delimiter = ' ']) {
|
||||||
|
if (maxLength <= 0) return '';
|
||||||
if (length <= maxLength) return this;
|
if (length <= maxLength) return this;
|
||||||
|
|
||||||
int endIndex = substring(0, maxLength).lastIndexOf(delimiter);
|
final cutIndex = substring(0, maxLength).lastIndexOf(delimiter);
|
||||||
if (endIndex == -1) return substring(0, maxLength);
|
if (cutIndex == -1) return substring(0, maxLength);
|
||||||
|
|
||||||
String shortened = substring(0, endIndex);
|
final shortened = substring(0, cutIndex).trim();
|
||||||
int remainingWordsCount =
|
final remainingWordsCount =
|
||||||
split(delimiter).length - shortened.split(delimiter).length;
|
split(delimiter).length - shortened.split(delimiter).length;
|
||||||
|
|
||||||
return remainingWordsCount > 0
|
return remainingWordsCount > 0
|
||||||
? '$shortened +$remainingWordsCount'
|
? '$shortened +$remainingWordsCount'
|
||||||
: shortened;
|
: shortened;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Splits the string into chunks of length [len], padding with [filler] if necessary.
|
||||||
Iterable<String> splitByLength(int len, {String filler = '0'}) sync* {
|
Iterable<String> splitByLength(int len, {String filler = '0'}) sync* {
|
||||||
String paddedString = padRight((length + len - 1) ~/ len * len, filler);
|
if (len <= 0)
|
||||||
|
throw ArgumentError.value(len, 'len', 'Must be greater than 0');
|
||||||
|
final paddedString = padRight((length + len - 1) ~/ len * len, filler);
|
||||||
for (var i = 0; i < paddedString.length; i += len) {
|
for (var i = 0; i < paddedString.length; i += len) {
|
||||||
yield paddedString.substring(i, i + len);
|
yield paddedString.substring(i, i + len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Capitalizes the first character of the string.
|
||||||
String capitalize() =>
|
String capitalize() =>
|
||||||
length > 0 ? substring(0, 1).toUpperCase() + substring(1) : this;
|
isNotEmpty ? '${this[0].toUpperCase()}${substring(1)}' : this;
|
||||||
|
|
||||||
|
/// Decapitalizes the first character of the string.
|
||||||
String decapitalize() =>
|
String decapitalize() =>
|
||||||
length > 0 ? substring(0, 1).toLowerCase() + substring(1) : this;
|
isNotEmpty ? '${this[0].toLowerCase()}${substring(1)}' : this;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
name: open_exts
|
name: open_exts
|
||||||
description: "Extensions. Its that simple..."
|
description: "Extensions. Its that simple..."
|
||||||
version: 0.0.3
|
version: 0.0.4
|
||||||
homepage: http://reinemuth.rocks:3000/jens/open_exts
|
homepage: http://reinemuth.rocks:3000/jens/open_exts
|
||||||
publish_to:
|
publish_to:
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue