Flutter provider consumer removes my items - flutter

I'm trying to build a sort function in order to sort JSON data.
For this, I have a button that opens a "showModalBottomSheet".
Within it I can choose the following data of the school class numbers.
So in my data I have 6 classrooms when loading in my constructor.
My filter is represented by buttons which are active or not if the filter contains the number of the classroom. My code works pretty much, my problem is that when I select a filter button in order to activate or not the filter, the button is deleted instead of staying but changing color
My notifier :
class TablesNotifier with ChangeNotifier {
// Services
// ---------------------------------------------------------------------------
final jsonSelectorService = locator<JsonSelectorService>();
// Variables
// ---------------------------------------------------------------------------
//all data from my classerooms in JSON
List<ClassroomModel> classrooms;
// Data that I will display and reconstruct based on my filter parameters
List<ClassroomModel> classroomsFiltered;
List<int> numberOfClassrooms = List();
// Model which will store the parameters of my filters and as a function I will load the data to display
FilterClassroomsModel filterClassroomsModel = FilterClassroomsModel();
// Constructor
// ---------------------------------------------------------------------------
TablesNotifier(){
_initialise();
}
// Initialisation
// ---------------------------------------------------------------------------
Future _initialise() async{
classrooms = await jsonSelectorService.classrooms('data');
classroomsFiltered = classrooms ;
// I install the number of existing classrooms
// Here the result is [1,2,3,4,5,6]
classrooms.forEach((element) {
if(!numberOfClassrooms.contains(element.type)){
numberOfClassrooms.add(element.type);
}
});
// I install the number of classrooms activated by default in my filter
// As I decide to display all my classrooms by default
// My filter on the classrooms must contain all the loaded classrooms
filterClassroomsModel.classrooms = numberOfClassrooms;
notifyListeners();
}
// Functions public
// ---------------------------------------------------------------------------
void saveClassroomsSelected(int index)
{
// Here my classroom model also contains the numbers of the classrooms that I want to filter
if(filterClassroomsModel.classrooms.contains(index)){
filterClassroomsModel.classrooms.remove(index);
}else{
filterClassroomsModel.classrooms.add(index);
}
notifyListeners();
}
}
I have identified that in my function initialize () if I change my code by this it works :
filterClassroomsModel.classrooms= numberOfClassrooms; // this
filterClassroomsModel.classrooms= [1,2,3,4,5,6]; // By this
I am losing the dynamic side of my classroom calculation and that does not suit me. But I don't understand this behavior.
My view :
class TableScreen extends StatelessWidget {
final String title;
TableScreen({Key key, #required this.title}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
drawer: MenuDrawerComponent.builder(context),
appBar: AppBar(
backgroundColor: AppColors.backgroundDark,
elevation: 0,
centerTitle: true,
title: Text(title),
),
floatingActionButton: FloatingActionButton.extended(
icon: Icon(Icons.sort),
label: Text('Filter'),
onPressed: () async{
slideSheet(context);
},
backgroundColor: AppColors.contrastPrimary,
),
body: _buildBody(context),
);
}
Widget _buildBody(BuildContext context)
{
var _tableProvider = Provider.of<TablesNotifier>(context);
if(_tableProvider.chargesFiltered == null){
return Center(
child: CircularProgressIndicator(
backgroundColor: AppColors.colorShadowLight,
),
);
}else{
return Column(
children: <Widget>[
Expanded(
child: Container(
padding: EdgeInsets.only(top: 10, right : 20, left : 20),
child: ListView.builder(
itemCount: _tableProvider.classroomsFiltered.length,
itemBuilder: (context, index){
return Container(
child: Column(
children: [
Row(
// Some classrooms data
),
],
),
);
},
),
)
),
],
);
}
}
void slideSheet(BuildContext context) {
var _tableProvider = Provider.of<TablesNotifier>(context, listen:false);
showModalBottomSheet(
context: context,
isScrollControlled: true,
isDismissible: true,
builder: (context) {
return Wrap(
children: [
Container(
color: Color(0xFF737373),
child: Container(
child: Column(
children: <Widget>[
// Some filters ...
// Here I want to rebuild the list of button for show the changes
ChangeNotifierProvider.value(
value: _tableProvider,
child: Consumer<TablesNotifier>(
builder: (context, model, child){
return _listOfClassrooms(context);
}
),
),
],
),
),
),
]
);
});
}
Widget _listOfClassrooms(BuildContext context){
var _tableProvider = Provider.of<TablesNotifier>(context);
List<Widget> list = List<Widget>();
var listClassrooms = _tableProvider.numberOfClassrooms;
var filterClassrooms = _tableProvider.filterClassroomsModel.classrooms;
for (var i = 0; i < listClassrooms.length; i++) {
int selectIndex = 0;
if(filterClassrooms.contains(listClassrooms[i])){
selectIndex = listClassrooms[i];
}
list.add(
RadioComponent(
text: "${listClassrooms[i]}",
index: listClassrooms[i],
width: (MediaQuery.of(context).size.width - 56) /3,
selectedIndex: selectIndex,
onPressed: _tableProvider.saveChargesSelected,
),
);
}
return Wrap(
spacing: 8.0, // gap between adjacent chips
runSpacing: 8.0, // gap between lines
children: list
);
}
}
My FilterClassroomsModel :
class FilterClassroomsModel {
int order;
int sort;
List<int> classrooms;
FilterClassroomsModel ({
this.order = 0,
this.sort = 0,
this.classrooms = const[],
});
#override
String toString() {
return '{ '
'${this.order}, '
'${this.sort}, '
'${this.classrooms}, '
'}';
}
}
EDIT : Resolved topic. Thanks to Javachipper.
In the notifier I replace that :
filterClassroomsModel.classrooms = numberOfClassrooms;
By that :
filter.classrooms = List<int>();
filter.classrooms.addAll(numberOfClassrooms);

