mobile bluesky app made with flutter
lazurite.stormlightlabs.org/
mobile
bluesky
flutter
1import 'package:bluesky/app_bsky_feed_defs.dart';
2import 'package:intl/intl.dart';
3
4/// Returns up to two initials from a display value.
5String formatInitials(String value) {
6 final parts = value.trim().split(RegExp(r'\s+')).where((part) => part.isNotEmpty).toList();
7 if (parts.isEmpty) {
8 return '?';
9 }
10 if (parts.length == 1) {
11 return parts.first.substring(0, 1).toUpperCase();
12 }
13 return '${parts.first.substring(0, 1)}${parts.last.substring(0, 1)}'.toUpperCase();
14}
15
16/// Formats counts using compact K/M suffixes.
17String formatCount(int count, {String? locale}) {
18 final numberFormat = NumberFormat.decimalPattern(locale ?? Intl.getCurrentLocale());
19 final absoluteCount = count.abs();
20 final sign = count < 0 ? '-' : '';
21 if (absoluteCount >= 1000000) {
22 return '$sign${(absoluteCount / 1000000).toStringAsFixed(1)}M';
23 }
24 if (absoluteCount >= 1000) {
25 return '$sign${(absoluteCount / 1000).toStringAsFixed(1)}K';
26 }
27 return numberFormat.format(count);
28}
29
30/// Formats a relative timestamp using short units with optional suffix/casing.
31String formatRelativeTime(
32 DateTime time, {
33 DateTime? now,
34 String nowLabel = 'now',
35 bool includeAgo = false,
36 bool uppercase = false,
37 String? locale,
38}) {
39 final current = now ?? DateTime.now();
40 var difference = current.difference(time);
41 if (difference.isNegative) {
42 difference = Duration.zero;
43 }
44
45 final agoSuffix = includeAgo ? ' ago' : '';
46 final formatted = switch (difference) {
47 final d when d.inMinutes < 1 => nowLabel,
48 final d when d.inHours < 1 => '${d.inMinutes}m$agoSuffix',
49 final d when d.inDays < 1 => '${d.inHours}h$agoSuffix',
50 final d when d.inDays < 7 => '${d.inDays}d$agoSuffix',
51 _ => DateFormat('MMM d', locale ?? Intl.getCurrentLocale()).format(time),
52 };
53
54 return uppercase ? formatted.toUpperCase() : formatted;
55}
56
57String formatTimestamp(DateTime time, {String? locale}) {
58 final month = time.month.toString().padLeft(2, '0');
59 final day = time.day.toString().padLeft(2, '0');
60 final hour = time.hour.toString().padLeft(2, '0');
61 final minute = time.minute.toString().padLeft(2, '0');
62 return '${time.year}-$month-$day $hour:$minute';
63}
64
65String feedDisplayName(GeneratorView value) {
66 final displayName = value.displayName.trim();
67 if (displayName.isNotEmpty) {
68 return displayName;
69 }
70 return value.uri.rkey;
71}
72
73String formatBytes(int bytes) {
74 if (bytes >= 1024 * 1024 * 1024) {
75 final gb = bytes / (1024 * 1024 * 1024);
76 return '${gb.toStringAsFixed(2)} GB';
77 }
78 final mb = bytes / (1024 * 1024);
79 return '${mb.toStringAsFixed(2)} MB';
80}