How to get certain user data when clicking to one specific item in List View Flutter from Firebase Realtime Database? - flutter

Currently, I am working on a Flutter project which is a tricycle booking system. I am developing two mobile apps in flutter, one for the passenger, and another for the driver. The functionality that I'm having a problem is that a passenger should ask or request a driver for his/her booking. On the driver's side, the driver will be able to see the list of active passengers (these are those who requested a ride). All these rides are stored in a list called pList. When a modal popup displays all the items (passengers that request a ride) in the pList, and then the driver chose one, the passenger data that is being fetched is only the passenger who FIRST requested a ride or the first item being listed in the list, and not the one who the driver has chosen. Do you have any idea why and how will I fix this problem?
What I want to happen is when the driver clicked on passenger C, passenger C data will be fetched and not passenger A (first to request). Any help will be much appreciated.
Here is my code:
readUserInformation(BuildContext context) async
{
Object? empty = "";
var passengerListKeys = Provider.of<AppInfo>(context, listen: false).activePassengerList;
for(String eachPassengerKey in passengerListKeys)
{
FirebaseDatabase.instance.ref()
.child("All Ride Requests")
.child(eachPassengerKey)
.once()
.then((snapData)
{
if(snapData.snapshot.value != null)
{
var passengerRequestInfo = snapData.snapshot.value;
if (passengerRequestInfo.toString() == empty.toString())
{
print("Same lang");
return null;
}
else
{
empty = passengerRequestInfo;
setState(() {
pList.add(passengerRequestInfo);
});
print("pList: " + pList.toString());
}
double originLat = double.parse((snapData.snapshot.value! as Map)["origin"]["latitude"]);
double originLng = double.parse((snapData.snapshot.value! as Map)["origin"]["longitude"]);
String originAddress = (snapData.snapshot.value! as Map)["originAddress"];
double destinationLat = double.parse((snapData.snapshot.value! as Map)["destination"]["latitude"]);
double destinationLng = double.parse((snapData.snapshot.value! as Map)["destination"]["longitude"]);
String destinationAddress = (snapData.snapshot.value! as Map)["destinationAddress"];
String userName = (snapData.snapshot.value! as Map)["username"];
String userId = (snapData.snapshot.value! as Map)["id"];
// String userPhone = (snapData.snapshot.value! as Map)["phone"];
String? rideRequestId = snapData.snapshot.key;
UserRideRequestInformation userRideRequestDetails = UserRideRequestInformation();
userRideRequestDetails.originLatLng = LatLng(originLat, originLng);
userRideRequestDetails.originAddress = originAddress;
userRideRequestDetails.destinationLatLng = LatLng(destinationLat, destinationLng);
userRideRequestDetails.destinationAddress = destinationAddress;
userRideRequestDetails.userName = userName;
userRideRequestDetails.userId = userId;
// userRideRequestDetails.userPhone = userPhone;
userRideRequestDetails.rideRequestId = rideRequestId;
showDialog(
context: context,
builder: (BuildContext context) => ConfirmDialogBox(
userRideRequestDetails: userRideRequestDetails,
),
);
}
else
{
Fluttertoast.showToast(msg: "This Ride Request Id do not exist.");
}
});
}
}
This is the UI for the modal popup:
import 'package:ehatid_driver_app/new_trip_screen.dart';
import 'package:ehatid_driver_app/user_ride_request_information.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:responsive_sizer/responsive_sizer.dart';
import 'global.dart';
class ConfirmDialogBox extends StatefulWidget
{
UserRideRequestInformation? userRideRequestDetails;
ConfirmDialogBox({this.userRideRequestDetails});
#override
State<ConfirmDialogBox> createState() => _ConfirmDialogBoxState();
}
class _ConfirmDialogBoxState extends State<ConfirmDialogBox>
{
final currentFirebaseUser = FirebaseAuth.instance.currentUser!;
#override
Widget build(BuildContext context)
{
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(24),
),
backgroundColor: Colors.transparent,
elevation: 2,
child: Container(
margin: const EdgeInsets.all(8),
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.white,
),
child: ListView.builder(
itemCount: pList.length,
itemBuilder: (BuildContext context, int index)
{
return GestureDetector(
onTap: ()
{
setState(() {
chosenPassengerId = pList[index]["id"].toString();
print("Passenger Id: " + chosenPassengerId.toString());
FirebaseDatabase.instance.ref()
.child("passengers")
.child(chosenPassengerId!)
.once()
.then((snap)
{
print("Snap: " + snap.toString());
if(snap.snapshot.value != null)
{
//send notification to that specific driver
// sendNotificationToDriverNow(chosenPassengerId!);
//Display Waiting Response from a Driver UI
// showWaitingResponseFromPassengerUI();
print("Waiting for Response");
//Response from the driver
FirebaseDatabase.instance.ref()
.child("passengers")
.child(chosenPassengerId!)
.child("newRideStatus")
.set("accepted");
FirebaseDatabase.instance.ref()
.child("passengers")
.child(chosenPassengerId!)
.child("newRideStatus")
.onValue.listen((eventSnapshot)
{
//accept the ride request push notification
//(newRideStatus = accepted)
if(eventSnapshot.snapshot.value == "accepted")
{
//design and display ui for displaying driver information
rideRequest(context);
print("accepted");
}
});
}
else
{
Fluttertoast.showToast(msg: "This passenger do not exist. Try again.");
}
});
});
// Navigator.pop(context, "passengerChoosed");
},
child: Card(
color: Colors.white54,
elevation: 3,
shadowColor: Colors.green,
margin: EdgeInsets.all(8.0),
child: ListTile(
title: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Row(
children: [
Padding(
padding: const EdgeInsets.only(left: 6.0),
child: Text(
pList[index]["username"],
style: const TextStyle(
fontFamily: 'Montserrat',
fontSize: 16,
color: Color(0xFF272727),
fontWeight: FontWeight.bold,
),
),
),
Icon(
Icons.verified_rounded,
color: Color(0xFF0CBC8B),
),
],
),
SizedBox(height: 1.h,),
//icon + pickup
Row(
children: [
Image.asset(
"assets/images/origin.png",
height: 26,
width: 26,
),
const SizedBox(width: 12,),
Expanded(
child: Container(
child: Text(
pList[index]["originAddress"],
style: const TextStyle(
fontFamily: 'Montserrat',
fontSize: 14,
color: Color(0xFF272727),
),
),
),
),
],
),
SizedBox(height: 1.h,),
Row(
children: [
Image.asset(
"assets/images/destination.png",
height: 26,
width: 26,
),
const SizedBox(width: 12,),
Expanded(
child: Container(
child: Text(
pList[index]["destinationAddress"],
style: const TextStyle(
fontFamily: 'Montserrat',
fontSize: 14,
color: Color(0xFF272727),
),
),
),
),
],
),
],
),
),
),
);
},
),
),
);
}
rideRequest(BuildContext context)
{
String getRideRequestId="";
FirebaseDatabase.instance.ref()
.child("drivers")
.child(currentFirebaseUser.uid)
.child("newRideStatus")
.set(widget.userRideRequestDetails!.rideRequestId);
FirebaseDatabase.instance.ref()
.child("drivers")
.child(currentFirebaseUser.uid)
.child("newRideStatus")
.once()
.then((snap)
{
if(snap.snapshot.value != null)
{
getRideRequestId = snap.snapshot.value.toString();
}
else
{
Fluttertoast.showToast(msg: "This ride request do not exists.");
}
if(getRideRequestId == widget.userRideRequestDetails!.rideRequestId)
{
FirebaseDatabase.instance.ref()
.child("drivers")
.child(currentFirebaseUser.uid)
.child("newRideStatus")
.set("accepted");
Fluttertoast.showToast(msg: "Accepted Successfully.");
//trip started now - send driver to new tripScreen
Navigator.push(context, MaterialPageRoute(builder: (c)=> NewTripScreen(
userRideRequestDetails: widget.userRideRequestDetails,
)));
}
else
{
Fluttertoast.showToast(msg: "This Ride Request do not exists.");
}
});
}
}

