diff --git a/app/lib/pass_backside/pass_backside_page.dart b/app/lib/pass_backside/pass_backside_page.dart index 5eae98e..fd7055b 100644 --- a/app/lib/pass_backside/pass_backside_page.dart +++ b/app/lib/pass_backside/pass_backside_page.dart @@ -133,7 +133,7 @@ class _PassBacksidePageState extends State { ListTile( title: Text(entry.label ?? ''), subtitle: Linkify( - text: entry.value.toString(), + text: entry.formatted() ?? '', onOpen: (link) => launchUrl(Uri.parse(link.url)), ), ), diff --git a/passkit/lib/src/passkit/field_dict.dart b/passkit/lib/src/passkit/field_dict.dart index 986dce4..c90cc8c 100644 --- a/passkit/lib/src/passkit/field_dict.dart +++ b/passkit/lib/src/passkit/field_dict.dart @@ -1,3 +1,4 @@ +import 'package:intl/intl.dart'; import 'package:json_annotation/json_annotation.dart'; import 'package:passkit/src/passkit/semantics.dart'; @@ -11,7 +12,7 @@ class FieldDict { this.dataDetectorTypes, required this.key, this.label, - this.textAlignment, + this.textAlignment = PkTextAlignment.natural, required this.value, this.currencyCode, this.dateStyle, @@ -81,7 +82,7 @@ class FieldDict { /// appropriately based on its script direction. /// /// This key is not allowed for primary fields or back fields. - final PkTextAlignment? textAlignment; + final PkTextAlignment textAlignment; /// Required. Value of the field, for example, 42. /// This can contain a localizable string, ISO 8601 date as a string, @@ -132,6 +133,56 @@ class FieldDict { /// Possible Values: 0, 1 /// This field is only valid for event pass types. final int? row; + + String? formatted({String? locale}) { + if (value == null) { + return null; + } + if (value is num) { + if (numberStyle != null) { + return numberStyle!.asFormat(currencyCode, locale).format(value as num); + } + if (currencyCode != null) { + return NumberFormat.simpleCurrency(locale: locale, name: currencyCode) + .format(value as num); + } + return value.toString(); + } + + var dateTime = DateTime.tryParse(value as String); + if (dateTime != null) { + DateFormat format = DateFormat(null, locale); + + if (dateStyle != null) { + format = switch (dateStyle!) { + DateStyle.none => DateFormat(null, locale), + DateStyle.full => DateFormat.yMMMMEEEEd(locale), + DateStyle.long => DateFormat.yMMMMd(locale), + // We can't easily do spellOut, so fall back to decimal + DateStyle.medium => DateFormat.yMMMd(locale), + DateStyle.short => DateFormat.yMd(locale), + }; + } + if (timeStyle != null) { + switch (timeStyle!) { + case DateStyle.none: + break; + case DateStyle.short: + format.add_jm(); + case DateStyle.medium: + case DateStyle.long: + case DateStyle.full: + format.add_jms(); + } + } + if (!(ignoresTimeZone ?? false)) { + dateTime = dateTime.toLocal(); + } + return format.format(dateTime); + } + // TODO(any): Could be localizable + return value?.toString(); + } } enum PkTextAlignment { @@ -202,3 +253,20 @@ enum NumberStyle { @JsonValue('PKNumberStyleSpellOut') spellOut, } + +extension on NumberStyle { + NumberFormat asFormat(String? currency, String? locale) { + return switch (this) { + NumberStyle.decimal => () { + if (currency != null) { + return NumberFormat.simpleCurrency(locale: locale, name: currency); + } + return NumberFormat.decimalPattern(locale); + }(), + NumberStyle.percent => NumberFormat.percentPattern(locale), + NumberStyle.scientific => NumberFormat.scientificPattern(locale), + // We can't easily do spellOut, so fall back to decimal + NumberStyle.spellOut => NumberFormat.decimalPattern(locale), + }; + } +} diff --git a/passkit/lib/src/passkit/field_dict.g.dart b/passkit/lib/src/passkit/field_dict.g.dart index 7522636..bdd61be 100644 --- a/passkit/lib/src/passkit/field_dict.g.dart +++ b/passkit/lib/src/passkit/field_dict.g.dart @@ -14,8 +14,9 @@ FieldDict _$FieldDictFromJson(Map json) => FieldDict( .toList(), key: json['key'] as String, label: json['label'] as String?, - textAlignment: - $enumDecodeNullable(_$PkTextAlignmentEnumMap, json['textAlignment']), + textAlignment: $enumDecodeNullable( + _$PkTextAlignmentEnumMap, json['textAlignment']) ?? + PkTextAlignment.natural, value: json['value'], currencyCode: json['currencyCode'] as String?, dateStyle: $enumDecodeNullable(_$DateStyleEnumMap, json['dateStyle']), @@ -38,7 +39,7 @@ Map _$FieldDictToJson(FieldDict instance) => { .toList(), 'key': instance.key, 'label': instance.label, - 'textAlignment': _$PkTextAlignmentEnumMap[instance.textAlignment], + 'textAlignment': _$PkTextAlignmentEnumMap[instance.textAlignment]!, 'value': instance.value, 'currencyCode': instance.currencyCode, 'dateStyle': _$DateStyleEnumMap[instance.dateStyle], diff --git a/passkit/pubspec.yaml b/passkit/pubspec.yaml index 66f81b1..e637263 100644 --- a/passkit/pubspec.yaml +++ b/passkit/pubspec.yaml @@ -20,6 +20,7 @@ dependencies: csslib: ^1.0.0 http: ^1.2.0 http_parser: ^4.0.0 + intl: ^0.19.0 json_annotation: ^4.9.0 dev_dependencies: