add new elements to class - flutter

I've written a class like this,
class LessonCategory{final String name;
LessonCategory(this.name);
#override
String toString() {
return 'LessonCategory{name: $name}';
}
}
class Lessons {
final String lessonsName;
int discontinuity;
final LessonCategory lesscategory;
Lessons(this.lessonsName, this.discontinuity,
this.lesscategory,
);
#override
String toString() {
return 'Lessons{lessonsName: $lessonsName, discontinuity:
$discontinuity, lesscategory: $lesscategory}';
}
}
class Data {
static List<LessonCategory> categories = [
LessonCategory("a1"),
];
static List<Lessons> lessons = [
Lessons(
'Lesson A1',
0,
getCategoryFromName("a1"),
),
];
static LessonCategory getCategoryFromName(name) {
return categories.firstWhere(
(c) => c.name.toLowerCase() == name.toString().toLowerCase());
}
}
But I can't figure out how to add a new element.I already tried add,push,insert (or i missed something).
Can someone please show me the right way?
i want something like
Data.lessons.add({
lessonsName: 'Lesson Z1',
discontinuity: 0
lessCategory: 'a1'
});

just remove static syntax. if it is defined as static, it will be immutable
class Data {
static List<LessonCategory> categories = [
LessonCategory("a1"),
];
List<Lessons> lessons = [ // Remove Static syntax
Lessons(
'Lesson A1',
0,
getCategoryFromName("a1"),
),
];
static LessonCategory getCategoryFromName(name) {
return categories.firstWhere(
(c) => c.name.toLowerCase() == name.toString().toLowerCase());
}
}
but also we can correct another syntaxes
Data newData = Data();
newData.lessons.add(Lessons(
'Lesson Z1', // remove named parameters, and use positional params
0,
LessonCategory('a1'),
));
print("New Length : ${newData.lessons.length}");
Fully working code
class LessonCategory {
final String name;
LessonCategory(this.name);
#override
String toString() {
return 'LessonCategory{name: $name}';
}
}
class Lessons {
final String lessonsName;
int discontinuity;
final LessonCategory lesscategory;
Lessons(
this.lessonsName,
this.discontinuity,
this.lesscategory,
);
#override
String toString() {
return """Lessons{lessonsName: $lessonsName, discontinuity: $discontinuity, lesscategory: $lesscategory}""";
}
}
class Data {
static List<LessonCategory> categories = [
LessonCategory("a1"),
];
List<Lessons> lessons = [ // Remove Static syntax
Lessons(
'Lesson A1',
0,
getCategoryFromName("a1"),
),
];
static LessonCategory getCategoryFromName(name) {
return categories.firstWhere(
(c) => c.name.toLowerCase() == name.toString().toLowerCase());
}
#override
String toString() {
return "{${lessons.map((fruit) => print(fruit))}}";
}
}
main(List<String> args) {
Data newData = Data(); // Create instance first
newData.lessons.add(Lessons(
'Lesson Z1', // remove named parameters, and use positional params
0,
LessonCategory('a1'),
));
print("New Length : ${newData.lessons.length}");
newData.lessons.add(Lessons(
'Lesson Z1',
0,
LessonCategory('a1'),
));
print("New Length : ${newData.lessons.length}");
print("${newData.lessons}");
}
which we able to play arount in Dartpad
Result

remove the static syntax and the problem will be solved

Related

Dart - How to merge two list of objects into singe list