Related

How Can i create a conditional questionnaire in Flutter

I am trying to build a questionnaire within an application
The idea is that the user answers questions
So every answer he gives is in one question
Accordingly he will receive the following question
For example if he answered a question with answer a
Will get one question
If he answered the same question with answer b
Will get another question later
how can i solve this
The code is attached
Thanks
import 'package:flutter/material.dart';
import 'package:gsheets/question_model.dart';
class QuizScreen extends StatefulWidget {
#override
State<QuizScreen> createState() => _QuizScreenState();
}
class _QuizScreenState extends State<QuizScreen> {
//define the datas
List<Question> questionList = getQuestions();
int currentQuestionIndex = 0;
int score = 0;
Answer? selectedAnswer;
int? nextQuestionId;
int? questionId;
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color.fromARGB(255, 5, 50, 80),
body: Container(
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 32),
child:
Column(mainAxisAlignment: MainAxisAlignment.spaceAround, children: [
const Text(
"Simple Quiz App",
style: TextStyle(
color: Colors.white,
fontSize: 24,
),
),
_questionWidget(),
_answerList(),
_nextButton(),
]),
),
);
}
_questionWidget() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Question ${currentQuestionIndex + 1}/${questionList.length.toString()}",
style: const TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 20),
Container(
alignment: Alignment.center,
width: double.infinity,
padding: const EdgeInsets.all(32),
decoration: BoxDecoration(
color: Colors.orangeAccent,
borderRadius: BorderRadius.circular(16),
),
child: Text(
questionList[currentQuestionIndex].questionText,
style: const TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
)
],
);
}
_answerList() {
return Column(
children: questionList[currentQuestionIndex]
.answerList
.map(
(e) => _answerButton(e),
)
.toList(),
);
}
Widget _answerButton(Answer answer) {
bool isSelected = answer == selectedAnswer;
return Container(
width: double.infinity,
margin: const EdgeInsets.symmetric(vertical: 8),
height: 48,
child: ElevatedButton(
child: Text(answer.answerText),
style: ElevatedButton.styleFrom(
shape: const StadiumBorder(),
primary: isSelected ? Colors.orangeAccent : Colors.white,
onPrimary: isSelected ? Colors.white : Colors.black,
),
onPressed: () {
// if (selectedAnswer == null) {
// if (answer.isCorrect) {
// score++;
// }
setState(() {
selectedAnswer = answer;
});
}
// },
),
);
}
_nextButton() {
// if(answer == )
bool isLastQuestion = false;
if (currentQuestionIndex == questionList.length - 1) {
isLastQuestion = true;
}
return Container(
width: MediaQuery.of(context).size.width * 0.5,
height: 48,
child: ElevatedButton(
child: Text(isLastQuestion ? "Submit" : "Next"),
style: ElevatedButton.styleFrom(
shape: const StadiumBorder(),
primary: Colors.blueAccent,
onPrimary: Colors.white,
),
onPressed: () {
// if(nextQuestionId == questionId)
if (isLastQuestion) {
//display score
showDialog(context: context, builder: (_) => _showScoreDialog());
} else {
//next question
setState(() {
selectedAnswer = null;
currentQuestionIndex++;
});
}
},
),
);
}
_showScoreDialog() {
bool isPassed = false;
if (score >= questionList.length * 0.6) {
//pass if 60 %
isPassed = true;
}
String title = isPassed ? "Passed " : "Failed";
return AlertDialog(
title: Text(
title + " | Score is $score",
style: TextStyle(color: isPassed ? Colors.green : Colors.redAccent),
),
content: ElevatedButton(
child: const Text("Restart"),
onPressed: () {
Navigator.pop(context);
setState(() {
currentQuestionIndex = 0;
score = 0;
selectedAnswer = null;
});
},
),
);
}
}
========================
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:gsheets/quiz.dart';
class Question {
final String questionText;
final List<Answer> answerList;
final int questionId;
Question(this.questionText, this.answerList, this.questionId);
}
class Answer {
final String answerText;
final int nextQuestionId;
// final bool selectedOption;
Answer(this.answerText, this.nextQuestionId);
}
List<Question> getQuestions() {
List<Question> list = [];
list.add(Question(
"Which school did you learn",
[
Answer("a", 3),
Answer("b", 2),
],
3,
));
list.add(Question(
"what is your age",
[
Answer("18", 3),
Answer("20", 5),
],
2,
));
list.add(Question(
"which car do you drive",
[
Answer("c", 3),
Answer("d", 2),
],
3,
));
return list;
}

How to increase quantity of same item click in Flutter (Bloc)

