Calling a private constructor - Constructor doesn't exist - flutter

I saw this answer and I am trying to replicate it in my code.
Below is the base class:
class ResponseObjectBase<T> {
bool success;
T responseObject;
ResponseObjectBase._fromJson(Map<String, dynamic> json){
success = true;
}
factory ResponseObjectBase.fromJson(Map<String, dynamic> json) {
if (T == OsGridRefModel) {
return OsGridRefModel.fromJson(json) as ResponseObjectBase<T>;
}
throw UnimplementedError();
}
}
And here is the derived class:
class OsGridRefModel extends ResponseObjectBase<OsGridRefModel>{
String descriptor;
double easting;
double northing;
OsGridRefModel.fromJson(Map<String, dynamic> json) : super._fromJson(json) {
this.descriptor = json['descriptor'] as String;
this.northing = json["northing"] as double;
this.easting = json["easting"] as double;
this.responseObject = this;
}
}
Inside of the derived class the super._fromJson(json) is throwing the following error:
The class 'ResponseObjectBase<OsGridRefModel>' doesn't have a constructor named '_fromJson'.
Try defining a constructor named '_fromJson' in 'ResponseObjectBase<OsGridRefModel>', or invoking a different constructor.
Thanks.

Related

How to add Singleton in dart?

i'm pretty new to flutter and i want to add singleton in my flutter app. I used shared preferences to save my private and public key, but also i want to take this info from it when i launch app
try {
userPubKey = getPublicKey() as String;
userPrivateKey = getPrivateKey() as String;
} catch (e) {
}
if (userPrivateKey == "null" || userPubKey == "null") {
var crypter = RsaCrypt();
var pubKey = crypter.randPubKey;
var privKey = crypter.randPrivKey;
String pubKeyString = crypter.encodeKeyToString(pubKey);
String privKeyString = crypter.encodeKeyToString(privKey);
setPublicKey(pubKeyString);
setPrivateKey(privKeyString);
userPubKey = pubKeyString;
userPrivateKey = privKeyString;
}
Here is my singleton screen. I need to add my pubKey, privateKey, UId and userName data in Singleton. I copied random singleton code with factory construct.
class Singleton {
Singleton.privateConstructor();
static final Singleton instance = Singleton.privateConstructor();
factory Singleton() {
return instance;
}
String pubKey;
String privateKey;
String userName;
String userID;
setPubKey(String key){
this.pubKey = key;
}
String getPubKey(){
return this.pubKey;
}
}
You don't need factory constructor as you can directly use instance variable being static. Here's how you do it.
class Singleton {
Singleton._();
static final Singleton instance = Singleton._();
String pubKey;
String privateKey;
String userName;
String userID;
void setPubKey(String key) => pubKey = key;
String getPubKey() => pubKey;
}
void main() {
var instance = Singleton.instance;
}

Dart: Which is a better practice? Using 'late' or constructor initializer list

I am modelling a Dart class with the new null safety types in mind. I believe there are two effective ways to initialize non-nullable properties, calculated from a parameter.
For this example, we will use the Favourite class.
This class uses the initializer list in the constructor.
class Favourite {
int favouriteId;
Favourite({required this.favouriteId});
Favourite.mapFromJson(dynamic json)
: this.favouriteId = json["favouriteId"];
}
This class uses the 'late' keyword.
class Favourite {
late int favouriteId;
Favourite({required this.favouriteId});
Favourite.mapFromJson(dynamic json) {
this.favouriteId = json["favouriteId"];
}
}
When would you use one over the other? Using 'late' feels risky. If I added another named constructor, the compiler would not complain about 'favouriteId' not being initialized.
Are there other options?
Thank you!
Neither.
Use a default constructor that initializes the fields themselves and a factory constructor that handles deserializing the json object:
class Favourite {
final int favouriteId;
Favourite({required this.favouriteId});
factory Favourite.fromMap(Map<String, dynamic> map) {
final favouriteId = json['favouriteId'];
assert(favouriteId != null && favouriteId is int);
return Favourite(
favouriteId: favouriteId,
);
}
}
The late keyword can be a source of headache if you don't handle it properly, so in general don't use it unless you have to.
If you're sure the json will always have a "favouriteId", you can write it like this:
class Favourite {
int favouriteId;
Favourite({required this.favouriteId});
Favourite.mapFromJson(Map<String, dynamic?> json):
assert(() {
final favouriteId = json["favouriteId"];
return favouriteId != null && favouriteId is int;
}()),
favouriteId = json["favouriteId"] as int;
}
void main() {
dynamic m = {"favouriteId":2};
final favourite = Favourite.mapFromJson(m);
print("favourite id: ${favourite.favouriteId}");
}

How do i invoke method on a generic type in dart

There are several models have a same structure, { type: xxx, settings: xxx}, so i would like to use a parent class "WidgetConfig" with a generic type "T" to implement this, but problem occurs when i add "fromJson" methods. How can i invoke method on a generic type or any other ways to implement this?
class BannerWidgetViewModel extends ChangeNotifier {
WidgetConfig<BannerWidgetConfig> config;
BannerWidgetViewModel(String configJson){
config = WidgetConfig.fromJson(configJson);
}
}
class BannerWidgetConfig {
String imgUrl;
String padImgUrl;
String lessonId;
BannerWidgetConfig.fromJson(json){
if (json != null) {
this.imgUrl = json['imgUrl'];
this.padImgUrl = json['padImgUrl'];
this.lessonId = json['lessonId'];
}
}
}
class WidgetConfig<T> {
WidgetType type;
WidgetConfig.fromJson(json){
if (json != null) {
this.type = json['type'];
// this.settings = T.fromJson(json['settings']); // T doesn't have fromJson method
}
}
}
then i use a abstract class but still not working.
abstract class BaseWidgetConfig {
BaseWidgetConfig.fromJson(dynamic json);
}
class WidgetConfig<T extends BaseWidgetConfig> {
WidgetType type;
T settings;
WidgetConfig.fromJson(json){
if (json != null) {
this.type = json['type'];
this.settings = T.fromJson();
}
}
}
code picture
Directly show the function as a reference.
send function as a reference here.
FireStoreHelper.getList<ModelLesson>('grade4', ModelLesson.fromJson);
get the method here.
static Future<List<T>> getList<T>(String path, Function fromJson)

How to compare the type variable in "is" operator in Dart

I couldn't find a way to store the Type value in Map so that I could use it in is operator to check the validity of type using this map later on. Also, can is operator accept Type as a variable?
For eg, Below is hypothetical code solving the problem but it's invalid.
Map<String, Type> map = {
"sku": String,
"price": double,
"quantity": int,
};
dynamic value = 10;
if(value is map["quantity"]){
print("value is of type int and int is expected for quantity value");
}
You can do something like this:
class TypeCheck<T> {
const TypeCheck();
bool typeCheck(dynamic value) => value is T;
}
void main() {
Map<String, TypeCheck> map = {
"sku": TypeCheck<String>(),
"price": TypeCheck<double>(),
"quantity": TypeCheck<int>(),
};
dynamic value = 10;
if (map["quantity"]!.typeCheck(value)) {
print("value is of type int and int is expected for quantity value");
}
}
Im not sure I fully understand I understand what you are trying to do but why don't you try something like.
bool _validate(Map productDetails){
if (productDetails.containsKey("sold_individually") && productDetails["sold_individually"] is bool) {
//return true or false
}
else if (productDetails.containsKey("stock_quantity") && productDetails["stock_quantity"] is int){
//return true or false
}
else if (productDetails.containsKey("tax_class") && productDetails["tax_class"] is String && productDetails["tax_class"].isNotEmpty) {
//return true or false
} else {
//return true or false
}
}
As for the other part of your question you wont get an error but you will always return false. In contrast if you check if a variable is dynamic it will always return true.
I don't really understand your end goal. But from what you have, I don't think you are taking advantage of the strongly-typed nature of dart.
Assuming you are getting your map from an API, you could enforce
typing manually in your code as follows;
Map<String, Type> map = {
"sku": json['key'] as String,
"price": json['key'] as double,
"quantity": json['key'] as int,
};
And avoid using dynamic when declaring variables.
OR
In the case you have a user-defined type you what to compare, you can use the equatable package on a class for instance as follows;
class CustomMap extends Equatable {
String sky;
double price;
int quantity;
// here you put the fields of a class you want for two instances of a class to be equal.
#overide
List<Object> get props => [sky, price, quantity];
}
Update from your comment
You should have a custom class for the API objects for instance;
class Item extends Equatable {
String sku;
double price;
int quantity;
Item({this.sky, this.price, this.quantity});
// factory constructor
factory Item.fromMap(Map<String, dynmic> json) {
final sku = json['sku'] as String,
final price = (json['price'] as num) as double,
final quantity = json['quantity'] as num,
return Item(sku: sku, price: price, quantity: quantity);
}
// define equatable objects
#override
List<Object> get props => [sku, price, quantity];
}
Now you can use it as follows;
Future<Item> objectsFromService(Map<String, dynamic> json ) async {
http.Response response = http.get(url);
if(response.status == 200) {
final decodedJson = json.decode(response.body);
return Item.fromJson(decodedJson);
}else{
print('Error fetch data');
return null;
}
}
Hope it helps