2> as you can see below i have two list of object and i want to merge into single it should compare list based on date
//here is the list 1
List<Object1> list1=[
Object1("date":"1","day_data":12),
Object1("date":"2","day_data":15),
]
//here is the list 2
List<Object2> list2=[
Object2("date":"1","night_data":56),
Object2("date":"3","night_data":80),
];
//expected output
List<Object3> expectedList=[
Object3("date":"1","day_data":12,"night_data":56),
Object3("date":"2","day_data":15,"night_data":null),
Object3("date":"3","day_data":null,"night_data":80),
];
The code below should do the trick. It uses a Map where the keys are, let's say, the Primary Key. And the values are the reduce from list1 and list2 (It even merges duplicated items by date from list1 and/or list2). At the end, I've added some asserts to actually test if it works.
Here's also the DartPad to run it online.
class Object1 {
final String date;
final int day_data;
const Object1({required this.date, required this.day_data});
}
class Object2 {
final String date;
final int night_data;
const Object2({required this.date, required this.night_data});
}
class Object3 {
final String date;
final int? day_data;
final int? night_data;
const Object3({required this.date, this.day_data, this.night_data});
}
List<Object3> merge(List<Object1> obj1List, List<Object2> obj2List) {
final map = <String, Object3>{};
obj1List.forEach((obj1) =>
map.update(
obj1.date,
(obj3) => Object3(date: obj3.date, day_data: obj1.day_data, night_data: obj3.night_data),
ifAbsent: () => Object3(date: obj1.date, day_data: obj1.day_data, night_data: null),
));
obj2List.forEach((obj2) =>
map.update(
obj2.date,
(obj3) => Object3(date: obj3.date, day_data: obj3.day_data, night_data: obj2.night_data),
ifAbsent: () => Object3(date: obj2.date, day_data: null, night_data: obj2.night_data),
));
return map.values.toList()
..sort((a, b) => a.date.compareTo(b.date));
}
void main() {
//here is the list 1
List<Object1> list1=[
Object1(date:"1",day_data:12),
Object1(date:"2",day_data:15),
];
//here is the list 2
List<Object2> list2=[
Object2(date:"1",night_data:56),
Object2(date:"3",night_data:80),
];
List<Object3> actualList = merge(list1, list2);
//expected output
List<Object3> expectedList=[
Object3(date:"1",day_data:12,night_data:56),
Object3(date:"2",day_data:15,night_data:null),
Object3(date:"3",day_data:null,night_data:80),
];
print('Checking size...');
assert(actualList.length == expectedList.length);
print('OK');
print('Checking items...');
actualList.asMap().forEach((i, actual) {
final expected = expectedList[i];
print(' Checking item $i...');
assert(actual.date == expected.date);
assert(actual.day_data == expected.day_data);
assert(actual.night_data == expected.night_data);
print(' OK');
});
print('OK');
}
You need to do manually with two loops and comparing dates.
Hey you can achieve by compering two list and get list like below -
void compareList(){
List<ObjectModel> list1=[
ObjectModel(date:"1",dayData:12),
ObjectModel(date:"2",dayData:15),
];
//here is the list 2
List<ObjectModel> list2=[
ObjectModel(date:"1",nightData:56),
ObjectModel(date:"3",nightData:80),
];
//expected output
List<ObjectModel> expectedList= [];
list1.forEach((element) {
ObjectModel innerObject = list2.firstWhere((ObjectModel innerElement) => element.date == innerElement.date, orElse: (){return ObjectModel();});
if(innerObject.date !=null){
expectedList.add(ObjectModel(date:element.date,dayData:element.dayData,nightData: innerObject.nightData));
}else{
expectedList.add(element);
}
});
list2.forEach((element) {
ObjectModel innerObject = list1.firstWhere((ObjectModel innerElement) => element.date == innerElement.date, orElse: (){return ObjectModel();});
if(innerObject.date ==null){
expectedList.add(element);
}
});
print(expectedList.length);
}
class ObjectModel{
String? date;
int? dayData;
int? nightData;
ObjectModel({ this.date, this.dayData, this.nightData});
}

How to check if list contains a String, but String value is from other dart file

