/// Shared formatting helpers. Anything a screen would otherwise write inline /// to render a value belongs here, so the same quantity reads the same way /// everywhere in the app. library; /// Human-friendly "time ago" formatting. String timeAgo(DateTime t) { final d = DateTime.now().difference(t); if (d.inSeconds < 45) return 'just now'; if (d.inMinutes < 60) return '${d.inMinutes}m ago'; if (d.inHours < 24) return '${d.inHours}h ago'; if (d.inDays < 7) return '${d.inDays}d ago'; String two(int n) => n.toString().padLeft(2, '0'); return '${t.year}-${two(t.month)}-${two(t.day)}'; } /// Byte count as B / KB / MB / GB. String formatBytes(int bytes) { if (bytes < 1024) return '$bytes B'; if (bytes < 1024 * 1024) return '${(bytes / 1024).toStringAsFixed(1)} KB'; if (bytes < 1024 * 1024 * 1024) { return '${(bytes / (1024 * 1024)).toStringAsFixed(1)} MB'; } return '${(bytes / (1024 * 1024 * 1024)).toStringAsFixed(2)} GB'; } /// An integer with thousands separators — offsets and message counts are /// unreadable without them. String formatCount(int value) { final digits = value.abs().toString(); final out = StringBuffer(value < 0 ? '-' : ''); for (var i = 0; i < digits.length; i++) { if (i > 0 && (digits.length - i) % 3 == 0) out.write(','); out.write(digits[i]); } return out.toString(); } /// `HH:MM` for a timestamp. String formatClock(DateTime t) { String two(int n) => n.toString().padLeft(2, '0'); return '${two(t.hour)}:${two(t.minute)}'; } /// The last segment of a path, accepting either separator and ignoring a /// trailing slash. String baseName(String path) { final normalised = path.replaceAll('\\', '/').replaceAll(RegExp(r'/+$'), ''); final i = normalised.lastIndexOf('/'); return i >= 0 ? normalised.substring(i + 1) : normalised; } /// Joins a POSIX directory and a child name without doubling the separator. String joinRemote(String base, String name) { final trimmed = base.endsWith('/') ? base.substring(0, base.length - 1) : base; return '$trimmed/$name'; } /// The parent of a POSIX path, bottoming out at `/`. String parentRemote(String path) { final trimmed = path.endsWith('/') && path.length > 1 ? path.substring(0, path.length - 1) : path; final i = trimmed.lastIndexOf('/'); if (i <= 0) return '/'; return trimmed.substring(0, i); }