pass different class object to function

I have multiple class objects and i want to create a standalone function that will take any class object as parameter.
here is my income class
import 'package:finsec/model/dao.dart';
class Income {
int id, groupId, weekNumber, monthNumber, calendarYear;
String frequency, payoutDate, category, depositTo, description, status;
double expectedAmount, actualAmount;
Income(
this.id,
this.groupId,
this.expectedAmount,
this.actualAmount,
this.frequency,
this.payoutDate,
this.category,
this.depositTo,
this.status,
this.weekNumber,
this.monthNumber,
this.calendarYear,
[this.description]
);
}
here is my expense class object
import 'package:finsec/model/dao.dart';
class Expense{
int id, groupId
String frequency, paidDate, expCategory, description, status;
double expectedAmount, actualAmount;
Expense(
this.id,
this.groupId,
this.expectedAmount,
this.actualAmount,
this.frequency,
this.paidDate,
this.expCategory,
this.status,
[this.description]
);
}
// The base class for the different types of items the list can contain.
abstract class Dao<T> {
//queries
String get createTableQuery;
//abstract mapping methods
T fromMap(Map<String, dynamic> query);
List<T> fromList(List<Map<String,dynamic>> query);
Map<String, dynamic> toMap(T object);
}
import 'package:finsec/model/dao.dart';
import 'package:finsec/model/income/income.dart';
class IncomeDao implements Dao<Income> {
#override
Income fromMap(Map<String, dynamic> query) {
Income income = Income();
income.id = query["id"];
income.groupId = query["groupId"];
income.amount = query["amount"];
income.frequency = query["frequency"];
income.payoutDate = query["payoutDate"];
income.category = query["category"];
income.depositTo = query["depositTo"];
income.status = query["status"];
return income;
}
#override
Map<String, dynamic> toMap(Income object) {
return <String, dynamic>{
"id": object.id,
"groupId": object.groupId,
"amount": object.amount,
"frequency": object.frequency,
"payoutDate": object.payoutDate,
"category": object.category,
"depositTo": object.depositTo,
"status": object.status,
};
}
#override
List<Income> fromList(List<Map<String,dynamic>> query) {
List<Income> income = List<Income>();
for (Map map in query) {
income.add(fromMap(map));
}
return income;
}
}
i want to create function that takes any class object
Future<int> insertTransaction(T object) async {
var dao = new IncomeDao();
dao.toMap(object));
}
basically, i want to be able to call insertTransaction and pass any class object and then pass that object to the dao class. when i called dao.toMap(object)); in insertTransaction function. i get error message such as "The argument type 'T' can't be assigned to the parameter type 'Income'."
I guess flutter is not able to determine if object parameter is Income or expense etc. i tried using casting such as (Income)object but didnt work.
can someone help me on this? im trying to reuse my function (insertTransaction) instead of creating the same function for every object class such as income, expenses, events, etc...
just change T to dynamic
insertTransaction(dynamic object)