change this:
filterClassroomsModel.classrooms = numberOfClassrooms;
to:
filterClassroomsModel.classrooms.addAll(numberOfClassrooms);
Update (you can also do it like this):
filterClassroomsModel.classrooms= new List<int>();
filterClassroomsModel.classrooms.addAll(numberOfClassrooms);

Related

How to change variable value in flutter with bloc?

Want to ask is How to change variable value with stream flutter?
You think my question is so fundamental and I can search in everywhere on internet. But in this scenario with stream, I can't change the variable value with method. How I need to do? please guide me. I will show with example.
Here, this is bloc class code with rxDart.
class ChangePinBloc {
final ChangePinRepository _changePinRepository = ChangePinRepository();
final _isValidateConfirmNewPinController = PublishSubject();
String oldPin = '';
Stream get isValidateConfirmNewPinStream =>
_isValidateConfirmNewPinController.stream;
void checkValidateConfirmNewPin(
{required String newPinCode, required String oldPinCode}) {
if (newPinCode == oldPinCode) {
oldPin = oldPinCode;
changePin(newCode: newPinCode);
isValidateConfirmPin = true;
_isValidateConfirmNewPinController.sink.add(isValidateConfirmPin);
} else {
isValidateConfirmPin = false;
_isValidateConfirmNewPinController.sink.add(isValidateConfirmPin);
}
}
void changePin({required String newCode}) async {
changePinRequestBody['deviceId'] = oldPin;
}
dispose() {
}
}
Above code, want to change the value of oldPin value by calling checkValidateConfirmNewPin method from UI. And want to use that oldPin value in changePin method. but oldPin value in changePin always get empty string.
This is the calling method checkValidateConfirmNewPin from UI for better understanding.
PinCodeField(
pinLength: 6,
onComplete: (value) {
pinCodeFieldValue = value;
changePinBloc.checkValidateConfirmNewPin(
newPinCode: value,
oldPinCode: widget.currentPinCodeFieldValue!);
},
onChange: () {},
),
Why I always get empty String although assign a value to variable?
Lastly, this is complete code that calling state checkValidateConfirmNewPin from UI.
void main() {
final changePinBloc = ChangePinBloc();
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: StreamBuilder(
stream: changePinBloc.isValidateConfirmNewPinStream,
builder: (context, AsyncSnapshot pinValidateSnapshot) {
return Stack(
children: [
Positioned.fill(
child: Column(
children: [
const PinChangeSettingTitle(
title: CONFIRM_NEW_PIN_TITLE,
subTitle: CONFIRM_NEW_PIN_SUBTITLE,
),
const SizedBox(
height: margin50,
),
Padding(
padding: const EdgeInsets.only(
left: margin50, right: margin50),
child: PinCodeField(
pinLength: 6,
onComplete: (value) {
changePinBloc.checkValidateConfirmNewPin(
newPinCode: value,
oldPinCode: widget.newCodePinValue!,
);
},
onChange: () {},
),
)
],
),
),
pinValidateSnapshot.hasData
? pinValidateDataState(pinValidateSnapshot, changePinBloc)
: const Positioned.fill(
child: SizedBox(),
),
],
);
},
),
),
);
}
}
To update the variable you should emit a new state using emit() method.
Just make sure your bloc is correct as it should inherit from Bloc object. Read flutter_bloc documentation to know how to use it.
A simple example:
class ExampleBloc extends Bloc<ExampleEvent, ExampleState> {
ExampleBloc() : super(ExampleInitial()) {
on<ExampleEvent>((event, emit) {
//Do some logic here
emit(ExampleLoaded());
});
}
}