In HomePage.dart i am fetching an api data by using http package and flutter_bloc for the architecture. Now once i get the data and if i select any of the item in HomePage.dart then it will be added in MenuCart.dart. Now the problem i am facing is
If i click the same item more than one time then it shows duplicate card widget.
In MenuCart.dart i have added two buttons + & - and i increases the quantity to 3 then i decided to delete the item. Now i go back to previous screen and again i add that same item and if i go to MenuCart.dart then quantity displays 4.
What i am Expecting
It should not generate duplicate card instead quantity should increment.
After i delete an item and again add the same item then quantity must show 1.
In HomePage.dart i show very limited amount of code because of lengthy, but i have added the code of bloc and MenuCart.dart.
HomePage.dart
GestureDetector(
onTap: () {
BlocProvider.of<MenuCartBloc>(context)
.add(AddToCart(data[index])); // Here adding an item in MenuCart
},
child: Container(
child: Center(
child: Padding(
padding: const EdgeInsets.all(4.5)
child: Text('ADD'),
),
),
),
);
DishMenuTypesId.dart (Model)
class DishMenuTypesIdData {
String? id;
int? status;
int? quantity;
String? dishPrice;
String? photo;
DishMenuTypesIdData({
this.id,
this.status,
this.quantity = 1,
this.dishPrice,
this.photo,
});
DishMenuTypesIdData.fromJson(Map<String, dynamic> json) {
id = json['id']?.toString();
status = json['status']?.toInt();
quantity = 1;
dishPrice = json['dish_price']?.toString();
photo = json['photo']?.toString();
}
Map<String, dynamic> toJson() {
final data = <String, dynamic>{};
data['id'] = id;
data['status'] = status;
data["quantity"] = quantity;
data['dish_price'] = dishPrice;
data['photo'] = photo;
return data;
}
}
class DishMenuTypesId {
String? message;
List<DishMenuTypesIdData?>? data;
DishMenuTypesId({
this.message,
this.data,
});
DishMenuTypesId.fromJson(Map<String, dynamic> json) {
message = json['message']?.toString();
if (json['data'] != null) {
final v = json['data'];
final arr0 = <DishMenuTypesIdData>[];
v.forEach((v) {
arr0.add(DishMenuTypesIdData.fromJson(v));
});
this.data = arr0;
}
}
Map<String, dynamic> toJson() {
final data = <String, dynamic>{};
data['message'] = message;
if (this.data != null) {
final v = this.data;
final arr0 = [];
v!.forEach((v) {
arr0.add(v!.toJson());
});
data['data'] = arr0;
}
return data;
}
}
MenuCartBloc.dart
class MenuCartBloc extends Bloc<MenuCartEvent, MenuCartState> {
MenuCartBloc() : super(MenuLoaded([]));
List<DishMenuTypesIdData> cart = [];
#override
Stream<MenuCartState> mapEventToState(
MenuCartEvent event,
) async* {
yield MenuLoading();
try {
if (event is AddToCart) {
final itemExist = cart.where((e) => e.id == event.dish.id);
if (itemExist.isNotEmpty) {
print("Not Empty"); // Here i am expecting to show qty 2 if i click an item more than 1 time
} else {
print("Empty");
cart.add(event.dish);
}
} else if (event is DeleteToCart) {
cart.remove(event.dish);
} else if (event is ClearAllCart) {
cart = [];
}
yield MenuLoaded(cart);
} catch (e) {
yield MenuFailed(e.toString());
}
}
}
MenuCartEvent.dart
abstract class MenuCartEvent {}
class AddToCart extends MenuCartEvent {
late final DishMenuTypesIdData dish;
AddToCart(this.dish);
}
class DeleteToCart extends MenuCartEvent {
late final DishMenuTypesIdData dish;
DeleteToCart(this.dish);
}
class ClearAllCart extends MenuCartEvent {}
MenuCartState.dart
abstract class MenuCartState {}
class MenuLoading extends MenuCartState {}
class MenuLoaded extends MenuCartState {
final List<DishMenuTypesIdData> cart;
MenuLoaded(this.cart);
}
class MenuFailed extends MenuCartState {
final String message;
MenuFailed(this.message);
}
MenuCart.dart
Widget build(BuildContext context) {
var height = MediaQuery.of(context).size.height;
var width = MediaQuery.of(context).size.width;
var lang = translator.activeLanguageCode;
return Container(
child: Padding(
padding: const EdgeInsets.only(top: 20.0, left: 10.0, right: 10.0),
child: BlocBuilder<MenuCartBloc, MenuCartState>(
builder: (context, state) {
DishMenuTypesIdData _cart = DishMenuTypesIdData();
if (state is MenuLoading) {
return PlatformCircularProgressIndicator();
} else if (state is MenuLoaded) {
return SingleChildScrollView(
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Your Reservation Details'.tr(),
style: TextStyle(
color: TuxedoColor.blackColor,
fontSize: lang == "en" ? 14.0 : 15.0,
fontFamily: lang == "en"
? 'OpenSansBold'
: 'ArabicSemiBold'),
),
GestureDetector(
onTap: () {
BlocProvider.of<MenuCartBloc>(context)
.add(ClearAllCart());
},
child: Row(
children: [
Icon(
Icons.close,
color: TuxedoColor.redColor,
size: 15.0,
),
Text(
'Clear All'.tr(),
style: TextStyle(
color: TuxedoColor.redColor,
fontSize: 12.0,
fontFamily: lang == "en"
? 'OpenSansRegular'
: 'ArabicLight'),
),
],
),
)
],
),
SizedBox(
height: 25.0,
),
Container(
height: height * 0.3,
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.vertical,
itemCount: state.cart.length,
itemBuilder: (BuildContext context, int index) {
_cart = state.cart[index];
return Dismissible(
key: UniqueKey(),
background: Container(
alignment: AlignmentDirectional.centerEnd,
color: TuxedoColor.redBrightColor,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Icon(
Icons.delete,
color: TuxedoColor.whiteColor,
),
),
),
onDismissed: (direction) {
BlocProvider.of<MenuCartBloc>(context)
.add(DeleteToCart(_cart));
setState(() {
state.cart.removeAt(index);
});
},
direction: DismissDirection.endToStart,
child: Card(
child: Row(
children: [
Stack(
children: [
ClipRRect(
borderRadius:
BorderRadius.circular(10.0),
child: CachedNetworkImage(
imageUrl:
_cart.photo!,
placeholder: (context, url) => Center(
child:
PlatformCircularProgressIndicator()),
errorWidget:
(context, url, error) =>
Icon(Icons.error),
width: width * 0.25,
height: height * 0.1,
fit: BoxFit.fill,
),
),
Positioned(
bottom: 0,
right: 0,
child: Container(
decoration: BoxDecoration(
color: TuxedoColor.redColor,
borderRadius: lang == "en"
? BorderRadius.only(
bottomRight:
Radius.circular(
10),
)
: BorderRadius.only(
bottomLeft:
Radius.circular(
10),
)),
height: 25.0,
width: 45.0,
child: Padding(
padding: const EdgeInsets.only(
left: 3.0, right: 3.0),
child: FittedBox(
fit: BoxFit.fitWidth,
child: Text(
'${_cart.dishPrice!} \SR',
style: TextStyle(
color: TuxedoColor
.whiteColor,
fontFamily: lang == "en"
? 'OpenSansSemiBold'
: 'ArabicSemiBold'),
),
),
),
),
)
],
),
Padding(
padding:
const EdgeInsets.only(left: 10.0),
child: Column(
children: [
Container(
width: width * 0.6,
child: Row(
mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
children: [
Container(
height: 25.0,
child: Row(
children: [
MaterialButton(
color: TuxedoColor
.redColor,
shape: CircleBorder(),
onPressed: () {
setState(() {
var minus = state
.cart[index]
.quantity;
if (minus !=
null) {
minus--;
state
.cart[index]
.quantity = minus;
}
});
},
child: Text(
'-',
style: TextStyle(
color: Colors
.white,
fontSize: 20),
),
),
Text(_cart.quantity
.toString()),
MaterialButton(
color: TuxedoColor
.redColor,
shape: CircleBorder(),
onPressed: () {
setState(() {
var add = state
.cart[index]
.quantity;
if (add != null) {
add++;
state
.cart[index]
.quantity = add;
}
});
},
child: Text(
'+',
style: TextStyle(
color: Colors
.white,
fontSize: 20),
),
),
],
),
),
GestureDetector(
onTap: () {
BlocProvider.of<
MenuCartBloc>(
context)
.add(DeleteToCart(
state.cart[
index]));
},
child: Icon(
Icons.delete,
color:
TuxedoColor.redColor,
),
)
],
),
),
SizedBox(
height: 15.0,
)
],
),
),
],
),
),
);
}),
),
],
),
);
} else if (state is MenuFailed) {
return Center(child: Text(state.message));
}
return Container();
},
)),
);
}
Something like that should work:
final itemExist = cart.firstWhere((e) => e.id == event.dish.id, orElse: () => null);
if (itemExist != null) {
itemExist.quantity++;
print("Not Empty"); // Here i am expecting to show qty 2 if i click an item more than 1 time
} else {
print("Empty");
cart.add(event.dish);
}
Basically, we need to check whether the cart already has a dish with the same id or not. If the cart contains the dish with this id we increment dish quantity else we just add a dish to the cart.
Besides that, I see a potential problem with your code. Bloc to work properly requires either creating new instances of models or properly implementing of equals and hashCode. So even the code above may not work properly due to this problem. Be aware of it. You can fix it using this package.

