Reputation: 400
I'm looking for some help for an app my team and I are working on. We are facing the following problem for weeks :
flutter type 'Timestamp' is not a subtype of type 'DateTime'
We want to get these user data from Cloud Firestore:
Only birth and license are stored as [Timestamp] in Cloud Firestore so we parse these data to [DateTime].
Here's our code to get user's data :
import 'package:cloud_firestore/cloud_firestore.dart';
class User{
final String _name;
final String _gender; // 'homme' or 'femme' or 'autre'
final DateTime _birth;
final DateTime _license;
final double _weight;
final int _size;
DocumentReference ref;
User(this._birth,this._gender,this._license,this._name,this._size,this._weight,this.ref);
User.fromMap(Map<String, dynamic> map, {this.ref})
: assert(map['name'] != null && map['gender'] != null && map['birth'] != null && map['weight'] != null && map['size'] != null),
_name = map['name'],
_gender = map['gender'],
_birth = map['birth'] as DateTime,
_license = map['license'] as DateTime,
_weight = double.parse(map['weight']),
_size = int.parse(map['size']);
User.fromSnapshot(DocumentSnapshot snapshot)
: this.fromMap(snapshot.data, ref: snapshot.reference);
String get name => _name;
String get gender => _gender;
DateTime get birth => _birth;
DateTime get license => _license;
double get weight => _weight;
int get size => _size;
}
And here's where we call these functions and where the issue seems to appear :
import 'package:bappsalcolit/pages/homepage.dart';
import 'package:flutter/material.dart';
import 'package:bappsalcolit/sign_in/auth.dart';
import 'package:bappsalcolit/sign_in/log_page.dart';
import 'package:bappsalcolit/ads_display.dart';
import 'package:bappsalcolit/dbase/model/global_info.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
User currentUser = User(null, null, null, null, null, null, null);
class RootPage extends StatefulWidget {
RootPage({this.auth});
final AuthImpl auth;
@override
State<StatefulWidget> createState() => new _RootPageState();
}
enum AuthStatus {
NOT_DETERMINED,
NOT_SIGNED_IN,
SIGNED_IN,
}
class _RootPageState extends State<RootPage> {
AuthStatus authStatus = AuthStatus.NOT_DETERMINED;
String _userID = "";
@override
void initState(){
super.initState();
Ads.hideBanner();
widget.auth.getCurrentUser().then((user) {
setState(() {
if(user != null) {
_userID = user?.uid;
}
authStatus =
user?.uid == null ? AuthStatus.NOT_SIGNED_IN : AuthStatus.SIGNED_IN;
});
});
}
void _signedIn() {
widget.auth.getCurrentUser().then((user){
setState(() {
_userID = user?.uid.toString();
});
});
setState(() {
authStatus = AuthStatus.SIGNED_IN;
});
}
void _signedOut() {
setState(() {
authStatus = AuthStatus.NOT_SIGNED_IN;
_userID = "";
});
}
Widget _buildWaitingScreen() {
return Scaffold(
body: Container(
height: 20.0,
width: 20.0,
alignment: Alignment.center,
child: CircularProgressIndicator(),
),
);
}
//========== Here's where the problem seems to appear ==========\\
gettingSnapshots(){
Firestore db = Firestore.instance;
DocumentSnapshot userDS;
db.collection('users').document(_userID).snapshots().listen((ds) async{
if (ds.exists) {
userDS = await db.collection('users').document(_userID).get();
try {
currentUser = User.fromSnapshot(userDS);
} catch (e) {
print('Error 1131: $e');
}
}
});
}
@override
Widget build(BuildContext context) {
switch (authStatus) {
case AuthStatus.NOT_SIGNED_IN:
return new SignIn(
auth: widget.auth,
onSignedIn: _signedIn,
);
break;
case AuthStatus.SIGNED_IN:
if(_userID.length > 0 && _userID != null) {
gettingSnapshots();
return new HomePage(
userID: _userID,
auth: widget.auth,
onSignedOut: _signedOut,
);
}
break;
case AuthStatus.NOT_DETERMINED:
return _buildWaitingScreen();
break;
}
return _buildWaitingScreen();
}
}
The issue only occurs on iOS. Everything is OK on Android.
The problem should not come from the link between Cloud Firestore and the app because we can get other stored information.
Upvotes: 2
Views: 6520
Reputation: 375
I'm new to flutter and somehow I had a mental block with the answers above.
However, this is what i found to work for me.
import 'package:cloud_firestore/cloud_firestore.dart';
class User{
final String _name;
final String _gender; // 'homme' or 'femme' or 'autre'
final DateTime _birth;
final DateTime _license;
final double _weight;
final int _size;
DocumentReference ref;
User(this._birth,this._gender,this._license,this._name,this._size,this._weight,this.ref);
User.fromMap(Map<String, dynamic> map, {this.ref})
: assert(map['name'] != null && map['gender'] != null && map['birth'] != null && map['weight'] != null && map['size'] != null),
_name = map['name'],
_gender = map['gender'],
_birth = (map['birth'] as Timestamp).toDate(),
_license =(map['license'] as Timestamp).toDate(),
_weight = double.parse(map['weight']),
_size = int.parse(map['size']);
User.fromSnapshot(DocumentSnapshot snapshot)
: this.fromMap(snapshot.data, ref: snapshot.reference);
String get name => _name;
String get gender => _gender;
DateTime get birth => _birth;
DateTime get license => _license;
double get weight => _weight;
int get size => _size;
}
Upvotes: 0
Reputation: 2244
On my projects I use
birth: parsedJson['birth'].toDate()
and works well, it's another option.
Upvotes: 7
Reputation: 400
We solved the problem.
Instead of acting on received value, we stored our [DateTime] values parsed to [String]. So we parse these parameters back to [DateTime] the same way as described above :
import 'package:cloud_firestore/cloud_firestore.dart';
class User{
final String _name;
final String _gender; // 'homme' or 'femme' or 'autre'
final DateTime _birth;
final DateTime _license;
final double _weight;
final int _size;
DocumentReference ref;
User(this._birth,this._gender,this._license,this._name,this._size,this._weight,this.ref);
User.fromMap(Map<String, dynamic> map, {this.ref})
: assert(map['name'] != null && map['gender'] != null && map['birth'] != null && map['weight'] != null && map['size'] != null),
_name = map['name'],
_gender = map['gender'],
_birth = map['birth'] as DateTime,
_license = map['license'] as DateTime,
_weight = double.parse(map['weight']),
_size = int.parse(map['size']);
User.fromSnapshot(DocumentSnapshot snapshot)
: this.fromMap(snapshot.data, ref: snapshot.reference);
String get name => _name;
String get gender => _gender;
DateTime get birth => _birth;
DateTime get license => _license;
double get weight => _weight;
int get size => _size;
}
So the problem is quite solved. It should be nice to know why the previous way to store was not OK.
Upvotes: 1