How to sort the list of cards(according to the name) by clicking the sorting button in flutter

I have certain list of cards which are showing the user details and are unsorted. I want to sort them in ascending order according to the name of users by clicking on the sorting button.
I am doing state management so taking the help of ChangeNotifier . Here I tried the sorting functionality but getting Exception like : type 'Future' is not a subtype of type 'List'
Can you please help me figuring out where I am doing wrong? I want to plot the cards in a ordered format as per the names. Here is my code:-
patient.dart :
class Patient {
String name ;
String imgPath ;
int totalSession ;
int completedSession ;
String status ;
String dob ;
bool isActive ;
Patient(this.name, this.imgPath,this.totalSession,this.completedSession,this.status,this.dob,this.isActive);
}
patient_notifier.dart :
class PatientDataNotifier extends ChangeNotifier {
List<Patient> patient = [] ;
PatientDataNotifier(){
getPatient('All');
}
getPatient(String search) async{
final List<Patient> patients = [
Patient('Partha', 'https://images.unsplash.com/photo-1545996124-0501ebae84d0?ixid=MXwxMjA3fDB8MHxzZWFyY2h8OHx8aHVtYW58ZW58MHx8MHw%3D&ixlib=rb-1.2.1&w=1000&q=80',
8, 2, 'Pending', '10-08-2015', true),
Patient('Reenu', 'https://images.unsplash.com/photo-1544005313-94ddf0286df2?ixid=MXwxMjA3fDB8MHxzZWFyY2h8MTF8fGh1bWFufGVufDB8fDB8&ixlib=rb-1.2.1&w=1000&q=80',
8, 5, 'Cancelled', '23-12-2019', false),
Patient('Abhipsa', 'https://images.unsplash.com/photo-1554151228-14d9def656e4?ixid=MXwxMjA3fDB8MHxzZWFyY2h8NHx8aHVtYW58ZW58MHx8MHw%3D&ixlib=rb-1.2.1&w=1000&q=80',
8, 7, 'Visited', '01-02-2019', false),
Patient('Sushree', 'https://upload.wikimedia.org/wikipedia/commons/e/ec/Woman_7.jpg',
8, 4, 'Pending', '20-09-2018', true),
Patient('Arpita', 'https://cdn.pixabay.com/photo/2017/08/07/14/15/portrait-2604283__340.jpg',
8, 6, 'Visited', '28-04-2017', false),
Patient('Tanmay', 'https://cdn.pixabay.com/photo/2017/08/07/14/15/portrait-2604283__340.jpg',
8, 6, 'Visited', '28-04-2017', false),
Patient('Priyanka', 'https://cdn.pixabay.com/photo/2017/08/07/14/15/portrait-2604283__340.jpg',
8, 6, 'Visited', '28-04-2017', false)
];
if(search == 'All') {
patient.clear();
for(var i=0 ; i<patients.length ; i++){
patient.add(patients[i]);
}
}
else{
patient.clear();
List<Patient> filteredPatients = filterPatients(patients , search);
for(var i=0 ; i<filteredPatients.length ; i++){
patient.add(filteredPatients[i]);
}
}
notifyListeners();
return patients ;
}
// Logic for sorting data according to name
sortData() {
List<Patient> sortedList = getPatient("All");
sortedList.sort((a,b) => a.name.compareTo(b.name));
sortedList.forEach((patient) => print(patient.name));
notifyListeners();
}
}
adminhome_content.dart (the page containing the UI part) :
class AdminHomeContent extends StatelessWidget {
final Map<String, Color> options = {
'All': Colors.black, 'Cancelled':Colors.red,
'Pending': Colors.lightGreen, 'Visited': Colors.green[900],
};
String selectedOption = 'All';
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider<PatientDataNotifier>(
create: (context) => PatientDataNotifier(),
child: MaterialApp(
home: Scaffold(
appBar: aapBarSection('Today\'s Appointments' , Colors.blueAccent[700], context),
body: Container(
//codes for some Layouts
..............................
..........................
//code for the sorting icon
child: Container(
margin: EdgeInsets.only(right: 25.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Consumer<PatientDataNotifier>(
builder: (context, patientNotifier, _) {
return IconButton(
icon: Icon(Icons.sort),
onPressed: () {
patientNotifier.sortData();
},
);
}
)
],
),
),
Container(
child: Expanded(
child: Consumer<PatientDataNotifier>(
builder: (context, patientNotifier, _) {
return ListView.builder(
shrinkWrap: true,
itemCount: patientNotifier.patient.length,
itemBuilder: (context, index) {
return getListItem(patientNotifier.patient[index], options);
},
);
}
),
),
),
getListItem(Patient patient, options){
String status = patient.status;
return Padding(
padding: const EdgeInsets.all(9.0),
-----------------
-----------
Please help me solving it.
here is my output. I am unable to sort the cards

Question about Flutter State and retrieving variables from State vs StatefulWidget

Here's the context:
In my app, users can create a question, and all questions will be displayed on a certain page. This is done with a ListView.builder whose itemBuilder property returns a QuestionTile.
The problem:
If I create a new question, the text of the new question is (usually) displayed as the text of the previous question.
Here's a picture of me adding three questions in order, "testqn123", "testqn456", "testqn789", but all are displayed as "testqn123".
Hot restarting the app will display the correct texts for each question, but hot reloading wont work.
In my _QuestionTileState class, if I change the line responsible for displaying the text of the question on the page, from
child: Text(text)
to
child: Text(widget.text)
the issue will be resolved for good. I'm not super familiar with how hot restart/reload and state works in flutter, but can someone explain all of this?
Here is the code for QuestionTile and its corresponding State class, and the line changed is the very last line with words in it:
class QuestionTile extends StatefulWidget {
final String text;
final String roomName;
final String roomID;
final String questionID; //
QuestionTile({this.questionID, this.text, this.roomName, this.roomID});
#override
_QuestionTileState createState() => _QuestionTileState(text);
}
class _QuestionTileState extends State<QuestionTile> {
final String text;
int netVotes = 0;
bool expand = false;
bool alreadyUpvoted = false;
bool alreadyDownvoted = false;
_QuestionTileState(this.text);
void toggleExpansion() {
setState(() => expand = !expand);
}
#override
Widget build(BuildContext context) {
RoomDbService dbService = RoomDbService(widget.roomName, widget.roomID);
final user = Provider.of<User>(context);
print(widget.text + " with questionID of " + widget.questionID);
return expand
? ExpandedQuestionTile(text, netVotes, toggleExpansion)
: Card(
elevation: 10,
child: Padding(
padding: const EdgeInsets.fromLTRB(10, 7, 15, 7),
child: GestureDetector(
onTap: () => {
Navigator.pushNamed(context, "/ChatRoomPage", arguments: {
"question": widget.text,
"questionID": widget.questionID,
"roomName": widget.roomName,
"roomID": widget.roomID,
})
},
child: new Row(
// crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Column(
// the stack overflow functionality
children: <Widget>[
InkWell(
child: alreadyUpvoted
? Icon(Icons.arrow_drop_up,
color: Colors.blue[500])
: Icon(Icons.arrow_drop_up),
onTap: () {
dynamic result = dbService.upvoteQuestion(
user.uid, widget.questionID);
setState(() {
alreadyUpvoted = !alreadyUpvoted;
if (alreadyDownvoted) {
alreadyDownvoted = false;
}
});
},
),
StreamBuilder<DocumentSnapshot>(
stream: dbService.getQuestionVotes(widget.questionID),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(child: CircularProgressIndicator());
} else {
// print("Current Votes: " + "${snapshot.data.data["votes"]}");
// print("questionID: " + widget.questionID);
return Text("${snapshot.data.data["votes"]}");
}
},
),
InkWell(
child: alreadyDownvoted
? Icon(Icons.arrow_drop_down,
color: Colors.red[500])
: Icon(Icons.arrow_drop_down),
onTap: () {
dbService.downvoteQuestion(
user.uid, widget.questionID);
setState(() {
alreadyDownvoted = !alreadyDownvoted;
if (alreadyUpvoted) {
alreadyUpvoted = false;
}
});
},
),
],
),
Container(
//color: Colors.red[100],
width: 290,
child: Align(
alignment: Alignment.centerLeft,
child: Text(text)), // problem solved if changed to Text(widget.text)
),
}
}
You can wrap your UI with a Stream Builder, this will allow the UI to update every time any value changes from Firestore.
Since you are using an item builder you can wrap the widget that is placed with the item builder.
That Should update the UI

How to compare two list data in flutter (dart)

I have a grid data on my page. I want to compare these data to another list like (id 1,2,3,4,5).
GridView.builder(
itemCount: course == null ? 0 : course.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: (MediaQuery.of(context).orientation == Orientation.portrait) ? 3 : 4),
itemBuilder: (BuildContext context, int index) {
return Card(
child:InkWell(
onTap: () {
setState(() {
courseid = course[index]['id'];
coursename=course[index]['name'];
});
addCourse(course[index]['about']);
},
child:Column(
children: <Widget>[
Text((coursedata['courseid'] == course[index]['id']) ? "Added" : ""),
IconButton(
icon: index.isEven ? Icon(Icons.school) : Icon(Icons.book),
iconSize:MediaQuery.of(context).orientation == Orientation.portrait ?30 : 30,
color: index.isOdd ? Colors.amber[800]: Colors.green[800],
onPressed: (){
getcourseData();
},
),
Text(course[index]['name']),
],
),
),
);
},
),
This is another list data gets from a firebase database.
getcourseData() async {
databaseReference.collection(user.email).getDocuments().then((querySnapshot) {
querySnapshot.documents.forEach((result) {
coursedata=result.data;
});
});
}
Both the above lists are compared using data ids.
coursedata['courseid'] == course[index]['id']) ? "Added" : ""
Kindly help on how to compare data in Gride view builder. Currently, only one data show "Added" though there are other data too not showing "Added" in view.
I have created a demo. Change as per your requirement.
import 'package:flutter/material.dart';
void main() =>
runApp(MaterialApp(home: GridViewDemo()));
class GridViewDemo extends StatefulWidget {
#override
_GridViewDemoState createState() => _GridViewDemoState();
}
class _GridViewDemoState extends State<GridViewDemo> {
// already added indices numbers
List<int> alreadyAddedIndices = [3,4,5,6,7];
var courseid = 0;
var coursename = "default";
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text(("GridView Demo")),
),
body: SingleChildScrollView(
child: Column(
children: [
GridView.builder(
itemCount: 5,
shrinkWrap: true,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: (MediaQuery.of(context).orientation == Orientation.portrait) ? 3 : 4),
itemBuilder: (BuildContext context, int index) {
return Card(
child:InkWell(
onTap: () {
setState(() {
// change as per your code
courseid = index;
coursename=index.toString();
// add index in list if not available
// tapping again, remove index from list
alreadyAddedIndices.contains(index)?alreadyAddedIndices.remove(index):alreadyAddedIndices.add(index);
});
},
child:Column(
children: <Widget>[
Text((alreadyAddedIndices.contains(index)) ? "Added" : ""),
Icon(index.isEven ? Icons.school : Icons.book,
size:MediaQuery.of(context).orientation == Orientation.portrait ?30 : 30,
color: index.isOdd ? Colors.amber[800]: Colors.green[800],),
// course name text
const Text("course Name"),
],
),
),
);
},
),
],
),
),
);
}
}
Output:
Note:
This is a demo code. You can get all the added course ids in alreadyAddedIndices list. Change code as per the need.
The line,
Text((coursedata['courseid'] == course[index]['id']) ? "Added" : ""),
is only comparing one value as you are iterating over only one list. Try calling a method that returns a boolean value or a Text widget by iterating over both the lists. If the function returns false only then do you add to the list. Here is an example of a sudo code that return a Text widget:
_ComparingLists(int id) {
bool temp = false;
for (int i = 0; i < coursedata['courseid'].length; i++) {
if ((coursedata['courseid'][i] == id)) {
temp = true;
break;
} else {
temp = false;
}
}
// student is already enrolled
if (temp == true) {
return Text("Student is enrolled ...");
}
// student is not enrolled
else {
// do your operations like adding to the list here ....
return Text("No match");
}
}
You can call the method by :
_ComparingLists(course[index]['id'])
Hope that helps :)

