Flutter Firestore Server side Timestamp - dart

I need to add a server side timestamp on new documents added to Firestore using a Flutter app. I see I am supposed to use FieldValue.serverTimestamp but I am not sure where to find this.

As of September 5th, the updated cloud_firestore v0.8.0 library now has FieldValue.serverTimestamp(). All is now well in the universe

'timestamp' : Timestamp.now()
Timestamp.now() is part of cloud_firestore;
Example
Screenshot showing that the library is imported from cloud_firestore, and creates a server-generated timestamp in the written data. Docs

Expanding on #spongyboss' answer (which works as of April 2020) by adding sample usage:
_firestore.collection('messages').add({
'text': messageText,
'sender': loggedInUser.email,
'created': FieldValue.serverTimestamp()
});
'created' will be stored as a timestamp
Sample sorting:
_firestore.collection('messages')
.orderBy('created', descending: false)
.snapshots()

If you are using a model class to set the data, then you should create a dynamic variable with some name. For mine it was 'createdDate'.
class Products {
Products({
this.data,
this.createdDate,
});
List<ProductItems>? data;
dynamic createdDate;
factory Products.fromJson(Map<String, dynamic> json) => Products(
data: List<ProductItems>.from(json["data"].map((x) => ProductItems.fromJson(x))),
createdDate: json["createdDate"],
);
Map<String, dynamic> toJson() => {
"data": List<dynamic>.from(data!.map((x) => x.toJson())),
"createdDate": createdDate
};
}
class ProductItems {
String? id;
String? name;
int? price;
int? quantity;
ProductItems({
this.price,
this.quantity,
this.name,
this.id,
});
ProductItems.fromJson(Map<String, dynamic> json) {
price = json['price'];
quantity = json['quantity'];
name = json['name'];
id = json['id'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['price'] = price;
data['quantity'] = quantity;
data['name'] = name;
data['id'] = id;
return data;
}
}
And during setting the data to firestore,
final CollectionReference _cart = _firestore.collection('cart');
final _cartReference = _cart.withConverter<Products>(
fromFirestore: (snapshot, _) => Products.fromJson(snapshot.data()!),
toFirestore: (userModel, _) => userModel.toJson(),
);
await _cartReference.doc(auth?.uid).set(Products(
data: productList.data,
createdDate: FieldValue.serverTimestamp(),
));

Related

Using JSON Files for localization in GetX

I am trying to read translation files eg. en.json to use with GetX localization. I tried the following code but no success. Is there any better way of doing it? Somebody suggested using auto_localize with GetX, but I'll really appreciate if I can proceed without an extra package
Map<String, Map<String, String>> get keys => {
"ar": readJson("ar"),
"en": readJson("en"),
}
I tried loading the localization information using the following function
// Fetch content from the json file
Map<String, String> readJson(String languageCode) {
Map data = {};
rootBundle
.loadString('assets/translations/$languageCode.json')
.then((response) {
data = json.decode(response);
});
return data.map((key, value) {
return MapEntry(key, value.toString());
});
}
DebugPrint() gets shows that the files were successfully loaded. However, trying to display the loaded Maps doesn't work
The readJson should be Future and because of that the empty Map returned at the end.
The way i did
create languages.json file and put all texts to it.
[
{
"name": "English",
"code": "en_US",
"texts": {
"hello": "Hello World"
}
},
{
"name": "Arabic",
"code": "ar_AE",
"texts": {
"hello": "مرحبا بالعالم"
}
}
]
implement localization class like this
class LocalizationService extends Translations {
#override
Map<String, Map<String, String>> get keys => {};
static Future<void> initLanguages() async {
final _keys = await readJson();
Get.clearTranslations();
Get.addTranslations(_keys);
}
static Future<Map<String, Map<String, String>>> readJson() async {
final res = await rootBundle.loadString('assets/languages.json');
List<dynamic> data = jsonDecode(res);
final listData = data.map((j) => I18nModel.fromJson(j)).toList();
final keys = Map<String, Map<String, String>>();
listData.forEach((value) {
final String translationKey = value.code!;
keys.addAll({translationKey: value.texts!});
});
return keys;
}
}
As you see after getting the Map data, i used Get.addTranslations(); to set language keys.
this is a GetX function to add languages on air!
create model class to parse json data
class I18nModel {
String? name;
String? code;
Map<String, String>? texts;
I18nModel(
{this.name, this.code, this.texts});
I18nModel.fromJson(Map<String, dynamic> json) {
name = json['name'];
code = json['code'];
if (json['texts'] != null) {
texts = Map<String, String>.from(json['texts']);
}
}
}
And finally call await LocalizationService.initLanguages(); before going to your first Route.

Creating a default .toString() method

I have a lot of JSON models in my dart project that I would like to have a string representation of. I know that I can override the .toString() method per class, but that feels like a lot of work to write basically the same thing a bunch of times. Is there a way that I can create a mixin or extention to override toString? Or is it better to use code generation? (I found this package, but it seems like it isn't maintained any more)
The string representation I am looking for is just a list of all parameters, for example:
#JsonSerializable()
class User {
UserOver(
this.userId,
this.name,
);
int userId;
/// The full name of the user.
String name;
factory UserOverview.fromJson(Map<String, dynamic> json) => _$UserOverviewFromJson(json);
Map<String, dynamic> toJson() => _$UserOverviewToJson(this);
}
should have the following string representation:
User(userId: 1, name: "Name")
You answered your own question there buddy. Just create a base class and outsource it. It simple.
For example:
#JsonSerializable()
class User extends BaseModel {
User({
required this.userId,
required this.name,
});
int userId;
/// The full name of the user.
String name;
factory User.fromJson(Map<String, dynamic> json) =>
_$UserOverviewFromJson(json);
#override
Map<String, dynamic> toJson() => _$UserOverviewToJson(this);
}
Create a base model class
abstract class BaseModel {
Map<String, dynamic> toJson();
#override
String toString() {
return toJson().toString();
}
}
Don't forget these
User _$UserOverviewFromJson(Map<String, dynamic> json) => User(name: json['name'] as String, userId: json['userId'] as int);
Map<String, dynamic> _$UserOverviewToJson(User instance) => <String, dynamic>{
'name': instance.name,
'userId': instance.userId,
};
Now to use:
final cool = User(userId: 1, name: "Name");
print(cool.toString()); //{name: Name, userId: 1}

type 'JSArray<dynamic>' is not a subtype of type 'List<Ad>'

I tried two method to parse the rawData into dart objects. One using a for loop ads and it works but why _ads is not working when I use map ?
void main() {
dynamic rawData = [
{"title": "a", "id": 1}
];
List<Ad> ads = [];
for (var raw in rawData) {
Ad ad = Ad.fromJson(raw);
ads.add(ad);
}
print(ads);
List<Ad> _ads = rawData.map((e) => Ad.fromJson(e)).toList();
print(_ads);
}
class Ad {
Ad({
this.id,
this.title,
});
int id;
String title;
factory Ad.fromJson(Map<String, dynamic> json) => _$AdFromJson(json);
Map<String, dynamic> toJson() => _$AdToJson(this);
}
Ad _$AdFromJson(Map json) {
return Ad(
id: json['id'] as int,
title: json['title'] as String,
);
}
Map<String, dynamic> _$AdToJson(Ad instance) {
final val = <String, dynamic>{};
void writeNotNull(String key, dynamic value) {
if (value != null) {
val[key] = value;
}
}
writeNotNull('id', instance.id);
writeNotNull('title', instance.title);
return val;
}
The result of calling nearly any method on a dynamic defined variable are going to be dynamic since the Dart compiler are going through a difficult time guessing the type you want. So when you want the result to be saved into a variable with a specific type like List<Ad> _ads you really need to tell the compiler at each step what generic type you want and expect.
With that said, you can get you code to work by changing:
List<Ad> _ads = rawData.map((e) => Ad.fromJson(e)).toList();
Into:
List<Ad> _ads = rawData.map<Ad>((e) => Ad.fromJson(e)).toList();
And if you also want to make the analyzer happy:
List<Ad> _ads = rawData.map<Ad>((Map<String, dynamic> e) => Ad.fromJson(e)).toList() as List<Ad>;

FireStore and Flutter

I am writing an android app with flutter and Firestore at the backend database.
I can add single data to Firestore, but when I add an object with the nested object it fails. can't find any example or solution on google.
please help.
below is my code,
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:json_annotation/json_annotation.dart';
part 'Inspection.g.dart';
//run code => flutter packages pub run build_runner build
#JsonSerializable()
class Inspection extends Object with _$InspectionSerializerMixin {
Inspection(
{this.inspectionDate,
this.staffName,
this.arrivedTime,
this.leaveTime,
this.foundLocation,
this.postName,
this.guestsProportion,
this.situationRemark,
this.userid,
this.id,
this.grooming});
String id;
#JsonSerializable(nullable: false)
DateTime inspectionDate;
#JsonSerializable(nullable: false)
String arrivedTime;
#JsonSerializable(nullable: false)
String leaveTime;
#JsonSerializable(nullable: false)
String staffName;
#JsonSerializable(nullable: false)
String postName;
#JsonSerializable(nullable: false)
String foundLocation;
#JsonSerializable(nullable: false)
String guestsProportion;
#JsonSerializable(nullable: false)
String situationRemark;
#JsonKey(nullable: false)
String userid;
#JsonKey(nullable: false)
Grooming grooming;
static Inspection fromDocument(DocumentSnapshot document) =>
new Inspection.fromJson(document.data);
factory Inspection.fromJson(Map<String, dynamic> json) =>
_$InspectionFromJson(json);
}
#JsonSerializable()
class Grooming extends Object {
int groomingScore;
int hairScore;
int uniformScore;
int decorationScore;
int maskWearScore;
int maskCleanScore;
Grooming();
factory Grooming.fromJson(Map<String, dynamic> json) =>
_$GroomingFromJson(json);
}
and this is generated by build_runner
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'Inspection.dart';
// **************************************************************************
// Generator: JsonSerializableGenerator
// **************************************************************************
Inspection _$InspectionFromJson(Map<String, dynamic> json) => new Inspection(
inspectionDate: json['inspectionDate'] == null
? null
: DateTime.parse(json['inspectionDate'] as String),
staffName: json['staffName'] as String,
arrivedTime: json['arrivedTime'] as String,
leaveTime: json['leaveTime'] as String,
foundLocation: json['foundLocation'] as String,
postName: json['postName'] as String,
guestsProportion: json['guestsProportion'] as String,
situationRemark: json['situationRemark'] as String,
userid: json['userid'] as String,
id: json['id'] as String,
grooming: new Grooming.fromJson(json['grooming'] as Map<String, dynamic>));
abstract class _$InspectionSerializerMixin {
String get id;
DateTime get inspectionDate;
String get arrivedTime;
String get leaveTime;
String get staffName;
String get postName;
String get foundLocation;
String get guestsProportion;
String get situationRemark;
String get userid;
Grooming get grooming;
Map<String, dynamic> toJson() => <String, dynamic>{
'id': id,
'inspectionDate': inspectionDate?.toIso8601String(),
'arrivedTime': arrivedTime,
'leaveTime': leaveTime,
'staffName': staffName,
'postName': postName,
'foundLocation': foundLocation,
'guestsProportion': guestsProportion,
'situationRemark': situationRemark,
'userid': userid,
'grooming': grooming
};
}
Grooming _$GroomingFromJson(Map<String, dynamic> json) => new Grooming()
..groomingScore = json['groomingScore'] as int
..hairScore = json['hairScore'] as int
..uniformScore = json['uniformScore'] as int
..decorationScore = json['decorationScore'] as int
..maskWearScore = json['maskWearScore'] as int
..maskCleanScore = json['maskCleanScore'] as int;
abstract class _$GroomingSerializerMixin {
int get groomingScore;
int get hairScore;
int get uniformScore;
int get decorationScore;
int get maskWearScore;
int get maskCleanScore;
Map<String, dynamic> toJson() => <String, dynamic>{
'groomingScore': groomingScore,
'hairScore': hairScore,
'uniformScore': uniformScore,
'decorationScore': decorationScore,
'maskWearScore': maskWearScore,
'maskCleanScore': maskCleanScore
};
}
code used to insert data
Future<bool> addInspection(Inspection item) async {
print('creating');
var newdoc = await inspectionCollection.document().get();
item.id = newdoc.documentID;
item.userid = user.uid;
inspectionCollection.add(item.toJson()).then((onValue) {
onValue.setData({'id': onValue.documentID});
}).catchError((error) {
print(error.toString());
});

Dart Convert List as Map Entry for JSON Encoding

I asked a question before about Dart encoding/decoding to JSON, however, the libraries that were suggested were not complete and I decided to manually handle that.
The objective is to convert these objects to a map.
class Parent extends Object {
int id;
String name;
List<Child> listChild = new List<Child>();
Map toMap() => {"id":id, "name":name, "listChild":listChild};
}
class Child extends Object {
int id;
String childName;
Map toMap() => {"id":id, "childName":childName};
}
When doing
print(JSON.encode(parent.toMap()));
I am seeing it go here, any suggestion how to make this work?
if (!stringifyJsonValue(object)) {
checkCycle(object);
try {
var customJson = _toEncodable(object);
if (!stringifyJsonValue(customJson)) {
throw new JsonUnsupportedObjectError(object);
}
_removeSeen(object);
} catch (e) {
throw new JsonUnsupportedObjectError(object, cause : e);
}
}
}
Map toMap() => {"id":id, "name":name: "listChild": listChild.map((c) => c.toJson().toList())};
is valid for JSON.
import 'dart:convert' show JSON;
...
String json = JSON.encode(toMap());
You can also use the toEncodeable callback - see How to convert DateTime object to json
If your class structure does not contain's any inner class then follow
class Data{
String name;
String type;
Map<String, dynamic> toJson() => {
'name': name,
'type': type
};
}
If your class uses inner class structure
class QuestionTag {
String name;
List<SubTags> listSubTags;
Map<String, dynamic> toJson() => {
'name': name,
'listSubTags': listSubTags.map((tag) => tag.toJson()).toList()
};
}
class SubTags {
String tagName;
String tagDesc;
SubTags(this.tagName, this.tagDesc);
Map<String, dynamic> toJson() => {
'tagName': tagName,
'tagDesc': tagDesc,
};
}
Just rename Map toMap() into Map toJson() and it will work fine. =)
void encode() {
Parent p = new Parent();
Child c1 = new Child();
c1 ..id = 1 ..childName = "Alex";
Child c2 = new Child();
c2 ..id = 2 ..childName = "John";
Child c3 = new Child();
c3 ..id = 3 ..childName = "Jane";
p ..id = 1 ..name = "Lisa" ..listChild = [c1,c2,c3];
String json = JSON.encode(p);
print(json);
}
class Parent extends Object {
int id;
String name;
List<Child> listChild = new List<Child>();
Map toJson() => {"id":id, "name":name, "listChild":listChild};
}
class Child extends Object {
int id;
String childName;
Map toJson() => {"id":id, "childName":childName};
}

Resources