/// Tolerant JSON coercion helpers. /// /// The API is generated from C# records, so numbers may arrive as `int` or /// `double` and nullable strings as `null`; parsing must not crash the UI. library; int asInt(Object? value, {int fallback = 0}) { if (value is int) return value; if (value is num) return value.toInt(); if (value is String) return int.tryParse(value) ?? fallback; return fallback; } double asDouble(Object? value, {double fallback = 0}) { if (value is double) return value; if (value is num) return value.toDouble(); if (value is String) return double.tryParse(value.replaceAll(',', '.')) ?? fallback; return fallback; } bool asBool(Object? value, {bool fallback = false}) { if (value is bool) return value; if (value is String) return value.toLowerCase() == 'true'; return fallback; } String asString(Object? value, {String fallback = ''}) { if (value is String) return value; if (value == null) return fallback; return value.toString(); } String? asStringOrNull(Object? value) { if (value is String && value.isNotEmpty) return value; return null; } /// Parses `YYYY-MM-DD` (and full ISO timestamps) as a local calendar day. DateTime asDate(Object? value) { final raw = asString(value); if (raw.isEmpty) return DateTime.now(); final parsed = DateTime.tryParse(raw); if (parsed == null) return DateTime.now(); return DateTime(parsed.year, parsed.month, parsed.day); } Map asMap(Object? value) { if (value is Map) return value; if (value is Map) return value.cast(); return const {}; } List> asList(Object? value) { if (value is! List) return const []; return value.map(asMap).toList(); } /// `YYYY-MM-DD` — the format every date-typed endpoint expects. String formatIsoDate(DateTime date) { final month = date.month.toString().padLeft(2, '0'); final day = date.day.toString().padLeft(2, '0'); return '${date.year}-$month-$day'; }