I'm facing issue with scrolling bar, the lists of data load at bottom rather than showing at top.I have made code dynamic which is loading according to conditions. I'm new flutter I have written code as from different side and still learning, If you want to give suggest me to written in better way please go ahead let me know the change where I can do.
class EventsPageState extends State<EventsPage>
with SingleTickerProviderStateMixin {
int theirGroupValue = 0;
List data = List();
String url = 'https://e19f7c9d.ngrok.io/api/events/westernaf/packages';
Future<String> makeRequest() async {
var response = await http
.get(Uri.encodeFull(url), headers: {"Accept": "application/json"});
setState(() {
var extractdata = json.decode(response.body);
data = extractdata["result"];
});
for (var i = 0; i < data.length; i++) {
var startTime = data[i]['start_date'].split('T')[0];
var endTime = data[i]['end_date'].split('T')[0];
final todayDate = DateTime.now();
final pkgStartDate = DateTime.parse(startTime);
final pkgEndDate = DateTime.parse(endTime);
final difDate = todayDate.isAfter(pkgStartDate);
final difDate2 = todayDate.isBefore(pkgEndDate);
if (difDate && difDate2 == true) {
if (data[i]['regTypeId'] == 1) {
this.theirGroupValue = 0;
} else if (data[i]['regTypeId'] == 2) {
this.theirGroupValue = 1;
} else if (data[i]['regTypeId'] == 3) {
this.theirGroupValue = 2;
} else {
this.theirGroupValue = 0;
}
}
}
}
final Map<int, Widget> logoWidgets = const <int, Widget>{
0: Text('Early Bird'),
1: Text('General'),
2: Text('Onsite'),
};
List<bool> inputs = new List<bool>();
#override
void initState() {
super.initState();
this.makeRequest();
setState(() {
for (int i = 0; i < 35; i++) {
inputs.add(false);
}
});
}
void ItemChange(bool val, int index) {
setState(() {
inputs[index] = val;
});
}
static Widget giveCenter(String ListView) {
return new Card(
// child Container(
child: Text(
"Text: $ListView",
style: TextStyle(color: Colors.blue, fontSize: 20.0),
// )
),
);
}
void _Register() {
Navigator.push(
context, new MaterialPageRoute(builder: (context) => LandingScreen()));
}
#override
Widget _listingShow(i) {
if (data[i]['regTypeId'] == 1) {
var startTime = data[i]['start_date'].split('T')[0];
var endTime = data[i]['end_date'].split('T')[0];
final todayDate = DateTime.now();
final pkgStartDate = DateTime.parse(startTime);
final pkgEndDate = DateTime.parse(endTime);
final difDate = todayDate.isAfter(pkgStartDate);
final difDate2 = todayDate.isBefore(pkgEndDate);
if (difDate && difDate2 == true) {
return new Row(
children: <Widget>[
Expanded(
child: Text(data[i]["packageName"]),
),
Expanded(
child: Text((data[i]["price"]).toString()),
),
Expanded(
child: Checkbox(
value: inputs[i],
onChanged: (bool val) {
ItemChange(val, i);
},
),
),
],
);
}
}
}
#override
Widget _listingShow2(i) {
if (data[i]['regTypeId'] == 2) {
var startTime = data[i]['start_date'].split('T')[0];
var endTime = data[i]['end_date'].split('T')[0];
final todayDate = DateTime.now();
final pkgStartDate = DateTime.parse(startTime);
final pkgEndDate = DateTime.parse(endTime);
final difDate = todayDate.isAfter(pkgStartDate);
final difDate2 = todayDate.isBefore(pkgEndDate);
if (difDate && difDate2 == true) {
return new Row(
children: <Widget>[
Expanded(
child: Text(data[i]["packageName"]),
),
Expanded(
child: Text((data[i]["price"]).toString()),
),
Expanded(
child: Checkbox(
value: inputs[i],
onChanged: (bool val) {
ItemChange(val, i);
},
),
),
],
);
}
}
}
#override
Widget _listingShow3(i) {
if (data[i]['regTypeId'] == 3) {
var startTime = data[i]['start_date'].split('T')[0];
var endTime = data[i]['end_date'].split('T')[0];
final todayDate = DateTime.now();
final pkgStartDate = DateTime.parse(startTime);
final pkgEndDate = DateTime.parse(endTime);
final difDate = todayDate.isAfter(pkgStartDate);
final difDate2 = todayDate.isBefore(pkgEndDate);
if (difDate && difDate2 == true) {
return new Row(
children: <Widget>[
Expanded(
child: Text(data[i]["packageName"]),
),
Expanded(
child: Text((data[i]["price"]).toString()),
),
Expanded(
child: Checkbox(
value: inputs[i],
onChanged: (bool val) {
ItemChange(val, i);
},
),
),
],
);
}
}
}
Widget build(BuildContext context) {
List<Widget> bodies = [
new ListView.builder(
itemCount: data.length,
itemBuilder: (BuildContext context, i) {
return ListTile(
title: _listingShow(i),
);
},
),
new ListView.builder(
itemCount: data.length,
itemBuilder: (BuildContext context, i) {
return ListTile(
title: _listingShow2(i),
);
},
),
new ListView.builder(
itemCount: data == null ? 0 : data.length,
itemBuilder: (BuildContext context, i) {
return ListTile(
title: _listingShow3(i),
);
},
),
];
return Scaffold(
body: bodies[this.theirGroupValue],
appBar: AppBar(
elevation: 2.0,
backgroundColor: Colors.white,
centerTitle: true,
title: Text(
'Select conference Package',
style: TextStyle(color: Colors.black),
),
bottom: PreferredSize(
preferredSize: Size(double.infinity, 45.0),
child: Padding(
padding: EdgeInsets.only(top: 5.0, bottom: 10.0),
child: Row(
children: <Widget>[
SizedBox(
width: 15.0,
),
Expanded(
child: CupertinoSegmentedControl(
groupValue: this.theirGroupValue,
onValueChanged: (changeFromGroupValue) {
setState(() {
theirGroupValue = this.theirGroupValue;
});
},
children: logoWidgets,
),
),
],
),
),
),
),
);
}
}
I have attached the pic above, If you want to c all code I will push all the code.If needed , all I want to c listing at the top
in bodies, you define the ListViews like this:
ListView.builder(
itemCount: data.length,
itemBuilder: (BuildContext context, i) {
return ListTile(
title: _listingShow(i),
);
},
),
And this it listingShow, which returns the widget you use as the title property of your ListView.
Widget _listingShow3(i) {
if (data[i]['regTypeId'] == 3) {
// construct and return the widget
}
}
The problem is, your ListView has always a fixed number of items which is data.length, but in your function, you only return a widget if the data matches a certain type (if (data[i]['regTypeId'] == 3)), else, you return nothing. But the ListTile is always there, it just doesn't show anything.
My suggestion is to divide data into 3 separate lists, you can see how I did it here, it's probably not optimised, you'll need to figure out a better way.
Related
i am using Flutter and Firebase to build an order app.I'm using Realtime Database and a streambuilder to fetch the data and every update and listview.builder to portray them.
When i display the data works fine but the problem is that when i am trying to expand the data in the RTDB i'm getting this error
Another exception was thrown: RangeError (index): Index out of range: index should be less than 22: 22.
I'm trying to expand the data on another page.Sorry if my question is a bit of a crap i am asking for the first time
Scaffold(
body: StreamBuilder(
stream: ref.onValue,
builder: (context, snapshot) {
if(
snapshot.hasData &&
snapshot.data != null &&
(snapshot.data! as DatabaseEvent).snapshot.children !=
null){
List<Orderlist> listorder = [];
final myorders = snapshot.data!.snapshot.children;
myorders.forEach((numoftable) {
count+=1;
String payment_state = '';
String payment_method = '';
List<Order> orders=[];
final number_of_orders = numoftable.children.length;
numoftable.children.forEach((order) {
if(order.key=='payment_state') payment_state=order.value.toString();
if(order.key=='payment_method') payment_method=order.value.toString();
List<Orderitem> orderitems = [];
final order_id = order.key.toString();
// print(order_id);
if(order_id.length<=3){
final node = order.value as Map<dynamic,dynamic>?;
String temp_pending='';
String temp_payment='';
String customer_uid='';
node!.forEach((keys,values) {
// orderitem.name = element;
if(keys!='description' && keys!='customer_uid'){
final value = values as Map<String,dynamic>;
String price='';
String description='';
String number_of_appereance='';
value.forEach((key, value) {
if(key=='price') price=value.toString();
if(key=='description') description=value;
if(key=='number of appereances') number_of_appereance = value.toString();
});
final orderitem = Orderitem(name: keys,price: price,description: description,number_of_appereance: number_of_appereance);
orderitems.add(orderitem);
}
if(keys=='description'){
temp_pending = values.toString();
}
if(keys=='customer_uid'){
customer_uid=values.toString();
}
},);
final nextorder = Order(number_of_table: int.tryParse(numoftable.key.toString()),
items: orderitems,order_ids: order_id,customer_uid: customer_uid,
pending: temp_pending,);
orders.add(nextorder);
}
});
final current_index = int.parse(numoftable.key.toString())-1;
`your text`
if(temp_length.isEmpty || count<=myorders.length){
temp_length.insert(current_index, orders.length);
}
else if(temp_length[current_index]<orders.length ){
temp_length[current_index]= orders.length;
ref.child(numoftable.key.toString()).update({'payment_state':'Not payed'});
ref.child(numoftable.key.toString()).update({'payment_method':'Cash'});
}
final nextorderlist = Orderlist(
orderlist: orders,
number_of_table: numoftable.key.toString(),
payment_state: payment_state,
payment_method: payment_method,
number_of_orders: number_of_orders);
// print(nextorder.order_ids);
listorder.add(nextorderlist);
// ref.child(numoftable.key.toString()).update({'check':'false'});
},
);
return Column(
children: [
GeneralSettings(),
Flexible(
child: GridView.builder(
shrinkWrap: true,
itemCount: listorder.length ,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
itemBuilder: (context, index) {
return _listoforders(listorder, index,);
},
),
),
],
);
}else if(snapshot.connectionState==ConnectionState.waiting){
Center(child: CircularProgressIndicator(),);
}
else if(snapshot.hasError){
return Text('Error');
}
return Text('Error');
}
),
);
}
Widget _listoforders(List<Orderlist> listoforders,int index) {
return GestureDetector(
onTap: (){
orders.clear();
listoforders[index].orderlist!.forEach((element) { orders.add(element); });
context.goNamed('Details');
},
child: Container(
color:listoforders[index].payment_state=='None' ? Colors.lightBlue : (listoforders[index].payment_state=='Not payed') ? Colors.red : Colors.green,
child: Column(
children: [
ListTile(title: Text(listoforders[index].number_of_table.toString()),
subtitle: listoforders[index].payment_state=='None' ? Icon(Icons.no_food) : listoforders[index].payment_state=='Not payed' ? Icon(Icons.money_off) : Text('Payed'),
trailing: IconButton(onPressed: () {
listoforders[index].orderlist!.forEach((element) {
setState(() {
temp_length[index]=0;
ref.child(listoforders[index].number_of_table.toString()).child(element.order_ids!).remove();
ref.child(listoforders[index].number_of_table.toString()).update({'payment_state':'None'});
ref.child(listoforders[index].number_of_table.toString()).update({'payment_method':'None'});
delete(element.customer_uid!);
});
});
}, icon: Icon(Icons.delete)),
leading: (listoforders[index].payment_method=='None' ) ? Text('No payment method') : (listoforders[index].payment_method=='With card' ) ? Icon(Icons.credit_card) : Icon(Icons.money_rounded),),
Flexible(
child: ListView.builder(
physics: ClampingScrollPhysics(),
shrinkWrap: true,
itemCount: listoforders[index].orderlist!.length,
itemBuilder: (context, current_index) {
final current_order = listoforders[index].orderlist![current_index];
return Container(
color: current_order.pending=='Unchecked' ? Colors.red : (current_order.pending=='pending') ? Colors.amber : Colors.green,
child: ListTile(
onTap: () => Navigator.push(context, MaterialPageRoute(builder: (context)=>OrderSettings(order: current_order))),
title: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(current_order.order_ids!),
],
),
subtitle: Text(current_order.pending!),
trailing: current_order.pending=='Unchecked' ? IconButton(onPressed: () => setState(() {
ref.child(current_order.number_of_table.toString()).child(current_order.order_ids!).update({"description":"pending"});
}) , icon: Icon(Icons.alarm_add)) :
current_order.pending=='pending' ? IconButton(onPressed: () => setState(() {
ref.child(current_order.number_of_table.toString()).child(current_order.order_ids!).update({"description":"Done"});
}) , icon: Icon(Icons.pending_actions)) : Icon(Icons.check),
leading: IconButton(onPressed:() {
ref.child(current_order.number_of_table.toString()).child(current_order.order_ids!).remove();
} ,
icon:Icon(Icons.delete) ,),
),
);
},),
),
],
),
),
);}
}
Future delete(String uid) async{
final doc = FirebaseFirestore.instance.collection('Customers').doc(uid);
await doc.update({'order':''});
}
I am updating the RTDB on this page
class UpdatePanel extends StatefulWidget {
String? name;
bool check;
int? tables;
UpdatePanel({super.key,this.name,required this.check, this.tables});
#override
State<UpdatePanel> createState() => _UpdatePanelState();
}
class _UpdatePanelState extends State<UpdatePanel> {
late DatabaseReference ref;
TextEditingController namecontroller = TextEditingController();
TextEditingController number_of_tables = TextEditingController();
#override
void initState() {
// TODO: implement initState
ref=FirebaseDatabase.instance.ref().child(widget.name!);
super.initState();
}
#override
Widget build(BuildContext context) {
print(widget.name);
print(widget.tables);
Size size = MediaQuery.of(context).size;
final futurefiles = FirebaseStorage.instance.ref().child('${widget.name}/');
return AlertDialog(
title: Text(widget.check? 'Update businness name':'Update tables number'),
content: Container(
height: size.height*0.3,
child: SingleChildScrollView(
child: Column(children: [
widget.check ?
Textwidget(controller: namecontroller, hinttext: 'Update name', labeltext: 'Name', icon: Icon(Icons.business_center), color: Colors.black) :
Textwidget(controller: number_of_tables, hinttext: 'Update number of tables', labeltext: 'Number of tables', icon: Icon(Icons.table_bar), color: Colors.black),
SizedBox(height: size.height*0.05,),
ElevatedButton.icon(onPressed: () {
setState(() {
DatabaseManager(displayName: widget.name).settabledata(int.parse(number_of_tables.text.trim()));
createQrcodes();
resetRTDB();
(context as Element).reassemble();
Navigator.pop(context);
});
}, icon: Icon(Icons.update), label: Text('Update'))
]),
),
),
actions: [
OutlinedButton(onPressed: () => Navigator.pop(context), child: Text('Close'))
],
);
}
void resetRTDB() async{
for(int i=widget.tables!+1;i<=int.parse(number_of_tables.text.trim());i++){
await ref.child('${i}').set({"payment_state":"None","payment_method":"None",});
}
}
Future<Uint8List> toQrImageData(String text) async {
try {
final image = await QrPainter(
data: text,
version: QrVersions.auto,
gapless: false,
color: Colors.black,
emptyColor: Colors.white,
).toImage(300);
final a = await image.toByteData(format: ImageByteFormat.png);
return a!.buffer.asUint8List();
} catch (e) {
throw e;
}
}
Future createQrcodes() async{
for(int i=widget.tables!+1;i<=int.parse(number_of_tables.text.trim());i++){
final path = '${widget.name!.trim()}/${i}';
final ref = FirebaseStorage.instance.ref().child(path);
final file = await toQrImageData(widget.name!.trim().toLowerCase()+' '+'${i}');
ref.putData(file,SettableMetadata(contentType: 'image/png'));
}
}
}
this is where your error occurs
void resetRTDB() async{
for(int i=widget.tables!+1;i<=int.parse(number_of_tables.text.trim());i++){
await ref.child('${i}').set({"payment_state":"None","payment_method":"None",});
}
after getting all the data and it tries to get new data by adding 1 in every time ,change try changing your logic here
I made a function to delete saved recording files.
The delete function works fine.
However, if it is deleted, an error
'RangeError (index): Invalid value: Not in inclusive range 0..14: 15'
will occur and it will look like the picture above.
How can I solve this?
This is the delete function.
_delete() {
widget.file[widget.index].delete(recursive: true);
setState(() {
position = new Duration();
widget.file.removeAt(widget.index);
});
}
This is my listview code.
class _AudioViewerState extends State<AudioViewer> {
var audioPath;
var directory;
List file = [];
#override
void initState() {
super.initState();
getFiles();
}
void getFiles() async {
directory = (await getExternalStorageDirectory())!.path;
setState(() {
file = Directory("$directory").listSync();
});
}
#override
Widget build(BuildContext context) {
var height = MediaQuery.of(context).size.height;
var width = MediaQuery.of(context).size.width;
return Scaffold(
appBar: AppBar(
elevation: 0,
title: Text(
"Audio List",
),
),
body: Container(
child: CustomPaint(
child: ListView.builder(
reverse: true,
itemCount: file.length,
itemBuilder: (BuildContext context, int index) {
return AudioViewerCustomTile(
text: file[index].path.split('/').last,
path: file[index].path.toString(),
height: height,
width: width,
file: file,
index: index,
);
},
),
),
),
);
}
}
This is the file with the delete function.
class DialogBuilder extends StatefulWidget {
final String path;
final int index;
final List file;
DialogBuilder({required this.path,required this.index,required this.file});
#override
_DialogBuilderState createState() => _DialogBuilderState();
}
class _DialogBuilderState extends State<DialogBuilder> {
late AudioPlayer audioPlayer;
bool _isplaying = false;
var _icon = Icons.play_arrow;
var _deleteicon = Icons.delete;
Color _color = Colors.deepOrangeAccent;
Duration position = Duration();
Duration duration = Duration(seconds: 1);
#override
Widget build(BuildContext context) {
return Container(
height: 200,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10.0),
),
child: Column(
children: <Widget>[
Container(
child: Row(
children: <Widget>[
Container(
child: IconButton(
iconSize: 100,
onPressed: () {
if (!_isplaying) {
_play();
} else {
_stop();
}
},
icon: Icon(_icon),
color: _color,
),
),
Container(
child: IconButton(
iconSize: 50,
onPressed: () {
_delete();
},
icon: Icon(_deleteicon),
),
),
]
)
),
Padding(
padding: const EdgeInsets.all(8.0),
child: LinearProgressIndicator(
backgroundColor: Colors.grey[300],
valueColor: AlwaysStoppedAnimation(Colors.deepOrangeAccent),
value: (position.inMilliseconds / duration.inMilliseconds) * 1.0,
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
_getDuration(position),
style: TextStyle(color: Colors.black),
),
Text(
_getDuration(duration),
style: TextStyle(color: Colors.black),
)
],
),
)
],
),
);
}
String _getDuration(Duration duration) {
String twoDigits(int n) {
if (n >= 10) return "$n";
return "0$n";
}
String twoDigitMinutes = twoDigits(duration.inMinutes.remainder(60));
String twoDigitSeconds = twoDigits(duration.inSeconds.remainder(60));
return "${twoDigits(duration.inHours)}:$twoDigitMinutes:$twoDigitSeconds";
}
_play() {
audioPlayer.resume();
setState(() {
_isplaying = true;
_icon = Icons.pause;
_color = Colors.blueGrey;
});
}
_stop() {
audioPlayer.release();
setState(() {
position = new Duration();
_isplaying = false;
_icon = Icons.play_arrow;
_color = Colors.deepOrangeAccent;
});
}
_delete() {
widget.file[widget.index].delete(recursive: true);
setState(() {
position = new Duration();
widget.file.removeAt(widget.index);
});
}
_stateListener(PlayerState state) {
print(" In _stateListener the state of AudioPlayer :- " +
state.toString() +
"\n");
if (state == PlayerState.COMPLETED) {
Navigator.pop(context);
_stop();
}
}
The List file = []; is an empty list, so when you try to do itemCount = file.length, it displays an error, try giving the List file; a value instead of a an empty list and im sure it will work
I've been working on a project in part of it I needed to bring a list of data and do some filtering on it, some of those filters are just working fine but I've been facing that problem where the part of getting all the data when I press the button all retrieve all the items of the list and show them into listview.builder() with different Card shapes based on grouping similar data i.e a card designed for data.type[tests] & another card designed for data.type[offers] ..etc.
So when I press all button it shows only the first 4 items inside the listview + it doesn't show data in the card design that supposed to have base on it's group filtering.
here I'm getting the data from firestore
import 'package:cloud_firestore/cloud_firestore.dart';
class Test{
final String details;
final String name;
final String price;
final String type;
Test({
this.details,
this.name,
this.price,
this.type,
});
factory Test.fromDocument(DocumentSnapshot doc){
return Test(
details: doc.data()['details'],
name: doc.data()['name'],
price: doc.data()['price'],
type: doc.data()['type'],
);
}
}
..........................
import 'package:ilab/services/User.dart';
class Services {
final _db = FirebaseFirestore.instance.collection('tests');
// test list from snapshot
List<Test> _testsListFromSnapshot(QuerySnapshot snapshot) {
return snapshot.docs.map((doc) {
return Test(
details: doc.data()['details'] ?? '',
name: doc.data()['name'] ?? '',
price: doc.data()['price'] ?? '',
type: doc.data()['type'] ?? '');
}).toList();
}
// Get tests stream
Stream<List<Test>> get Tests {
return _db.snapshots().map(_testsListFromSnapshot);
}
my component starts here
List<String> alphabets = [
'all',
'a',
'b',
'c',
'd',
... etc
]
List<Test> filteredTests = List();
List<Test> tests = List();
Color color = KWhiteColor;
int Index;
#override
void initState() {
super.initState();
filteredTests = tests;
}
here is the code of giving a card desgin based on the type of data
// return different cardshape for different group of data
Widget _card(int index) {
if (filteredTests
.where((user) => user.type.toLowerCase().contains('باقة'))
.toList()
.isNotEmpty) {
return PackageCardDesign(
packageName: filteredTests[index].name,
price: '${filteredTests[index].price} YR',
details: filteredTests[index].details.toLowerCase(),
colour: Packgecolors[index],
icon: Icons.ac_unit_outlined,
type: filteredTests[index].type,
);
} else if (filteredTests
.where((user) => user.type.toLowerCase().contains('تحليل'))
.toList()
.isNotEmpty) {
return TestCardDesign(
colour: TestOffercolors[index],
testName: filteredTests[index].name,
details: filteredTests[index].details.toLowerCase(),
price: '${filteredTests[index].price} YR',
type: filteredTests[index].type,
);
} else if (filteredTests
.where((user) => user.type.toLowerCase().contains('عرض'))
.toList()
.isNotEmpty) {
return OfferCardDesign(
colour: TestOffercolors[index],
testName: filteredTests[index].name,
// details: filteredUsers[index].details.toLowerCase(),
price: '${filteredTests[index].price} %',
// type: filteredUsers[index].type,
);
}
}
here is the code of creating and printing the top three buttons
ReusableTestChip mainThreeButtonChip(
{#required String text, String buttonName, Function onTap}) {
return ReusableTestChip(
ontap: onTap,
cardChild: Text(
text,
textAlign: TextAlign.center,
style: TextStyle(
color: selectedButton == buttonName ? KWhiteColor : KInActiveColor,
fontSize: 18.0, //25.0,
fontFamily: 'Cairo-Italic',
fontWeight: FontWeight.w600,
),
),
colour: selectedButton == buttonName ? KInActiveColor : KWhiteColor,
);
}
// print Main Three Top Button method using for loop to iterate through loop of strings
List<ReusableTestChip> printMainThreeButtonMethod() {
List<ReusableTestChip> allButtons = [];
for (int i = 0; i < buttons.length; i++) {
String button = buttons[i];
var newItem = mainThreeButtonChip(
text: button,
onTap: () {
setState(() {
selectedButton = buttons[i];
if (buttons[i] == 'تحاليل') {
// setState(() {
// _card = offerList();
// });
filteredTests = tests
.where((u) => (u.type.toLowerCase().contains('تحليل')))
.toList();
} else if (buttons[i] == 'عروض') {
filteredTests = tests
.where((u) => (u.type.toLowerCase().contains('عرض')))
.toList();
} else if (buttons[i] == 'باقات') {
filteredTests = tests
.where((u) => (u.type.toLowerCase().contains('باقة')))
.toList();
}
});
},
buttonName: buttons[i],
);
allButtons.add(newItem);
}
return allButtons;
}
here is the code of creating and printing the all button
ReusableAlphabetChip alphabetChip(
{#required String text, String char, Function onTap}) {
return ReusableAlphabetChip(
ontap: onTap,
cardChild: Text(
text,
textAlign: TextAlign.center,
style: TextStyle(
color: selectedAlphabet == char ? KInActiveColor : KSecondaryColor,
fontSize: 18.0, //25.0,
fontFamily: 'Cairo-Italic',
fontWeight: FontWeight.w600,
),
),
colour: selectedAlphabet == char ? KWhiteColor : KInActiveColor,
);
}
// print all button
List<ReusableAlphabetChip> printAlphabetMethod() {
List<ReusableAlphabetChip> chars = [];
for (int i = 0; i < alphabets.length; i++) {
String char = alphabets[i];
var newItem = alphabetChip(
text: char,
onTap: () {
setState(() {
selectedAlphabet = alphabets[i];
if (alphabets[i] == 'الكل') {
filteredTests = tests;
// _foundUsers = _allUsers;
} else {
filteredTests = tests
.where((u) => (u.name.toLowerCase().startsWith(alphabets[i])))
.toList(); //json filter first filter && firebase second filter
// _foundUsers = _allUsers.where((u) => (u["name"].toLowerCase().startsWith(alphabets[i]))).toList();
}
});
},
char: alphabets[i],
);
chars.add(newItem);
}
return chars;
}
#override
Widget build(BuildContext context) {
tests = Provider.of<List<Test>>(context);
ScrollController scrollController = ScrollController(
initialScrollOffset: 10, // or whatever offset you wish
keepScrollOffset: true,
);
return SafeArea(
child: Scaffold(
appBar: AppBar(
toolbarHeight: 100,
title: Image.asset('images/logo.jpeg',
height: 100.0, alignment: Alignment.center),
),
drawer: AppDrawer(),
body: ListView(
shrinkWrap: true,
children: [
// applogo(),
Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(height: 10.0),
Row(
// top filters
mainAxisAlignment: MainAxisAlignment.center,
children: printMainThreeButtonMethod(),
),
Container(
// get all list items
margin: EdgeInsets.symmetric(vertical: 4.0),
height: 50.0,
child: ListView(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
children: printAlphabetMethod()),
),
SizedBox(
height: 390,
child: Column(
children: [
Expanded(
child: ListView.builder(
shrinkWrap: true,
padding: EdgeInsets.all(10.0),
controller: scrollController,
scrollDirection: Axis.vertical,
itemCount: filteredUsers.length,
itemBuilder: (BuildContext context, int index) {
Index = index;
if (index < filteredTests.length) {
return Card(
child: Padding(
padding: EdgeInsets.all(10.0),
child:_card(Index)
),
);
} else {
return Center(child: CircularProgressIndicator());
}
},
// itemCount: filteredUsers.length + 1,
),
),
],
),
),
],
),
],
),
bottomNavigationBar: MyBottomBar(),
),
);
}
I hope I explained what I'm facing clearly, any help will be appreciated and thanks in advance.
I found out that the problem was in color's list. where I made a list of colors to allow ListView.builder prints Cards of data that will retrieve with different colors, it turns out that due to color's list is finite and when the ListView.builder reaches the end of it, it returns that error [RangeError (index): Invalid value: Not in inclusive range 0..3: 4], So I've made a change on my color's list so when it reaches the end of the list it start over from the beginning and printing new data using the specified colors, like this
Color selectedColour(index) {
Color c;
if (index % 4 == 0) c = Colors.cyan;
if (index % 4 == 1) c = Colors.blueGrey;
if (index % 4 == 2) c = Colors.blue;
if (index % 4 == 3) c = Color(0xFFea9999);
return c;
}
this is my previous color's list before changing it
var Paccolors = [
Colors.blue,
Colors.cyan,
Colors.blueGrey,
Colors.pink,
Colors.black45,
Colors.lightGreen,
Colors.green,
Colors.red
];
I have a flutter grid view with multiple selection.
Each time I select an item, it goes inside the SelectedList and i can see a blue tick on each element.
But each time I add a new element, I update the the list and the Consumer receive the notification, I can see the new elements but I lost all the previous selected item.
Only the GridItemCustom is impacted for the CustomExercises.
Does someone has an idea, on how to keep the previous selected elements?
it look like that once the new list is updated, i have to check if the image has been selected or not..
In the video, I select 'Superman' and then add 'Test145', then I lost the selected item 'Superman'...
Future<void> updateOnceCustomExercisesList() async {
return this._memoizer.runOnce(() async {
List<ExerciseItem> newList = await dbHelper!
.findCustomExercises(widget.status == "cooldown" ? true : false);
exerciseLoader.updateList(newList); -> does nofify ExerciseLoader Consumer
});
}
Text('Custom Exercises'),
FutureBuilder(
future: updateOnceCustomExercisesList(),
builder:
(BuildContext context, AsyncSnapshot<void> snapshot) {
if (snapshot.hasError) {
print("ERROR\n");
}
switch (snapshot.connectionState) {
case ConnectionState.done:
return Container();
default:
return buildLoadingScreen();
}
},
),
Consumer<ExerciseLoader>(
builder: (context, customExercises, child) =>
GridView.builder(
shrinkWrap: true,
physics: ScrollPhysics(),
itemCount:
customExercises.getCustomExercises().length,
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 4,
childAspectRatio: 0.56,
crossAxisSpacing: 2,
mainAxisSpacing: 2),
itemBuilder: (context, index) {
return GridItemCustom(
item: customExercises
.getCustomExercises()
.elementAt(index),
isSelected: (bool value) {
setState(() {
if (value) {
widget.selectedList.add(customExercises
.getCustomExercises()
.elementAt(index));
} else {
widget.selectedList.remove(customExercises
.getCustomExercises()
.elementAt(index));
}
});
print("$index : $value");
},
key: Key(customExercises
.getCustomExercises()
.elementAt(index)
.uniqueKey
.toString()));
}),
),
My GridCustomItem is like:
class GridItemCustom extends StatefulWidget {
final Key key;
final ExerciseItem item;
final ValueChanged<bool> isSelected;
GridItemCustom(
{required this.item, required this.isSelected, required this.key});
String get2FirstLetters(String str) {
String initial = "";
List<String> words = str.split(" ");
for (int i = 0; i < words.length; i++) {
initial += words[i].substring(0, 1);
}
return initial.toUpperCase();
}
#override
_GridItemCustomState createState() => _GridItemCustomState();
}
class _GridItemCustomState extends State<GridItemCustom> {
bool isSelected = false;
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return InkWell(
onTap: () {
setState(() {
isSelected = !isSelected;
widget.isSelected(isSelected);
});
},
child: Column(
children: <Widget>[
Stack(alignment: Alignment.bottomRight, children: <Widget>[
CircleAvatar(
backgroundColor: Colors.black.withOpacity(isSelected ? 0.9 : 0),
child: Text(widget.get2FirstLetters(widget.item.title)),
),
isSelected
? Align(
alignment: Alignment.bottomRight,
child: Padding(
padding: const EdgeInsets.all(2.0),
child: Icon(
Icons.check_circle,
color: Colors.blue,
)),
)
: Container(),
]),
SizedBox(height: 10),
Text(
widget.item.title,
style: TextStyle(
color: Colors.orange,
fontFamily: 'LibreBaskerville',
fontSize: 10),
),
//: Container()
],
),
);
}
}
Thanks for your time
I need help in this please i have a RefreshIndicator that loads a ListView when there is data in the database however I want to make the widget return Text widget 'no data' if the table empty instead of the ListView.
but the when the table is empty it error appear
_TypeError (type 'String' is not a subtype of type 'Iterable')
and that will appear in the refresh method i don't know what should i do i appreciate any help thanks in advance.
this the UI for the page
class _onlineResultTab extends State<onlineResultTab> {
List<ResultsModelClass> resultslist = new List();
List<CoursesModelClass> coursesist = new List();
ResultsModelClass resultsModelClass;
CoursesModelClass courseModelClass;
final GlobalKey<RefreshIndicatorState> refreshKey = GlobalKey<RefreshIndicatorState>();
DataApiProvider dataApiProvider = new DataApiProvider();
Widget build(BuildContext context) {
return Scaffold(
body: RefreshIndicator(
key: refreshKey,
onRefresh: refreshList,
child: _resultwidget(context),
),
);
}
fetchResultDetails() async {
final allRows = await DbHelper.mydb.getOnlineResultList();
allRows.forEach((row) => {
resultsModelClass = ResultsModelClass(
"",
row["Res_Stud_Index"],
row["Res_Stud_Name"],
row["Res_Sem"].toString(),
"",
"",
row["Res_Batch"],
row["Res_Courses"],
row["Res_Grade"],
row["Res_GPA"].toString(),
row["Res_CGPA"],
row["Res_Status"],
row["faculty_desc_e"],
row["major_desc_e"]),
resultslist.add(resultsModelClass)
});
if (this.mounted) {
setState(() {});
}
}
fetchCourse() async {
final allRows = await DbHelper.mydb.getResultcoursesList();
allRows.forEach((row) => {
courseModelClass = CoursesModelClass(
row["Res_Courses"],
row["Res_Grade"],
),
coursesist.add(courseModelClass)
});
if (this.mounted) {
setState(() {});
}
}
List<String> listHeader = ['Student Results Details'];
Widget _resultwidget(context) {
final _size = MediaQuery.of(context).size;
return resultslist.length == 0
? ListView.builder(
controller: ScrollController(),
itemCount: 1,
itemBuilder: (context, index) {
return Center(
child: Padding(
padding: EdgeInsets.only(top: _size.height * 0.4),
child: Text(
"No Result Details !",
style: TextStyle(fontSize: 20),
),
));
},
physics: AlwaysScrollableScrollPhysics(),
)
: new ListView.builder(
itemCount: listHeader.length,
itemBuilder: (context, index) {
//var _size = MediaQuery.of(context).size;
return SingleChildScrollView(
child: Center(
child: Padding(
padding: EdgeInsets.only(bottom: _size.height * 0.02),
child: Column(
children: [
Card(
elevation: 20,
margin: EdgeInsets.symmetric(
horizontal: _size.width * 0.005,
),
child: Container(
height: 50.0,
decoration: BoxDecoration(
color: Theme.of(context).backgroundColor),
child: Center(
child: Text(
'Semester ' +
resultslist[0].Res_Sem +
' Result ',
style: TextStyle(
color: Colors.white,
fontSize: 17,
fontWeight: FontWeight.bold),
),
),
),
),
],
))),
);
},
);
}
the refresh method
Future<String> refreshList() async {
refreshKey.currentState?.show(atTop: false);
//await Future.delayed(Duration(seconds: 10));
var studentIndex;
final allRows = await DbHelper.mydb.MainInfoCehck();
allRows.forEach((row) => {
row["Stud_Index"],
studentIndex = row["Stud_Index"].toString()
//print( row["Stud_Index"].toString())
});
print(studentIndex);
//void refreshResult(String studentIndex)async{
await dataApiProvider.refresh_result(studentIndex);
// }
if (this.mounted) {
setState(() {
coursesist.clear();
resultslist.clear();
fetchResultDetails();
fetchCourse();
});
}
return null;
}
Future<String> refresh_result(String studentIndex) async {
var url = main_urll + "?studentIndex=" + studentIndex.trim();
final response = await http.get(url);
List<ResultDetailsModel> ResulttDetailsListModel = [];
final resultInfo = jsonDecode(response.body)['result_info'];
DbHelper.mydb.deleteTableData("Result");
print('Result informations : ' + resultInfo.toString());
for (Map i in resultInfo) {
ResulttDetailsListModel.add(ResultDetailsModel.fromJson(i));
DbHelper.mydb.saveResultDetails(ResultDetailsModel.fromJson(i));
}
return "";
}
Please check if
resultslist == null or resultslist.isNotEmpty()
for Handling empty list