Local camera in first video call is not working in Flutter app with Agora (using agora_rtc_engine 4.0.7)

I integrated Agora in Flutter Application with the help of agora_rtc_engine 4.0.7, but upon making a video call for the very first time the local camera view is not working. When we disconnect the call and call back again then everything works fine, the local camera view started working.
Again when we kill the application from Phone memory and rerun it then also the same problem occurs for the first time.
VideoCallingScreen.dart file
class VideoCallingScreen extends StatefulWidget {
String doctorId;
String bookingId;
VideoCallingScreen(this.doctorId, this.bookingId);
#override
_VideoCallingScreenState createState() => _VideoCallingScreenState();
}
class _VideoCallingScreenState extends State<VideoCallingScreen> {
int? _remoteUid;
RtcEngine? _engine;
bool isJoined = false,
switchCamera = true,
switchRender = true,
muteAudio = false,
muteVideo = false;
bool remoteUserMicMute = false, remoteUserVideoMute = false;
bool resizeVideo = false;
ServerHandler _serverHandler = ServerHandler();
String? token;
String? channelName;
String? channelId;
late user.Details userDetails;
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
#override
void initState() {
super.initState();
getAgoraToken().then((value) {
if (value) {
initForAgora();
} else {
_showMyDialog();
}
});
// initForAgora();
}
Future<void> _showMyDialog() async {
return showDialog<void>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
title: const Text('No Channel Found'),
content: SingleChildScrollView(
child: ListBody(
children: const <Widget>[
Text('No video channel has been created by the Doctor'),
],
),
),
actions: <Widget>[
TextButton(
child: const Text('Ok'),
onPressed: () async {
// int count = 0;
Navigator.pop(context);
Navigator.pop(_scaffoldKey.currentContext!);
},
),
],
);
},
);
}
Future<bool> getAgoraToken() async {
await Screen.keepOn(true);
var tokenBody = await _serverHandler.joinAgoraChannel(
widget.doctorId, widget.bookingId);
print('token Body from videoPage' + tokenBody.toString());
if (tokenBody['success'] == 1) {
setState(() {
token = tokenBody['channel']['access_token_patient'];
channelName = tokenBody['channel']['channel_name'];
print('**********Token Set********' + token!);
channelId = tokenBody['channel']['id'].toString();
});
return true;
} else {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(
"Unable to get Video Call Token, Please check your internet Connection and try again."),
));
return false;
}
}
Future<void> initForAgora() async {
// retrieve permissions
await [Permission.microphone, Permission.camera].request();
userDetails = await _serverHandler.getUserProfile();
//create the engine
_engine = await RtcEngine.create(appId);
await _engine?.enableVideo();
_engine?.setEventHandler(
RtcEngineEventHandler(
joinChannelSuccess: (String channel, int uid, int elapsed) async {
print("local user $uid joined");
// await _engine!.enableVideo();
},
userJoined: (int uid, int elapsed) {
print("remote user $uid joined");
setState(() {
_remoteUid = uid;
});
},
tokenPrivilegeWillExpire: (token) async {
await getAgoraToken();
await _engine?.renewToken(token);
},
userOffline: (int uid, UserOfflineReason reason) {
print("remote user $uid left channel");
// _engine!.enableVideo();
setState(() {
_remoteUid = null;
});
_userLeftTheCall();
},
userMuteVideo: (int uid, bool isMute) {
print('Audio Mutted');
setState(() {
remoteUserVideoMute = isMute;
});
},
userMuteAudio: (int uid, bool isMute) {
print('Audio Mutted');
setState(() {
remoteUserMicMute = isMute;
});
},
),
);
await getAgoraToken();
await _engine?.joinChannel(token, channelName!, null, userDetails.id!);
}
// Create UI with local view and remote view
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: _onWillPop,
child: Scaffold(
key: _scaffoldKey,
body: SafeArea(
child: Stack(
children: [
Center(
child:
resizeVideo ? _renderLocalPreview() : _renderRemoteVideo(),
),
if (remoteUserVideoMute)
BackdropFilter(
filter: ImageFilter.blur(
sigmaX: 10,
sigmaY: 10,
),
child: Padding(
padding: const EdgeInsets.only(bottom: 32),
child: Center(
child: Text(
'Doctor video Paused',
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
),
),
),
if (remoteUserMicMute)
Padding(
padding: const EdgeInsets.only(top: 32),
child: Center(
child: Text(
'Doctor Mic Muted',
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
),
),
Positioned(
top: 8,
left: 8,
child: InkWell(
//Uncomment it to unable resize
// onTap: () {
// setState(() {
// resizeVideo = !resizeVideo;
// });
// },
child: Container(
width: 100,
height: 120,
child: Stack(
children: [
ImageFiltered(
imageFilter: muteVideo
? ImageFilter.blur(sigmaX: 3.0, sigmaY: 3.0)
: ImageFilter.blur(sigmaX: 0, sigmaY: 0),
child: resizeVideo
? _renderRemoteVideo()
: _renderLocalPreview(), // Widget that is blurred
),
if (muteVideo)
Positioned(
top: 4,
left: 4,
child: Icon(
Icons.videocam_off_outlined,
color: Colors.white,
size: 32,
),
),
if (muteAudio)
Positioned(
bottom: 4,
right: 4,
child: Icon(
Icons.mic_off_outlined,
color: Colors.white,
size: 32,
),
),
],
),
),
),
),
Positioned(
bottom: 32,
right: 8,
left: 8,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
InkWell(
onTap: () async {
await Screen.keepOn(false);
await _engine?.leaveChannel();
await _serverHandler.leaveChannel(channelId!);
Navigator.pop(_scaffoldKey.currentContext!);
},
child: Container(
padding: EdgeInsets.all(16),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(50),
color: Colors.red),
child: Icon(
Icons.call_end,
color: Colors.white,
),
),
),
InkWell(
onTap: this._switchCamera,
child: Container(
padding: EdgeInsets.all(16),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(50),
color: Colors.white),
child: Icon(
Icons.flip_camera_android_rounded,
color: Colors.black87,
),
),
),
InkWell(
onTap: this._onToggleMuteVideo,
child: Container(
padding: EdgeInsets.all(16),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(50),
color: Colors.white),
child: Icon(
muteVideo
? Icons.videocam_off_outlined
: Icons.videocam_outlined,
color: Colors.black87,
),
),
),
InkWell(
onTap: this._onToggleMute,
child: Container(
padding: EdgeInsets.all(16),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(50),
color: Colors.white),
child: Icon(
muteAudio
? Icons.mic_off_outlined
: Icons.mic_none_outlined,
color: Colors.black87,
),
),
),
],
),
)
],
),
),
),
);
}
// current user video
Widget _renderLocalPreview() {
return RtcLocalView.SurfaceView();
}
// remote user video
Widget _renderRemoteVideo() {
// return RtcRemoteView.SurfaceView(uid: 70);
if (_remoteUid != null) {
return RtcRemoteView.SurfaceView(uid: _remoteUid!);
} else {
return Text(
'Please wait, doctor is joining shortly',
style: TextStyle(
color: Colors.white, fontSize: 16, fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
);
}
}
_switchCamera() {
_engine?.switchCamera().then((value) {
setState(() {
switchCamera = !switchCamera;
});
}).catchError((err) {
log('switchCamera $err');
});
}
void _onToggleMute() {
setState(() {
muteAudio = !muteAudio;
});
_engine!.muteLocalAudioStream(muteAudio);
}
void _onToggleMuteVideo() {
setState(() {
muteVideo = !muteVideo;
});
_engine!.muteLocalVideoStream(muteVideo);
}
Future<bool> _onWillPop() async {
return (await showDialog(
context: _scaffoldKey.currentContext!,
builder: (context) => new AlertDialog(
title: new Text('Are you sure?'),
content: new Text('Do you want to exit exit Video Call?'),
actions: <Widget>[
TextButton(
onPressed: () => Navigator.pop(_scaffoldKey.currentContext!),
child: new Text('No'),
),
TextButton(
onPressed: () async {
await Screen.keepOn(false);
await _serverHandler.leaveChannel(channelId!);
await _engine?.leaveChannel();
Navigator.pop(_scaffoldKey.currentContext!);
Navigator.pop(_scaffoldKey.currentContext!);
},
child: new Text('Yes'),
),
],
),
)) ??
false;
}
_userLeftTheCall() async {
return (await showDialog(
context: _scaffoldKey.currentContext!,
builder: (context) => new AlertDialog(
title: new Text('Doctor Left'),
content: new Text('Doctor left this call please join Again'),
actions: <Widget>[
TextButton(
onPressed: () async {
// await _serverHandler.leaveChannel(channelId!);
await Screen.keepOn(false);
await _engine?.leaveChannel();
Navigator.pop(_scaffoldKey.currentContext!);
Navigator.pop(_scaffoldKey.currentContext!);
// Navigator.of(context).pop(true);
},
child: new Text('Okay'),
),
],
),
)) ?? false;
}
}
Please ignore things which are not relevent. Also the log is too long to share, the log keeps on running during the entire video call.
Mobile Screenshot
Thank You