As you can see I have a list:
List avatarList = [
AssetsResources.VIP1,
AssetsResources.VIP2,
AssetsResources.VIP3,
AssetsResources.VIP4,
AssetsResources.VIP5,
AssetsResources.w1,
AssetsResources.w2,
];
I understand I can use method:
final bool isVIP = avatarList[index].contains('VIP');
But since AssetsResources.VIP1 is not a String like 'VIP1'but a path from other dart file, so here I have no idea how to check if the element from avatarList contains VIP value, thanks for any clue!
Update
Thanks guys for the help and sorry I didnt describe clearly, what I mean is, if
List idealList = [
'vip1',
'vip2',
'vip3',
'vip4',
'vip5',
];
so the elements in the idealList is 'vip1' but in my case the list myList is
List myList = [
AssetsResources.VIP1,
AssetsResources.VIP2,
AssetsResources.VIP3,
AssetsResources.VIP4,
AssetsResources.VIP5,
AssetsResources.w1,
AssetsResources.w2,
];
So it seems I can not directly use some methode as follows
final bool isVIP = myList[index].contains('VIP');
since the elements from myList is just a path(sorry I dont know how to call this value), could you please let me know in my case how to check if this path contains 'VIP' value? thanks!
Update
yes, AssetsResources is very simple, just store the asset path:
class AssetsResources {
/*worm avatar*/
static const String VIP1 = 'assets/worms/VIP_1.svg';
static const String VIP2 = 'assets/worms/VIP_2.svg';
static const String VIP3 = 'assets/worms/VIP_3.svg';
static const String VIP4 = 'assets/worms/VIP_4.svg';
}
The code should work fine :
class AssetsResources {
/*worm avatar*/
static const String VIP1 = 'assets/worms/VIP_1.svg';
static const String VIP2 = 'assets/worms/VIP_2.svg';
static const String VIP3 = 'assets/worms/VIP_3.svg';
static const String VIP4 = 'assets/worms/VIP_4.svg';
}
void main() {
List myList = [
AssetsResources.VIP1,
AssetsResources.VIP2,
AssetsResources.VIP3,
AssetsResources.VIP4,
];
for (final asset in myList) {
print(asset);
print(asset.contains('VIP'));
}
}
The above prints :
assets/worms/VIP_1.svg
true
assets/worms/VIP_2.svg
true
assets/worms/VIP_3.svg
true
assets/worms/VIP_4.svg
true
If I understood you correctly.
void main() {
for(var i = 0; i < avatarList.length; i++) {
String element = avatarList[i];
if(element.contains('VIP')) {
print(other.contains(element)); // true
print(other.firstWhere((e) => e.contains(element))); // 'VIP1', 'VIP2', 'VIP3', 'VIP4', 'VIP5'
}
}
}
List<String> avatarList = ['VIP1', 'VIP2', 'VIP3', 'VIP4', 'VIP5', 'w1', 'w2'];
List<String> other = ['VIP1', 'VIP2', 'VIP3', 'VIP4', 'VIP5', 'w1', 'w2'];

RiverPod Maintaining selected item of list

I am new to riverpod and trying to figure out a state management issue.
I have one list, and two independent states which need access to the list. The states also need to select an element of the list and know what its index is. The list can totally change (add or remove elements) and the states need to determine if their selected element is still in the list and update the index accordingly (to 0 if it is not found)
Here is an example with Riverpod in pure dart:
import 'package:riverpod/riverpod.dart';
void main(List<String> arguments) {
final container = ProviderContainer();
List<String> names = ["Jack", "Adam", "Sally"];
container.read(nameListProvider.notifier).setNames(names);
//selectedName1 = "Adam"
//selectedIndex1 = 1
//selectedName2 = "Sally"
//selectedIndex2 = 2
names.remove('Adam');
container.read(nameListProvider.notifier).setNames(names);
// print(selectedName1) = "Jack" // set to 0 because selection was removed
// print(selectedIndex1) = 0
// print(selectedName2) = "Sally"
// print(selectedIndex2) = 1 // decrement to match Sally's new list index
}
final nameListProvider =
StateNotifierProvider<NameListNotifier, List<String>>((ref) {
return NameListNotifier();
});
class NameListNotifier extends StateNotifier<List<String>> {
NameListNotifier() : super([]);
setNames(List<String> names) {
state = names;
}
}
But I need the selected Name and Index to be Providers
Update: Here is my more elegant solution:
import 'package:riverpod/riverpod.dart';
void main(List<String> arguments) {
final container = ProviderContainer();
List<String> names = ["Jack", "Adam", "Sally"];
print(container.read(nameListProvider));
container.read(nameListProvider.notifier).setNames(names);
var first = container.read(selectionProvider(1).notifier);
first.setName(1);
print(container.read(selectionProvider(1)).name);
var second = container.read(selectionProvider(2).notifier);
second.setName(2);
print(container.read(selectionProvider(2)).name);
names.remove('Adam');
List<String> newNames = List.from(names);
container.read(nameListProvider.notifier).setNames(newNames);
print(container.read(selectionProvider(1)).name);
print(container.read(selectionProvider(1)).index);
print(container.read(selectionProvider(2)).name);
print(container.read(selectionProvider(2)).index);
print(container.read(nameListProvider));
}
final selectionProvider =
StateNotifierProvider.family<SelectionNotifier, Selection, int>(
(ref, page) {
return SelectionNotifier(ref.read);
});
class SelectionNotifier extends StateNotifier<Selection> {
Reader _read;
SelectionNotifier(this._read) : super(Selection());
update() {
final String? selectedName = state.name;
final List<String> names = _read(nameListProvider);
if (names == []) {
state = Selection();
return null;
}
if (selectedName == null) {
state = Selection(name: names[0], index: 0);
return;
}
int i = names.indexOf(selectedName);
if (i == -1) {
state = Selection(name: names[0], index: 0);
return;
}
state = Selection(name: selectedName, index: i);
return;
}
setName(int index) {
final List<String> names = _read(nameListProvider);
state = Selection(name: names[index], index: index);
}
}
final nameListProvider =
StateNotifierProvider<NameListNotifier, List<String>>((ref) {
return NameListNotifier(ref.read);
});
class NameListNotifier extends StateNotifier<List<String>> {
Reader _read;
NameListNotifier(this._read) : super([]);
setNames(List<String> names) {
state = names;
_read(selectionProvider(0).notifier).update();
_read(selectionProvider(1).notifier).update();
}
}
class Selection {
final String? name;
final int? index;
Selection({this.name, this.index});
}

