main
1
2import 'package:flutter/material.dart';
3import 'package:health_data_store/health_data_store.dart';
4
5/// Utility class for converting dynamic values to concrete data types.
6///
7/// The functions this class provides interprets dynamic values as values of the data type. This makes them useful for
8/// contexts in which user generated data needs to be parsed.
9///
10/// An example for this are boolean fields in json data. Users could write `true` which will be converted to a boolean
11/// automatically and can be just checked with the `is boolean` condition, but the user may also write `"true"` or 1
12/// which are equally valid but would not get converted automatically.
13class ConvertUtil {
14 static bool? parseBool(value) {
15 if (value is bool) return value;
16 if (parseString(value)?.toLowerCase() == 'true' || parseInt(value) == 1) return true;
17 if (parseString(value)?.toLowerCase() == 'false' || parseInt(value) == 0) return false;
18 return null;
19 }
20
21 static int? parseInt(value) {
22 if (value is int) return value;
23 if (value is double) return _isInt(value);
24 if (value is String) return int.tryParse(value) ?? _isInt(double.tryParse(value));
25 return null;
26 }
27
28 static int? _isInt(double? value) {
29 if (value?.toInt() == value) return value?.toInt();
30 return null;
31 }
32
33 static double? parseDouble(value) {
34 if (value is double) return value;
35 if (value is int) return value.toDouble();
36 if (value is String) return double.tryParse(value);
37 return null;
38 }
39
40 static String? parseString(value) {
41 if (value is String) return value;
42 if (value is int || value is double || value is bool) return value.toString();
43 // No check for Object. While this would be convertible to string,
44 return null;
45 }
46
47 static String serializeLocale(Locale? value) {
48 if (value == null) return 'NULL';
49 return value.languageCode;
50 }
51
52 static Locale? parseLocale(value) {
53 if (value is Locale) return value;
54 // Should not use parseString, as values that get caught by it can not be locales.
55 if (value is String && value.toLowerCase() == 'null') return null;
56 if (value is String) return Locale(value);
57 return null;
58 }
59
60 static Color? parseColor(value) {
61 if (value is MaterialColor || value is Color) return value;
62 if (value == null) return null;
63
64 if (parseInt(value) != null) {
65 return Color(parseInt(value)!);
66 }
67 return null;
68 }
69
70 static DateRange? parseRange(start, end) {
71 final startTimestamp = parseInt(start);
72 final endTimestamp = parseInt(end);
73 if (startTimestamp == null || endTimestamp == null) return null;
74 return DateRange(
75 start: DateTime.fromMillisecondsSinceEpoch(startTimestamp),
76 end: DateTime.fromMillisecondsSinceEpoch(endTimestamp),
77 );
78 }
79
80 /// Example usage: `ConvertUtil.parseList<String>(json['columns'])`
81 static List<T>? parseList<T>(value) {
82 if (value is List<T>) return value;
83 if (value is List<dynamic>) {
84 final List<T> validValues = [];
85 for (final v in value) {
86 if (v is T) validValues.add(v);
87 }
88 if (value.length == validValues.length) return validValues;
89 }
90 if (value is List && value.isEmpty) return [];
91 return null;
92 }
93
94 /// Try to recreate the theme mode stored as a integer.
95 static ThemeMode? parseThemeMode(value) => switch(ConvertUtil.parseInt(value)) {
96 0 => ThemeMode.system,
97 1 => ThemeMode.dark,
98 2 => ThemeMode.light,
99 _ => null,
100 };
101
102 /// Does its best attempt at parsing a time in arbitrary format.
103 static DateTime? parseTime(dynamic time) {
104 final intTime = parseInt(time);
105 if (intTime != null) {
106 if (intTime.toString().length == 10) { // seconds
107 return DateTime.fromMillisecondsSinceEpoch(intTime * 1000);
108 } else if (intTime.toString().length == 13) { // milliseconds
109 return DateTime.fromMillisecondsSinceEpoch(intTime);
110 } else if (intTime.toString().length > 13) { // nanoseconds
111 return DateTime.fromMicrosecondsSinceEpoch(intTime ~/ 1000);
112 }
113 }
114
115 final timeStr = parseString(time);
116 return DateTime.tryParse(timeStr ?? '');
117 }
118}