The getter 'totalCartPrice' was called on null. Receiver: null Tried calling: totalCartPrice

The app itself works well. The product is added to the cart, but when you go to the cart page, this error appears. Maybe someone came across. I looked at similar errors, but my solution did not help.
The getter 'totalCartPrice' was called on null. Receiver: null Tried calling: totalCartPrice
enter code here
import 'package:flutter/material.dart';
import 'package:food_course/scr/helpers/order.dart';
import 'package:food_course/scr/helpers/style.dart';
import 'package:food_course/scr/models/cart_item.dart';
import 'package:food_course/scr/models/products.dart';
import 'package:food_course/scr/providers/app.dart';
import 'package:food_course/scr/providers/user.dart';
import 'package:food_course/scr/widgets/custom_text.dart';
import 'package:food_course/scr/widgets/loading.dart';
import 'package:provider/provider.dart';
import 'package:uuid/uuid.dart';
class CartScreen extends StatefulWidget {
#override
_CartScreenState createState() => _CartScreenState();
}
class _CartScreenState extends State<CartScreen> {
final _key = GlobalKey<ScaffoldState>();
OrderServices _orderServices = OrderServices();
#override
Widget build(BuildContext context) {
final user = Provider.of<UserProvider>(context);
final app = Provider.of<AppProvider>(context);
return Scaffold(
key: _key,
appBar: AppBar(
iconTheme: IconThemeData(color: black),
backgroundColor: white,
elevation: 0.0,
title: CustomText(text: "Shopping Cart"),
leading: IconButton(
icon: Icon(Icons.close),
onPressed: () {
Navigator.pop(context);
}),
),
backgroundColor: white,
body: app.isLoading ? Loading() : ListView.builder(
itemCount: user.userModel.cart.length,
itemBuilder: (_, index) {
return Padding(
padding: const EdgeInsets.all(16),
child: Container(
height: 120,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: white,
boxShadow: [
BoxShadow(
color: red.withOpacity(0.2),
offset: Offset(3, 2),
blurRadius: 30)
]),
child: Row(
children: <Widget>[
ClipRRect(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(20),
topLeft: Radius.circular(20),
),
child: Image.network(
user.userModel.cart[index].image,
height: 120,
width: 140,
fit: BoxFit.fill,
),
),
SizedBox(
width: 10,
),
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
RichText(
text: TextSpan(children: [
TextSpan(
text: user.userModel.cart[index].name+ "\n",
style: TextStyle(
color: black,
fontSize: 20,
fontWeight: FontWeight.bold)),
TextSpan(
text: "\$${user.userModel.cart[index].price / 100} \n\n",
style: TextStyle(
color: black,
fontSize: 18,
fontWeight: FontWeight.w300)),
TextSpan(
text: "Quantity: ",
style: TextStyle(
color: grey,
fontSize: 16,
fontWeight: FontWeight.w400)),
TextSpan(
text: user.userModel.cart[index].quantity.toString(),
style: TextStyle(
color: primary,
fontSize: 16,
fontWeight: FontWeight.w400)),
]),
),
IconButton(
icon: Icon(
Icons.delete,
color: red,
),
onPressed: ()async{
app.changeLoading();
bool value = await user.removeFromCart(cartItem: user.userModel.cart[index]);
if(value){
user.reloadUserModel();
print("Item added to cart");
_key.currentState.showSnackBar(
SnackBar(content: Text("Removed from Cart!"))
);
app.changeLoading();
return;
}else{
print("ITEM WAS NOT REMOVED");
app.changeLoading();
}
})
],
),
)
],
),
),
);
}),
bottomNavigationBar: Container(
height: 70,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
RichText(
text: TextSpan(children: [
TextSpan(
text: "Total: ",
style: TextStyle(
color: grey,
fontSize: 22,
fontWeight: FontWeight.w400)),
TextSpan(
text: " \$${user.userModel.totalCartPrice / 100}",
style: TextStyle(
color: primary,
fontSize: 22,
fontWeight: FontWeight.normal)),
]),
),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20), color: primary),
child: FlatButton(
onPressed: () {
if(user.userModel.totalCartPrice == 0){
showDialog(
context: context,
builder: (BuildContext context) {
return Dialog(
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(20.0)), //this right here
child: Container(
height: 200,
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Your cart is emty', textAlign: TextAlign.center,),
],
),
],
),
),
),
);
});
return;
}
showDialog(
context: context,
builder: (BuildContext context) {
return Dialog(
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(20.0)), //this right here
child: Container(
height: 200,
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('You will be charged \$${user.userModel.totalCartPrice / 100} upon delivery!', textAlign: TextAlign.center,),
SizedBox(
width: 320.0,
child: RaisedButton(
onPressed: () async{
var uuid = Uuid();
String id = uuid.v4();
_orderServices.createOrder(
userId: user.user.uid,
id: id,
description: "Some random description",
status: "complete",
totalPrice: user.userModel.totalCartPrice,
cart: user.userModel.cart
);
for(CartItemModel cartItem in user.userModel.cart){
bool value = await user.removeFromCart(cartItem: cartItem);
if(value){
user.reloadUserModel();
print("Item added to cart");
_key.currentState.showSnackBar(
SnackBar(content: Text("Removed from Cart!"))
);
}else{
print("ITEM WAS NOT REMOVED");
}
}
_key.currentState.showSnackBar(
SnackBar(content: Text("Order created!"))
);
Navigator.pop(context);
},
child: Text(
"Accept",
style: TextStyle(color: Colors.white),
),
color: const Color(0xFF1BC0C5),
),
),
SizedBox(
width: 320.0,
child: RaisedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text(
"Reject",
style: TextStyle(color: Colors.white),
),
color: red
),
)
],
),
),
),
);
});
},
child: CustomText(
text: "Check out",
size: 20,
color: white,
weight: FontWeight.normal,
)),
)
],
),
),
),
);
}
}
USER.dart
import 'dart:async';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:food_course/scr/helpers/order.dart';
import 'package:food_course/scr/helpers/user.dart';
import 'package:food_course/scr/models/cart_item.dart';
import 'package:food_course/scr/models/order.dart';
import 'package:food_course/scr/models/products.dart';
import 'package:food_course/scr/models/user.dart';
import 'package:uuid/uuid.dart';
enum Status{Uninitialized, Authenticated, Authenticating, Unauthenticated}
class UserProvider with ChangeNotifier{
FirebaseAuth _auth;
FirebaseUser _user;
Status _status = Status.Uninitialized;
Firestore _firestore = Firestore.instance;
UserServices _userServicse = UserServices();
OrderServices _orderServices = OrderServices();
UserModel _userModel;
// getter
UserModel get userModel => _userModel;
Status get status => _status;
FirebaseUser get user => _user;
// public variables
List<OrderModel> orders = [];
final formkey = GlobalKey<FormState>();
TextEditingController email = TextEditingController();
TextEditingController password = TextEditingController();
TextEditingController name = TextEditingController();
UserProvider.initialize(): _auth = FirebaseAuth.instance{
_auth.onAuthStateChanged.listen(_onStateChanged);
}
Future<bool> signIn()async{
try{
_status = Status.Authenticating;
notifyListeners();
await _auth.signInWithEmailAndPassword(email: email.text.trim(), password: password.text.trim());
return true;
}catch(e){
_status = Status.Unauthenticated;
notifyListeners();
print(e.toString());
return false;
}
}
Future<bool> signUp()async{
try{
_status = Status.Authenticating;
notifyListeners();
await _auth.createUserWithEmailAndPassword(email: email.text.trim(), password: password.text.trim()).then((result){
_firestore.collection('users').document(result.user.uid).setData({
'name':name.text,
'email':email.text,
'uid':result.user.uid,
"likedFood": [],
"likedRestaurants": []
});
});
return true;
}catch(e){
_status = Status.Unauthenticated;
notifyListeners();
print(e.toString());
return false;
}
}
Future signOut()async{
_auth.signOut();
_status = Status.Unauthenticated;
notifyListeners();
return Future.delayed(Duration.zero);
}
void clearController(){
name.text = "";
password.text = "";
email.text = "";
}
Future<void> reloadUserModel()async{
_userModel = await _userServicse.getUserById(user.uid);
notifyListeners();
}
Future<void> _onStateChanged(FirebaseUser firebaseUser) async{
if(firebaseUser == null){
_status = Status.Unauthenticated;
}else{
_user = firebaseUser;
_status = Status.Authenticated;
_userModel = await _userServicse.getUserById(user.uid);
}
notifyListeners();
}
Future<bool> addToCard({ProductModel product, int quantity})async{
print("THE PRODUC IS: ${product.toString()}");
print("THE qty IS: ${quantity.toString()}");
try{
var uuid = Uuid();
String cartItemId = uuid.v4();
List cart = _userModel.cart;
// bool itemExists = false;
Map cartItem ={
"id": cartItemId,
"name": product.name,
"image": product.image,
"restaurantId": product.restaurantId,
"totalRestaurantSale": product.price * quantity,
"productId": product.id,
"price": product.price,
"quantity": quantity
};
CartItemModel item = CartItemModel.fromMap(cartItem);
// if(!itemExists){
print("CART ITEMS ARE: ${cart.toString()}");
_userServicse.addToCart(userId: _user.uid, cartItem: item);
// }
return true;
}catch(e){
print("THE ERROR ${e.toString()}");
return false;
}
}
getOrders()async{
orders = await _orderServices.getUserOrders(userId: _user.uid);
notifyListeners();
}
Future<bool> removeFromCart({CartItemModel cartItem})async{
print("THE PRODUC IS: ${cartItem.toString()}");
try{
_userServicse.removeFromCart(userId: _user.uid, cartItem: cartItem);
return true;
}catch(e){
print("THE ERROR ${e.toString()}");
return false;
}
}
}
main.dart
import 'package:flutter/material.dart';
import 'package:food_course/scr/providers/app.dart';
import 'package:food_course/scr/providers/category.dart';
import 'package:food_course/scr/providers/product.dart';
import 'package:food_course/scr/providers/restaurant.dart';
import 'package:food_course/scr/providers/user.dart';
import 'package:food_course/scr/screens/home.dart';
import 'package:food_course/scr/screens/login.dart';
import 'package:food_course/scr/screens/splash.dart';
import 'package:food_course/scr/widgets/loading.dart';
import 'package:provider/provider.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(MultiProvider(
providers: [
ChangeNotifierProvider.value(value: AppProvider()),
ChangeNotifierProvider.value(value: UserProvider.initialize()),
ChangeNotifierProvider.value(value: CategoryProvider.initialize()),
ChangeNotifierProvider.value(value: RestaurantProvider.initialize()),
ChangeNotifierProvider.value(value: ProductProvider.initialize()),
],
child: MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Food App',
theme: ThemeData(
primarySwatch: Colors.red,
),
home: ScreensController())));
}
class ScreensController extends StatelessWidget {
#override
Widget build(BuildContext context) {
final auth = Provider.of<UserProvider>(context);
switch (auth.status) {
case Status.Uninitialized:
return Splash();
case Status.Unauthenticated:
case Status.Authenticating:
return LoginScreen();
case Status.Authenticated:
return Home();
default:
return LoginScreen();
}
}
}