How to create a List of Object in Back4App?

I'm using back4app in my application and I have a class like this called Meal:
and this is my code snippet :
class EatenMeals with ChangeNotifier {
List<Meal> _eatenMeals = [];
List<Meal> get eatenMeals {
return [..._eatenMeals];
}
void addMeal(Meal meal) {
var newMeal = Meal(
id: meal.id,
cal: meal.cal,
catId: meal.catId,
title: meal.title,
duration: meal.duration,
affordability: meal.affordability,
imageUrl: meal.imageUrl,
ingredients: meal.ingredients,
isBreakfast: meal.isDinner,
isDinner: meal.isDinner,
isLunch: meal.isLunch,
steps: meal.steps);
_eatenMeals.add(newMeal);
}
}
Now I want to create a class that contain list of Meals object.
and attach to users how do I achieve this?
Checkout Parse Server Custom Objects. Here is an example for your case how to create a Custom Object for Meal.
class Meal extends ParseObject implements ParseCloneable {
Meal() : super(_keyTableName);
Meal.clone() : this();
/// Looks strangely hacky but due to Flutter not using reflection, we have to
/// mimic a clone
#override
clone(Map map) => Meal.clone()..fromJson(map);
/// Colum names
static const String _keyTableName = 'Meal';
static const String keyCatId = 'catId';
static const String keyTitle = 'title';
static const String keyImgUrl = 'imgUrl';
static const String keyIngredients = 'ingredients';
static const String keySteps = 'steps';
static const String keyCalorie = 'calorie';
static const String keyDuration = 'duration';
static const String keyAffordability = 'affordability';
static const String keyIsBreakfast = 'isBreakfast';
static const String keyIsLunch = 'isLunch';
static const String keyIsDinner = 'isDinner';
/// Getter & Setters
List<String> get catId => get<List<String>>(keyCatId);
set name(List<String> catId) => set<List<String>>(keyCatId, catId);
String get title => get<String>(keyTitle);
set title(String title) => set<String>(keyTitle, title);
Strin> get imgUrl => get<String>(keyImgUrl);
set imgUrl(String imgUrl) => set<String>(keyImgUrl, imgUrl);
List<String> get ingredients => get<List<String>>(keyIngredients);
set ingredients(List<String> ingredients) => set<List<String>>(keyIngredients, ingredients);
List<String> get steps => get<List<String>>(keySteps);
set steps(List<String> steps) => set<List<String>>(keySteps, steps);
num get calorie => get<num>(keyCalorie);
set calorie(num calorie) => set<num>(keyCalorie, calorie);
num get duration => get<num>(keyDuration);
set affordability(num duration) => set<num>(keyDuration, duration);
String get affordability => get<String>(keyAffordability);
set name(String affordability) => set<String>(keyAffordability, affordability);
bool get isBreakfast => get<bool>(keyIsBreakfast);
set isBreakfast(bool isBreakfast) => set<bool>(keyIsBreakfast, isBreakfast);
bool get isLunch => get<bool>(keyIsLunch);
set isLunch(bool isLunch) => set<bool>(keyIsLunch, isLunch);
bool get isDinner => get<bool>(keyIsDinner);
set isDinner(bool isDinner) => set<bool>(keyIsDinner, isDinner);
}
Then you have to register this subclass.
Parse().initialize(
...,
registeredSubClassMap: <String, ParseObjectConstructor>{
'Meal': () => Meal(),
},
);

