I have been working with my Store App, but this null safety is getting me pissed now. I have created a class but it gives me this error with later doesn't allow my app to work correctly
this is the the product.dart file:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:loja_virtual_nnananene/models/item_size.dart';
class Product extends ChangeNotifier {
Product.fromDocument(DocumentSnapshot document) {
id = document.documentID;
name = document['name'];
description = document['description'];
images = List<String>.from(document.data['images'] as List<dynamic>);
// ingore_for_file: Warning: Operand of null-aware operation
sizes = (document.data['sizes'] as List<dynamic> ?? [])
.map((s) => ItemSize.fromMap(s as Map<String, dynamic>))
.toList();
}
String id = "";
String name = "";
String description = "";
List<String> images = [];
List<ItemSize> sizes = [];
ItemSize _selectedSize;
ItemSize get selectedSize => _selectedSize;
set selectedSize(ItemSize value) {
_selectedSize = value;
notifyListeners();
}
}
I'm receiving an error at the Product.from...
This is the error:
Non-nullable instance field '_selectedSize' must be initialized.
Try adding an initializer expression, or add a field initializer in this constructor, or mark it 'late'.
This is my ItemSize class:
class ItemSize {
ItemSize.fromMap(Map<String, dynamic> map) {
name = map['name'] as String;
price = map['price'] as num;
stock = map['stock'] as int;
}
String name = "";
num price = 0;
int stock = 0;
bool get hasStock => stock > 0;
#override
String toString() {
return 'ItemSize{name: $name, price: $price, stock: $stock}';
}
}
Calling in main widget:
class SizeWidget extends StatelessWidget {
const SizeWidget(this.size);
final ItemSize size;
#override
Widget build(BuildContext context) {
final product = context.watch<Product>();
final selected = size == product.selectedSize;
Color color;
if (!size.hasStock)
color = Colors.red.withAlpha(50);
else if (selected)
color = ColorSelect.cprice;
the code tries to get the selected item the first time, and of course it will be null. The alternative I found was...
in ItemSize class, i create a construtor simple with all null -> ItemSize();
class ItemSize {
ItemSize.fromMap(Map<String, dynamic> map) {
name = map['name'] as String;
price = map['price'] as num;
stock = map['stock'] as int;
}
ItemSize();
String? name;
num? price;
int? stock;
bool get hasStock => stock! > 0;
#override
String toString() {
return 'ItemSize{name: $name, price: $price, stock: $stock}';
}
}
in the Product class do the get this way.
ItemSize get selectedSize {
if (_selectedSize != null)
return _selectedSize!;
else
return ItemSize();
}
Related
how can I read data from firebase firestory by getx
I make all models and controllers and try to read data, but something is wrong
class ContollerBinding extends Bindings{
#override
void dependencies() {
Get.lazyPut(() => DetailController());
Get.lazyPut(() => DetailModel());
}
}
class DetailController extends GetxController {
List<DetailModel> get detailModel => _detailModel;
List<DetailModel> _detailModel = [];
final CollectionReference _detialCollectionReference = FirebaseFirestore.instance.collection('detail');
DetailController(){
getDetail();
}
getDetail() async {
_detialCollectionReference.get().then((value) {
for (int i= 0 ; i< value.docs.length ;i++){
_detailModel.add(DetailModel.fromJson(value.docs[i].data())); //error here
}
update();
});
}
}
class DetailModel {
String? name;
String? title;
String? text;
String? img;
String? time;
String? prize;
DetailModel({ this.name, this.title, this.text, this.img, this.time, this.prize ,});
DetailModel.fromJson(Map<dynamic, dynamic>?map, data){
if (map == null){
return;
}
name = map['name'];
title = map['title'];
text = map['text'];
img = map['img'];
time = map['time'];
prize = map['prize'];
}
toJson (){
return {
name = 'name',
title = 'title',
text = 'text',
img = 'img',
time = 'time',
prize = 'prize',
};
}
}
I can't figure out where is the problem and I see a lot of videos and do like him, but it seems a problem
Gets a list of all the documents included in this snapshot.
2 positional argument(s) were expected, but 1 found.
Try adding the missing arguments.dartnot_enough_positional_arguments
The function can't be unconditionally invoked because it can be 'null'.
Try adding a null check ('!').dartunchecked_use_of_nullable_value
enter image description here
I'm tryng to get a list of boxes to show in a dropdown. But I am can't convert to list map to my object list.
Here's the error message:
A value of type 'List<Map<String, dynamic>>' can't be assigned to a variable of type 'List'.
Try changing the type of the variable, or casting the right-hand type to 'List'.
Here's the code:
import 'package:flutter/material.dart';
import 'package:trfcompactapp/constants.dart';
import '../model/sql_helper.dart';
import '../screens/drawer.dart';
import '../controller/localizationstrf.dart';
class ProjectBoxes {
ProjectBoxes(this.boxId, this.boxName, this.lenght, this.width, this.weight,
this.useLabel, this.labelOrientation, this.createdAt);
int boxId;
String boxName;
int lenght;
int width;
int weight;
int useLabel;
int labelOrientation;
DateTime createdAt;
}
class Project extends StatefulWidget {
const Project({super.key});
#override
State<Project> createState() => _ProjectState();
}
class _ProjectState extends State<Project> {
late ProjectBoxes selectedProjectBox;
#override
void initState() {
super.initState();
_refreshJournals();
}
List<Map<String, dynamic>> _journals = [];
List<Map<String, dynamic>> _journalBoxes = [];
bool _isLoading = true;
// This function is used to fetch all data from the database
void _refreshJournals() async {
final data = await SQLHelper.getProjects();
final dataBoxes = await SQLHelper.getBoxes();
setState(() {
_journals = data;
_isLoading = false;
_journalBoxes = dataBoxes;
boxes = _journalBoxes; // in this line the error happens.
});
}
late List<ProjectBoxes> boxes = <ProjectBoxes>[];
final TextEditingController _projectNameController = TextEditingController();
final TextEditingController _fkProjectBoxController = TextEditingController();
final TextEditingController _fkProjectPalletController =
TextEditingController();
final TextEditingController _fkProjectRobotController =
TextEditingController();
void _showForm(int? id) async {
if (id != null) {
final existingJournal =
_journals.firstWhere((element) => element['projectId'] == id);
final existingJournalBox = _journalBoxes.firstWhere(
(element) => element['boxId'] == existingJournal['FK_project_box']);
_projectNameController.text = existingJournal['projectName'];
_fkProjectBoxController.text =
existingJournalBox['FK_project_box'].toString();
_fkProjectPalletController.text =
existingJournal['FK_project_pallet'].toString();
_fkProjectRobotController.text =
existingJournal['FK_project_robot'].toString();
selectedProjectBox = existingJournalBox[0];
boxes = existingJournalBox[0];
}
It trys to assign List<Map> to a List. You'll have to write a converter to convert the data inside the Map to new ProjectBoxes objects.
Instead of boxes = _journalBoxes; use the following loop:
for (Map<String, dynamic> item in _journalBoxes) {
boxes.add(ProjectBoxes(
field1: item["firstField"] ?? "default value",
field2: item["thirdField"],
field3: item["secondField"] ?? false,
));
}
I don't know the structure of ProjectBoxes so I added some example values:
class ProjectBoxes {
// example fields
String field1;
int? field2;
bool field3;
// constructor
ProjectBoxes({
required this.field1,
this.field2,
required this.field3,
});
}
I have two provider classes where as a property there is an instance of a Combo object.
My problem is when I modify value properties of Combo object of provider one, the instance of provider two is modified as well.
This is a problem for me because it makes me impossible to have two different instances even when they are created on different classes.
#immutable class Combo
{
Combo(
{
this.idCombo = 0,
this.idThirdCombo = 0,
this.name = '',
this.urlImage = '',
final List<int>? recipy,
final List<Product>? selectedRecipy,
final List<OptionalRecepy>? optionalRecepy,
final SwitStoreProductType? type,
}) :
this.recipy = recipy ?? [],
this.selectedRecipy = selectedRecipy ?? [],
this.optionalRecepy = optionalRecepy ?? [],
this.type = type ?? SwitStoreProductType.none;
final int idCombo;
final int idThirdCombo;
final String name;
final String urlImage;
final List<int> recipy;
final List<Product> selectedRecipy;
final List<OptionalRecepy> optionalRecepy;
final SwitStoreProductType type;
}
//Provider One
class ProductDetailsBSProvider extends ChangeNotifier
{
Combo? _currentCombo;
void modifyCombo(Product product, int index)
{
if(index != this._currentOptionIndex)
{
if(this._currentCombo!.selectedRecipy.length > 1)
{
int previousIndex = (this._currentCombo!.selectedRecipy.length - 1);
this._currentCombo!.selectedRecipy.removeAt(previousIndex);
this._currentCombo!.selectedRecipy.insert(previousIndex, product);
this._currentOptionIndex = index;
}
else
{
this._currentCombo!.selectedRecipy.add(product);
this._currentOptionIndex = index;
}
}
else
{
if(this._currentCombo!.selectedRecipy.length == 0)
{
this._currentCombo!.selectedRecipy.add(product);
}
else
{
this._currentCombo!.selectedRecipy.removeLast();
this._currentCombo!.selectedRecipy.add(product);
}
}
notifyListeners();
}
}
//Provider Two
class StoreProvider extends ChangeNotifier
{
Combo? _currentCombo;
}
If I print the _currentCombo properties value of Provider Two it will be exactly the same as Provider One
I am setting values of variables declared in View Model class which is a StateNotifier, inside a function of widget. When I try to access the values of those variables from a different function of same widget, their values are null. I have debugged code to verify that first function is setting values correctly.
Any help will be highly appreciated.
Here is cutdown version of my StateNotifier
class ProductViewModel extends StateNotifier<ProductState> {
String errorMessage;
Product product;
final ProductService productService;
final CategoryService categoryService;
final BrandService brandService;
final TranslatorService translatorService;
final ProductOptionsViewModel productOptionsViewModel;
final ProductVariantViewModel productVariantViewModel;
ProductViewModel(this.productService, this.categoryService, this.brandService, this.translatorService,
this.productOptionsViewModel, this.productVariantViewModel)
: super(ProductInitial());
String productId;
List<SizeEnum> _sizes;
String _selectedBrand;
String _selectedCategory;
String _selectedStore;
String _productName;
String _productIntlName;
String _sku;
String get selectedBrand => _selectedBrand;
set selectedBrand(String value) {
_selectedBrand = value;
}
String get selectedCategory => _selectedCategory;
set selectedCategory(String value) {
_selectedCategory = value;
}
String get selectedStore => _selectedStore;
set selectedStore(String value) {
_selectedStore = value;
}
String get productName => _productName;
set productName(String value) {
_productName = value;
}
String get productIntlName => _productIntlName;
set productIntlName(String value) {
_productIntlName = value;
}
String get sku => _sku;
set sku(String value) {
_sku = value;
}
Future<bool> saveProductDetails() async {
bool isSave = false;
bool imageSaved = await saveProductImage();
if (!imageSaved) return imageSaved;
List<String> searchKeywords = indexProductName(_productName);
List<String> searchTag1 = _searchTag1 != null ? indexProductName(_searchTag1) : null;
List<String> searchTag2 = _searchTag2 != null ? indexProductName(_searchTag2) : null;
List<String> searchTag3 = _searchTag3 != null ? indexProductName(_searchTag3) : null;
if (deal != null && _dealsAddedDateTime == null) {
_dealsAddedDateTime = DateTime.now();
}
print(productOptionsViewModel.toString());
Product _product = Product(
productId: productId,
name: _productName,
intlName: _productIntlName,
category: FirebaseFirestore.instance.doc(_selectedCategory),
brand: FirebaseFirestore.instance.doc(_selectedBrand),
sku: _sku,
quantity: _quantity,
price: _price,
containSizes: productOptionsViewModel.sizes,
containColors: productOptionsViewModel.colors,
accessory: productOptionsViewModel.accessory ,
salesTaxApplicable: productOptionsViewModel.salesTax,
);
isSave = await productService.saveProduct(_product);
if (!isSave) {
errorMessage = "Error in saving product information";
} else {
productId = productService.newProductId;
}
return isSave;
}
}
StateNotifierProvider declaration
final productViewModelProvider = StateNotifierProvider.autoDispose<ProductViewModel,ProductState>((ref) => ProductViewModel(
ref.watch(productServiceProvider),
ref.watch(categoryServiceProvider),
ref.watch(brandServiceProvider),
ref.watch(translatorServiceProvider),
ref.watch(productOptionsViewModelProvider),
ref.watch(productVariantViewModelProvider)));
UI Functions
I set values in validateProduct and read values again in saveProductDetails.
Future<bool> validateProduct() async {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
final model = context.read(productViewModelProvider.notifier);
final storeViewModel = context.read(storeViewModelProvider.notifier);
var _store = await storeViewModel.getMyStore();
model.productName = _productName;
model.productIntlName = _productIntlName;
model.sku = _sku;
model.quantity = _quantity;
model.price = _price;
model.selectedBrand = _selectedBrand;
model.selectedCategory = _selectedCategory;
model.selectedStore = _storeCode;
model.description = _productDescription;
model.manufacturerLink = _manufacturerLink;
model.searchTag1 = _searchTag1;
model.searchTag2 = _searchTag2;
model.searchTag3 = _searchTag3;
if (model.addedDateTime == null) {
model.addedDateTime = DateTime.now();
}
if (_storeCode == null) {
_storeCode = _store.store;
}
if (model.selectedStore == null) {
model.selectedStore = _storeCode;
}
return true;
}
else return false;
}
Future<bool> saveProductDetails() async {
final model = context.read(productViewModelProvider.notifier);
bool isProductSaved = await model.saveProductDetails();
if (isProductSaved) {
if (_isProductExist) {
displayMessage(context, "Product Information Updated");
} else
displayMessage(context, "Product Information Saved");
_formSaved = true;
isFormChanged = false;
return true;
} else if (isProductSaved == false) {
_formSaved = false;
displayMessage(context, model.errorMessage);
}
return isProductSaved;
}
State
abstract class ProductState {
const ProductState();
}
class ProductInitial extends ProductState {
const ProductInitial();
}
class ProductLoading extends ProductState {
const ProductLoading();
}
class ProductLoaded extends ProductState {
final Product product;
ProductLoaded(this.product);
#override
bool operator ==(Object other) =>
identical(this, other) || other is ProductLoaded && runtimeType == other.runtimeType && product == other.product;
#override
int get hashCode => product.hashCode;
}
class ProductSaving extends ProductState {
const ProductSaving();
}
class ProductSaved extends ProductState {
final Product product;
ProductSaved(this.product);
#override
bool operator ==(Object other) =>
identical(this, other) || other is ProductSaved && runtimeType == other.runtimeType && product == other.product;
#override
int get hashCode => product.hashCode;
}
class ProductError extends ProductState {
final String errorMessage;
ProductError(this.errorMessage);
}
Remove .autoDispose modifier
final productViewModelProvider = StateNotifierProvider<ProductViewModel,ProductState>((ref) => ProductViewModel(
ref.watch(productServiceProvider),
ref.watch(categoryServiceProvider),
ref.watch(brandServiceProvider),
ref.watch(translatorServiceProvider),
ref.watch(productOptionsViewModelProvider),
ref.watch(productVariantViewModelProvider)));
Hi I need to retrieve all documents from firestore collection with this:
EventList<Event>testdata(QuerySnapshot snapshot) {
return snapshot.docs.map((data) => EventList<Event>(events: {
data['date']: [
Event(
date: data['date'], title: data['name'], icon: Icon(
Icons.block,
color: Colors.red[200],
size: 30,
)),
]
})).toList();
}
Stream<EventList<Event>> get caldendardata {
return events.snapshots().map(testdata);
}
but i get this error: A value of type 'List<EventList<Event>>' can't be returned from the method 'testdata' because it has a return type of 'EventList<Event>'.
The Firestore :
I'm using this package to add calendar to my app it requires the event on the calendar to be {EventList<Event>? markedDatesMap} .
EventList form the package:
class EventList<T> {
Map<DateTime, List<T>> events;
EventList({
required this.events,
});
void add(DateTime date, T event) {
final eventsOfDate = events[date];
if (eventsOfDate == null)
events[date] = [event];
else
eventsOfDate.add(event);
}
void addAll(DateTime date, List<T> events) {
final eventsOfDate = this.events[date];
if (eventsOfDate == null)
this.events[date] = events;
else
eventsOfDate.addAll(events);
}
bool remove(DateTime date, T event) {
final eventsOfDate = events[date];
return eventsOfDate != null ? eventsOfDate.remove(event) : false;
}
List<T> removeAll(DateTime date) {
return events.remove(date) ?? [];
}
void clear() {
events.clear();
}
List<T> getEvents(DateTime date) {
return events[date] ?? [];
}
}
Event form the package:
class Event implements EventInterface {
final DateTime date;
final String? title;
final Widget? icon;
final Widget? dot;
final int? id;
Event({
this.id,
required this.date,
this.title,
this.icon,
this.dot,
});
#override
bool operator ==(dynamic other) {
return this.date == other.date &&
this.title == other.title &&
this.icon == other.icon &&
this.dot == other.dot &&
this.id == other.id;
}
#override
int get hashCode => hashValues(date, title, icon, id);
#override
DateTime getDate() {
return date;
}
#override
int? getId() {
return id;
}
#override
Widget? getDot() {
return dot;
}
#override
Widget? getIcon() {
return icon;
}
#override
String? getTitle() {
return title;
}
}
abstract class EventInterface {
DateTime getDate();
String? getTitle();
Widget? getIcon();
Widget? getDot();
int? getId();
}
I would appreciate a little help here.
Thank you in advance
map returns a List. That's why you have a List<EventList>.
I believe you are trying to flatten the list so that you instead have a single EventList with all of the events. One way to accomplish this is to use fold.
Here is an example that you should be able to apply to your code. One could paste this into Dartpad to quickly see how it works:
class Event {
const Event(this.id);
final int id;
}
class EventList {
const EventList({required this.events});
final List<Event> events;
}
class FirebaseData {
const FirebaseData(this.docs);
final List<Event> docs;
}
void main() {
// Simulating your data stream
final FirebaseData snapshot = FirebaseData(List.generate(5, (index) => Event(index)));
// What you are returning from your code currently
final List<EventList> eventListList =
snapshot.docs.map((data) => EventList(events: [data])).toList();
// What you actually want to return from your code
final EventList eventList = eventListList.fold(EventList(events: []),
(previousValue, element) => EventList(events: previousValue.events..addAll(element.events)));
print(eventList.events);
}
When performing toList you getting a List<EventList<Event>> each EventList with one event.
I think you want to get a List<Map> from Firestore to later build your class.
You can achieve that with a code like this.
EventList<Event>testdata(QuerySnapshot snapshot) {
//Get all data
final List<Map> eventListMap = snapshot.docs.map((data) => {
data['date']: [
Event(
date: data['date'], title: data['name'], icon: Icon(
Icons.block,
color: Colors.red[200],
size: 30,
)),
]
}).toList();
//Join to single Map, it should not contain repeated keys (date) as one of them would be lost
final Map eventsMap = eventsData.fold({},(map1, map2) => map1..addAll(map2));
//Return your class
return EventList<Event>(events: eventsMap);
}
Stream<EventList<Event>> get caldendardata {
return events.snapshots().map(testdata);
}
I did not try it and you can rename or change anything.