Why do i get a RangeError, if i add something to my List?

im trying to create a new Hero Widget by klicking on my FloatingActionButton. Therefore i have created a HeroCover widget, which holds the single Hero widgets.
class HeroCover extends StatelessWidget {
final Widget callPage;
final heroTag;
final coverImageName;
final name;
HeroCover({this.callPage, this.heroTag, this.coverImageName, this.name});
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Hero(
tag: heroTag,
child: GestureDetector(
onTap: () => Navigator.push(
context, MaterialPageRoute(builder: (context) => callPage)),
child: Column(children: <Widget>[
Image(
image: new AssetImage(coverImageName),
height: 100,
width: 100,
),
Text(name),
])),
),
);
}
}
On my HeroPage i now Create those HeroCover widgets depending on the following Lists with mapping
static List<int> matrixID = [0, 1, 2];
static var heroTag = ['matrix1', 'matrix2', 'matrix3'];
static var name = ['Matrix Kitchen', 'DAAANCEFLOR', 'Bath'];
static var matrixIMG = [
'imgs/matrix1.png',
'imgs/matrix2.png',
'imgs/matrix3.png'
];
var matrixCall = [
...matrixID.map((id) {
return MatrixPageOne(
name: name[id],
matrixSize: 20,
heroTag: heroTag[id],
heroImage: matrixIMG[id],
);
}).toList(),
];
Here i map the matrixID in the BuildMethod to return HeroCover Widgets depending on matrixID's length:
body: Column(
children: [
Wrap(children: [
...matrixID.map((id) {
return HeroCover(
heroTag: heroTag[id],
callPage: matrixCall[id],
name: name[id],
coverImageName: matrixIMG[id],
);
}).toList()
] // wrap children
),
],
),
Now if i press my FloatingActionButton, i add one Element to each of the lists:
floatingActionButton: FloatingActionButton(
onPressed: () {
//startAddMatrix(context);
setState(() {
matrixID.add(matrixID.length);
name.add('new Matrix');
matrixIMG.add('imgs/matrix1.png');
heroTag.add(DateTime.now().toString());
});
},
child: Icon(Icons.add),
backgroundColor: color_3,
),
So the .map should find one more element in each list and the next HeroCover Widget should be displayed ( if i add it manually to each list there is no problem), but if i press my FloatingActionButton, this happens:
but if i tap on "Home" in my BottomNavigationBar now and back to "Devices" everything is as it should be:
i just dont understand why .add is causing an RangeError. If anyone knows whats wrong here, id be very Thankful for your help!
your matrixCall init with ...matrixID.map((id) { ,
so it have 3 values 0..2
In your floatingActionButton, did not extend matrixCall, matrixCall still only have 3 values 0..2
when use
Wrap(children: [
...matrixID.map((id) {
return HeroCover(
heroTag: heroTag[id],
callPage: matrixCall[id],
name: name[id],
coverImageName: matrixIMG[id],
);
}).toList()
matrixID have 4 values 0..3,
and matrixCall still have 3 values, matrixCall[3] do not have value.