blob: 78f03574e0278441464e2ba150029803c998c0d9 [file] [log] [blame]
// Copyright 2019 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:convert' hide json;
import 'dart:convert' as convert show json;
import 'package:json_annotation/json_annotation.dart';
/// A converter for tags.
///
/// The JSON format is:
///
/// ```json
/// [
/// {
/// "key": "tag_key",
/// "value": "tag_value"
/// }
/// ]
/// ```
///
/// Which is flattened out as a `Map<String, List<String>>`.
class TagsConverter implements JsonConverter<Map<String?, List<String?>>?, List<dynamic>?> {
const TagsConverter();
@override
Map<String?, List<String?>>? fromJson(List<dynamic>? json) {
if (json == null) {
return null;
}
final Map<String?, List<String?>> result = <String?, List<String?>>{};
for (Map<String, dynamic> tag in json.cast<Map<String, dynamic>>()) {
final String? key = tag['key'] as String?;
result[key] ??= <String?>[];
result[key]!.add(tag['value'] as String?);
}
return result;
}
@override
List<Map<String, dynamic>>? toJson(Map<String?, List<String?>>? object) {
if (object == null) {
return null;
}
if (object.isEmpty) {
return const <Map<String, List<String>>>[];
}
final List<Map<String, String>> result = <Map<String, String>>[];
for (String? key in object.keys) {
if (key == null) {
continue;
}
final List<String?>? values = object[key];
if (values == null) {
continue;
}
for (String? value in values) {
if (value == null) {
continue;
}
result.add(<String, String>{
'key': key,
'value': value,
});
}
}
return result;
}
}
/// A converter for a "binary" JSON field.
///
/// Encodes and decodes a String to and from base64.
class Base64Converter implements JsonConverter<String, String> {
const Base64Converter();
@override
String fromJson(String json) {
return utf8.decode(base64.decode(json));
}
@override
String toJson(String object) {
return base64.encode(utf8.encode(object));
}
}
/// A converter for "timestamp" fields encoded as microseconds since epoch.
class MicrosecondsSinceEpochConverter implements JsonConverter<DateTime?, String?> {
const MicrosecondsSinceEpochConverter();
@override
DateTime? fromJson(String? json) {
if (json == null) {
return null;
}
return DateTime.fromMicrosecondsSinceEpoch(int.parse(json));
}
@override
String? toJson(DateTime? object) {
if (object == null) {
return null;
}
return object.microsecondsSinceEpoch.toString();
}
}
/// A converter for "timestamp" fields encoded as milliseconds since epoch.
class MillisecondsSinceEpochConverter implements JsonConverter<DateTime?, String?> {
const MillisecondsSinceEpochConverter();
@override
DateTime? fromJson(String? json) {
if (json == null) {
return null;
}
return DateTime.fromMillisecondsSinceEpoch(int.parse(json));
}
@override
String? toJson(DateTime? object) {
if (object == null) {
return null;
}
return object.millisecondsSinceEpoch.toString();
}
}
/// A converter for "timestamp" fields encoded as seconds since epoch.
class SecondsSinceEpochConverter implements JsonConverter<DateTime?, String?> {
const SecondsSinceEpochConverter();
@override
DateTime? fromJson(String? json) {
if (json == null) {
return null;
}
return DateTime.fromMillisecondsSinceEpoch(int.parse(json) * 1000);
}
@override
String? toJson(DateTime? dateTime) {
if (dateTime == null) {
return null;
}
final int secondsSinceEpoch = dateTime.millisecondsSinceEpoch ~/ 1000;
return secondsSinceEpoch.toString();
}
}
/// A converter for boolean fields encoded as strings.
class BoolConverter implements JsonConverter<bool?, String?> {
const BoolConverter();
@override
bool? fromJson(String? json) {
if (json == null) {
return null;
}
return json.toLowerCase() == 'true';
}
@override
String? toJson(bool? value) {
if (value == null) {
return null;
}
return '$value';
}
}
/// A converter for fields with nested JSON objects in String format.
class NestedJsonConverter implements JsonConverter<Map<String, dynamic>?, String?> {
const NestedJsonConverter();
@override
Map<String, dynamic>? fromJson(String? json) {
if (json == null) {
return null;
}
return convert.json.decode(json) as Map<String, dynamic>?;
}
@override
String? toJson(Map<String, dynamic>? object) {
if (object == null) {
return null;
}
return convert.json.encode(object);
}
}