How display a list of data order by date?

Here is the result now :
It is much better but i Don't know why BELSHINA BOBRUISK is not centered vertically. As you can see the others team are centered vertically. FC SMOELVITCHI is centered. Strange. Too i would like display the "2020-06-01" in mobile format so if it is french mobile it will be "01-06-2020".
And another question i Don't know why my mobile app use the theme with fontfamily but not all. I have some pages with a part of data in good family font and the other part in default font, its is really strange
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'dart:async';
import 'package:flutter_app/menu_member.dart';
import 'package:flutter_app/globals.dart' as globals;
import 'package:flutter_app/appbar_draw.dart';
// Create a Form widget.
class Affiche_Matchs extends StatefulWidget {
#override
_Affiche_Matchs_State createState() {
return _Affiche_Matchs_State();
}
}
// Create a corresponding State class.
// This class holds data related to the form.
class _Affiche_Matchs_State extends State<Affiche_Matchs> {
#override
final _formKey = GlobalKey<FormState>();
List<String> radioValues = [];
Future<List<Match>> grid;
Future <List<Match>> Liste_Match_Display() async {
// SERVER LOGIN API URL
var url = 'https://www.easytrafic.fr/game_app/display_matchs.php';
// Starting Web API Call.
var response = await http.get(url,headers: {'content-type': 'application/json','accept': 'application/json','authorization': globals.token});
// Getting Server response into variable.
var jsondata = json.decode(response.body);
List<Match> Matchs = [];
var i=0;
for (var u in jsondata) {
i=i+1;
Match match = Match(u["id"],u["equipe1"],u["equipe2"],u["type_prono"],u["date_debut"],u["heure_debut"]);
Matchs.add(match);
radioValues.add("");
}
return Matchs;
}
void initState() {
grid = Liste_Match_Display();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: drawappbar(true),
drawer: new DrawerOnly(className: Affiche_Matchs()),
body:
Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child:
FutureBuilder(
future: grid,
builder: (BuildContext context, AsyncSnapshot snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting: return new Center(child: new CircularProgressIndicator(),);
default:
if(snapshot.hasError) {
return new Center(child: new Text('Error: ${snapshot.error}'),);
}
else {
List<Match> values = snapshot.data;
Match lastitem;
lastitem=values[0];
if (values.isEmpty) {
return Container(
child: Center(
child: Text("Aucun match disponible !!!")
)
);
}
else {
return Form(
key: _formKey,
child: ListView.builder(itemCount: values.length,itemBuilder: (_,index) {
bool header = lastitem.date_debut !=
values[index].date_debut;
lastitem = values[index];
return Column(
children: [
(header || index == 0)
?
Container(
height: 30,
margin: EdgeInsets.only(top:10),
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
border: Border.all(
color: Colors.blue[700],
width: 2,
),
color: Colors.blue[700]
),
child : new Text(values[index].date_debut,textAlign: TextAlign.center,style: TextStyle(fontSize: 18.0,fontWeight: FontWeight.w500,color: Colors.white),),
)// here display header
:
Container(),
Container(
margin: EdgeInsets.only(top:20,bottom:20),
child: Center(
child: Text(values[index].heure_debut),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(values[index].equipe1,style: TextStyle(fontSize:12)),
draw_grid("1", index, values[index].typeprono),
draw_grid("N", index, values[index].typeprono), //
draw_grid("2", index, values[index].typeprono), //
Text(values[index].equipe2,style: TextStyle(fontSize:12)),
]
),
]
);
}
)
);
}
};
};
}
),
),
);
}
draw_grid (String choix, int index,String type_prono) {
if (type_prono.contains(choix)) {
return new InkWell(
onTap: () {
setState(() {
if (radioValues[index] == choix) {
radioValues[index] = "";
}
else {
radioValues[index] = choix;
}
});
print(radioValues);
},
child:
Container(
height: 30.0,
width: 30.0,
margin: EdgeInsets.only(right: 2,left: 2),
child: new Center(
child: new Text(choix,
style: new TextStyle(
color:
radioValues[index] == choix ? Colors.white : Colors.red,
//fontWeight: FontWeight.bold,
fontSize: 18.0, fontWeight: FontWeight.w900)),
),
decoration: new BoxDecoration(
color: radioValues[index] == choix
? Colors.red
: Colors.white,
border: new Border.all(
width: 2.0,
color: radioValues[index] == choix
? Colors.red
: Colors.red),
borderRadius: const BorderRadius.all(const Radius.circular(5)),
),
),
);
}
else {
return Text("");
}
}
}
class Match {
final String id;
final String equipe1;
final String equipe2;
final String typeprono;
final String date_debut;
final String heure_debut;
const Match(this.id,this.equipe1, this.equipe2, this.typeprono,this.date_debut,this.heure_debut);
}
You have to sort you list base on date and then you can display by checking you have to display header or not.
Following code help you to understand more and then you can implement.
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
class DeleteWidget extends StatefulWidget {
#override
_DeleteWidgetState createState() => _DeleteWidgetState();
}
class _DeleteWidgetState extends State<DeleteWidget> {
final _formKey = GlobalKey<FormState>();
List<String> radioValues = [];
Future<List<Match>> grid;
Future<List<Match>> Liste_Match_Display() async {
// SERVER LOGIN API URL
var url = 'https://www.easytrafic.fr/game_app/display_matchs.php';
// Starting Web API Call.
var response = await http.get(url, headers: {
'content-type': 'application/json',
'accept': 'application/json',
'authorization':
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJpc3MiOjE1ODg5NTQ0NDgsImlhdCI6MTU4ODk1NDQ0OCwiZXhwIjoxNTg5MDE0NDQ4LCJkYXRhIjp7ImlkIjoiMSIsImVtYWlsIjoicGFzMzBAbmV0Y291cnJpZXIuY29tIn19.-jcyoxtkNVWWagune6EOjInjBgObyxf9gweXJrA2MxLL5fRTW1pkFSFrJOW8uYzhVpaZ4CF9A-c_m8akUq74NA '
});
// Getting Server response into variable.
var jsondata = json.decode(response.body);
List<Match> Matchs = [];
var i = 0;
for (var u in jsondata) {
i = i + 1;
Match match = Match(u["id"], u["equipe1"], u["equipe2"], u["type_prono"],
u["date_debut"], u["heure_debut"]);
Matchs.add(match);
radioValues.add("");
}
return Matchs;
}
void initState() {
grid = Liste_Match_Display();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
// appBar: drawappbar(true),
//drawer: new DrawerOnly(className: Affiche_Matchs()),
body: Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: FutureBuilder(
future: grid,
builder: (BuildContext context, AsyncSnapshot snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return new Center(
child: new CircularProgressIndicator(),
);
default:
if (snapshot.hasError) {
return new Center(
child: new Text('Error: ${snapshot.error}'),
);
} else {
List<Match> values = snapshot.data;
Match lastitem;
lastitem = values[0];
if (values.isEmpty) {
return Container(
child: Center(
child: Text("Aucun match disponible !!!")));
} else {
return Form(
key: _formKey,
child: ListView.builder(
itemCount: values.length,
itemBuilder: (_, index) {
bool header = lastitem.date_debut !=
values[index].date_debut;
lastitem = values[index];
return Column(
children: [
(header || index == 0)
? Container(
height: 30,
margin: EdgeInsets.only(top: 10),
width: MediaQuery.of(context)
.size
.width,
decoration: BoxDecoration(
border: Border.all(
color: Colors.blue[700],
width: 2,
),
color: Colors.blue[700]),
child: new Text(
values[index].date_debut,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 18.0,
fontWeight: FontWeight.w500,
color: Colors.white),
),
) // here display header
: Container(),
Text(values[index].heure_debut),
Text(values[index].equipe1),
Row(
mainAxisAlignment:
MainAxisAlignment.center,
children: [
draw_grid("1", index,
values[index].typeprono),
draw_grid("N", index,
values[index].typeprono), //
draw_grid("2", index,
values[index].typeprono), //
],
),
Text(values[index].equipe2),
// here display whole item
],
);
}));
}
}
;
}
;
}),
),
);
}
draw_grid(String choix, int index, String type_prono) {
if (type_prono.contains(choix)) {
return new InkWell(
onTap: () {
setState(() {
if (radioValues[index] == choix) {
radioValues[index] = "";
} else {
radioValues[index] = choix;
}
});
print(radioValues);
},
child: Container(
height: 40.0,
width: 40.0,
child: new Center(
child: new Text(choix,
style: new TextStyle(
color:
radioValues[index] == choix ? Colors.white : Colors.red,
//fontWeight: FontWeight.bold,
fontSize: 18.0,
fontWeight: FontWeight.w900)),
),
decoration: new BoxDecoration(
color: radioValues[index] == choix ? Colors.red : Colors.white,
border: new Border.all(
width: 2.0,
color: radioValues[index] == choix ? Colors.red : Colors.red),
borderRadius: const BorderRadius.all(const Radius.circular(5)),
),
),
);
} else {
return Text("");
}
}
}
class Match {
final String id;
final String equipe1;
final String equipe2;
final String typeprono;
final String date_debut;
final String heure_debut;
const Match(this.id, this.equipe1, this.equipe2, this.typeprono,
this.date_debut, this.heure_debut);
}