flutter - Comparing two lists of objects isn't working

I've two lists of objects that i wanna compare, a and b:
final dia = DateTime(2017, 9, 7, 17, 30);
final ppp = Parcela("1", 225.5, dia, null, 1, false, false);
final ppp2 =Parcela("1", 225, dia.add(const Duration(days: 3)), null, 1, false, false);
final ppp3 =Parcela("1", 225, dia.add(const Duration(days: 3)), null, 1, false, false);
List<Parcela> a = [ppp,ppp2,];
List<Parcela> b = [ppp, ppp3];
Both of them are equal, but when i try to check it with the functions bellow i get false on response:
print(a.every(b.toSet().contains));
print(listEquals(a, b));
I tried also "quiver" and "collection" libraries from pub dev but the result is the same
The Parcela model:
class Parcela {
String id;
double valor;
DateTime dataPagamento;
DateTime dataPago;
int status;
int ref;
Parcela(String id, double valor, DateTime dataPagamento, DateTime dataPago,
int ref, bool pago, bool atraso) {
this.id = id;
this.valor = valor;
this.dataPagamento = dataPagamento;
this.dataPago = this.dataPago;
this.status = _getStatus(pago, atraso);
this.ref = this.ref;
}
int _getStatus(bool pago, bool atraso) {
if (pago) {
if (atraso) {
return 3;
} else {
return 1;
}
} else {
if (atraso) {
return 2;
} else {
return 0;
}
}
}
}
Edit1:
I've tried Dan James suggestion but my class isn't final as his, so i've removed "final" from name attribute:
class Person extends Equatable {
Person(this.name);
String name;
#override
List<Object> get props => [name];
}
the new test vars:
Person p = Person("name");
Person p2 = Person("name2");
Person p3 = Person("tobias");
List<Person> aa = [p, p2];
List<Person> bb = [p, p2..name = "teste"];
List<Person> cc = [p, p3];
but when i test the lists:
var filtered_lst =List.from(aa.where((value) => !bb.contains(value)));
print(filtered_lst);
print(listEquals(aa, bb));
print(listEquals(aa, cc));
the console returns this:
I/flutter (12746): []
I/flutter (12746): true
I/flutter (12746): false
ppp2 does not equal ppp3 because they are two different instances of a class. You could override the '==' operator to check if each field is the same. ie. ppp2.id == ppp3.id.
eg/ (taken from equatable docs but this is vanillar dart)
class Person {
const Person(this.name);
final String name;
#override
bool operator ==(Object other) =>
identical(this, other) ||
other is Person &&
runtimeType == other.runtimeType &&
name == other.name;
#override
int get hashCode => name.hashCode;
}
Or look into the equatable package which does this for you. https://pub.dev/packages/equatable
Straight from the equatable docs:
import 'package:equatable/equatable.dart';
class Person extends Equatable {
const Person(this.name);
final String name;
#override
List<Object> get props => [name];
}
Using the library equatable from Dan James answer:
import 'package:equatable/equatable.dart';
// ignore: must_be_immutable
class Parcela extends Equatable {
String id;
double valor;
DateTime dataPagamento;
DateTime dataPago;
int status;
int ref;
Parcela(String id, double valor, DateTime dataPagamento, DateTime dataPago,
int ref, bool pago, bool atraso) {
this.id = id;
this.valor = valor;
this.dataPagamento = dataPagamento;
this.dataPago = this.dataPago;
this.status = _getStatus(pago, atraso);
this.ref = this.ref;
}
int _getStatus(bool pago, bool atraso) {
if (pago) {
if (atraso) {
return 3;
} else {
return 2;
}
} else {
if (atraso) {
return 1;
} else {
return 0;
}
}
}
#override
List<Object> get props => [id,valor,dataPagamento,];
}
The only way of copying a list that doesn't point to the same memory address:
List<Parcela> copyParcelas(List<Parcela> list) {
List<Parcela> copyList = [];
for (var item in list) {
List<bool> _status = pagoAtraso(item.status);
Parcela betItems = Parcela(item.id, item.valor, item.dataPagamento,
item.dataPago, item.ref, _status[0], _status[1]);
copyList.add(betItems);
}
return copyList;
}
Then the check to return the list items that changed:
List<Parcela> editarParcelas(List<Parcela> parcelas, List<Parcela> original){
return filteredlst = parcelas.toSet().difference(original.toSet()).toList();
}