extension StringExtension on String { /// Capitalize first letter String capitalize() { if (isEmpty) return this; return '${this[0].toUpperCase()}${substring(1)}'; } /// Check if string is a valid number bool isNumeric() { return double.tryParse(this) != null; } /// Truncate string with ellipsis String truncate(int maxLength, {String suffix = '...'}) { if (length <= maxLength) return this; return '${substring(0, maxLength)}$suffix'; } } extension DateTimeExtension on DateTime { /// Check if date is today bool isToday() { final now = DateTime.now(); return year == now.year && month == now.month && day == now.day; } /// Check if date is yesterday bool isYesterday() { final yesterday = DateTime.now().subtract(const Duration(days: 1)); return year == yesterday.year && month == yesterday.month && day == yesterday.day; } /// Get relative time string (e.g., "2 hours ago") String getRelativeTime() { final now = DateTime.now(); final difference = now.difference(this); if (difference.inSeconds < 60) { return 'Just now'; } else if (difference.inMinutes < 60) { return '${difference.inMinutes}m ago'; } else if (difference.inHours < 24) { return '${difference.inHours}h ago'; } else if (difference.inDays < 7) { return '${difference.inDays}d ago'; } else { return '${(difference.inDays / 7).floor()}w ago'; } } } extension DoubleExtension on double { /// Round to specific decimal places double roundToDecimals(int decimals) { final mod = 10.0 * decimals; return (this * mod).round() / mod; } /// Format as currency String toCurrency({String symbol = '\$'}) { return '$symbol${toStringAsFixed(2)}'; } } extension ListExtension on List { /// Check if list is not null and not empty bool get isNotEmpty => this.isNotEmpty; /// Get first element or null T? get firstOrNull => isEmpty ? null : first; /// Get last element or null T? get lastOrNull => isEmpty ? null : last; }