flutter search in firestore for two items - flutter

I'm developing a flight ticket booking app with flutter and I'm trying to add a search query from Firestore for the start and destination. basically the idea is for the user to choose his starting and destination location by searching and when he select his starting station it will be stored in selected item and this particular item will not be found in the destination items no longer.
can you show me how to accomplish this task?

You can implement search text by using this code:
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:trackingsystem/Director/Director_View_Job_Details.dart';
class DirectorViewJob extends StatefulWidget {
#override
_DirectorViewJobState createState() => new _DirectorViewJobState();
}
class _DirectorViewJobState extends State<DirectorViewJob> {
var jobTitle = [];
var jobDescription = [];
var jobSalary = [];
var jobExperience = [];
var jobDeadlineDate = [];
var companyName = [];
bool dataCheck = false;
bool isLoading = false;
var jobDetails;
var id;
var documnet = [];
List products = [];
var productId = [];
var deleteTitle;
void getJobs() async {
setState(() {
isLoading = true;
});
Firestore.instance
.collection("CreateJob")
.getDocuments()
.then((querySnapshot) {
querySnapshot.documents.forEach((result) {
id = result.documentID;
products.add(result.data['Job Details']);
documnet.add(id);
jobDetails = (result.data["Job Details"]);
jobTitle.add(jobDetails['title']);
jobDescription.add(jobDetails['description']);
jobSalary.add(jobDetails['salary']);
jobDeadlineDate.add(jobDetails['date']);
print("date $jobDeadlineDate");
jobExperience.add(jobDetails['Experience_Level']);
companyName.add(jobDetails['companyName']);
if (jobDetails.isNotEmpty) {
setState(() {
dataCheck = true;
});
} else {
isLoading = true;
}
});
setState(() {
isLoading = false;
});
});
}
searchJob(q) {
print(q);
print('products $products');
for (int i = 0; i < products.length; i++) {
if (products[i]['title'] == "$q") {
setState(() {
jobTitle.clear();
jobSalary.clear();
jobDescription.clear();
jobDeadlineDate.clear();
jobTitle.add(products[i]['title']);
jobDescription.add(products[i]["description"]);
jobSalary.add(products[i]['salary']);
jobDeadlineDate.add(products[i]['date']);
});
}
}
}
#override
void initState() {
getJobs();
super.initState();
}
#override
void dispose() {
// TODO: implement dispose
super.dispose();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
backgroundColor: Colors.blueGrey[600],
title: Text(
"Jobs",
style: TextStyle(fontFamily: 'Righteous'),
),
),
backgroundColor: Colors.white,
body: isLoading
? SpinKitDoubleBounce(
color: Colors.blueGrey,
)
: Center(
child: ListView(
children: dataCheck
? <Widget>[
SizedBox(
height: 20,
),
SizedBox(
height: 10,
),
Container(
child: TextField(
// controller: _searchQueryController,
autofocus: true,
decoration: InputDecoration(
labelText: "Search Job",
hintText: "Search",
prefixIcon: Icon(
Icons.search,
color: Colors.blueGrey[400],
),
fillColor: Colors.white,
border: new OutlineInputBorder(
borderRadius:
new BorderRadius.circular(25.0),
borderSide: new BorderSide(),
),
//fillColor: Colors.green
),
style: TextStyle(
color: Colors.blueGrey[300],
fontSize: 16.0),
onChanged: (query) => {searchJob(query)},
),
),
SizedBox(
height: 10,
),
Container(
decoration: BoxDecoration(
// color: Colors.lightGreen[100],
),
child: new ListView.builder(
shrinkWrap: true,
physics: BouncingScrollPhysics(),
itemCount: jobTitle?.length ?? 0,
itemBuilder: (BuildContext context, index) {
return InkWell(
splashColor: Colors.white,
onTap: () async {
Navigator.push(
context,
new MaterialPageRoute(
builder: (context) =>
DirectorJobDetails(
jobDetailName:
jobTitle[index],
jobDetailDescription:
jobDescription[
index],
jobDetailExperience:
jobExperience[
index],
jobDetailDate:
jobDeadlineDate[
index],
jobDetailSalary:
jobSalary[index],
jobDetailCompany:
companyName[index],
documentId:
documnet[index],
)),
);
},
child: new Card(
color: Colors.blueGrey[200],
elevation: 5,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(30.0),
),
child: Container(
decoration: BoxDecoration(),
child: ListTile(
leading: Icon(Icons.work,
size: 40),
title: Text(jobTitle[index],
style: TextStyle(
color: Colors.black,
fontSize: 23.0,
// fontWeight: FontWeight.bold,
fontFamily:
'Righteous',
//decoration: TextDecoration.none
)),
subtitle: Row(children: [
SizedBox(
height: 10,
),
Expanded(
child: Text(
"Salary : ${jobSalary[index]}",
style: TextStyle(
color:
Colors.black,
fontSize: 18.0,
// fontWeight: FontWeight.bold,
fontFamily:
'Righteous',
//decoration: TextDecoration.none
)),
),
Expanded(
child: Text(
"DeadLine Date : ${jobDeadlineDate[index]}",
style: TextStyle(
color:
Colors.black,
fontSize: 18.0,
// fontWeight: FontWeight.bold,
fontFamily:
'Righteous',
//decoration: TextDecoration.none
)),
)
]),
//
))));
}),
),
SizedBox(
height: 20,
)
]
: <Widget>[
Container(
padding: EdgeInsets.fromLTRB(
50.0, 100.0, 50.0, 50.0),
child: Center(
child: Text(
"No Jobs are available",
style: TextStyle(
color: Colors.black,
fontSize: 25.0,
fontWeight: FontWeight.bold,
fontFamily: 'Righteous',
//decoration: TextDecoration.none
),
),
))
]),
)),
// This trailing comma makes auto-formatting nicer for build methods.
);
}
}

You can use limit in your code Like this:
FirebaseFirestore.instance.collection('test').limit(2).get()
and you'll get only two elements

Related

List of text in one Card using ListView.builder twice and for loop?

With my current code, my list is put into separate cards. I need it to be in one. I'm using two ListView.builders and a loop. I believe that's what's causing the problem. Please tell me if I'm wrong.
Every time the user taps submit on my second TextField a new TextField appears, functionality I would like to keep one way or another.
I'm just staring out so any help if appreciated.
My end goal is to have a bullet point list but the bullet points aren't important right now.
Here's my code:
class PostNote extends StatefulWidget {
User user;
PostNote({
required this.user,
});
#override
State<PostNote> createState() => _PostNoteState();
}
class _PostNoteState extends State<PostNote> {
FirebaseFirestore firestore = FirebaseFirestore.instance;
TextEditingController titleController = TextEditingController();
final List<TextField> _textFields = [];
final List<TextEditingController> _controllers = [];
bool loading = false;
#override
void initState() {
super.initState();
_addTextField();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Color(0xFF162242),
elevation: 0,
),
body: GestureDetector(
onTap: () {
FocusScope.of(context).unfocus();
},
child: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(20),
child: Column(
children: [
Text(
"Title",
style: TextStyle(
fontSize: 25,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
SizedBox(
height: 15,
),
Container(
height: 60,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(
Radius.circular(10),
),
color: Colors.white,
),
padding: EdgeInsets.only(left: 10, right: 10),
child: TextField(
decoration: InputDecoration(
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.transparent),
),
),
textInputAction: TextInputAction.next,
style: TextStyle(
color: Color(0xFF192A4F),
fontSize: 18,
),
controller: titleController,
autofocus: true,
),
),
SizedBox(
height: 30,
),
Text(
"Notes",
style: TextStyle(
fontSize: 25,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
SizedBox(
height: 15,
),
Container(
padding: EdgeInsets.only(left: 10, right: 10),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(
Radius.circular(10),
),
color: Colors.white,
),
child: ListView.builder( // HERE
shrinkWrap: true,
itemCount: _textFields.length,
itemBuilder: (_, index) {
return _textFields[index];
},
),
),
SizedBox(
height: 50,
),
loading
? Center(
child: CircularProgressIndicator(),
)
: Container(
height: 50,
width: MediaQuery.of(context).size.width,
child: ElevatedButton(
child: Text(
"Add Note",
style: TextStyle(
fontSize: 25,
fontWeight: FontWeight.bold,
),
),
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all(Color(0xFF162242)),
shape: MaterialStateProperty.all<
RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
),
),
onPressed: () async {
for (var notesController in _controllers) // HERE {
if (titleController.text == "" ||
notesController.text.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content:
Text("All fields are required")));
} else {
setState(() {
loading = true;
});
await FirestoreServiceEdit().insertNote(
titleController.text,
notesController.text,
widget.user.uid);
CollectionReference notes =
firestore.collection('notes');
QuerySnapshot allResults = await notes.get();
allResults.docs.forEach((DocumentSnapshot result) {
print(result.data());
});
if (!mounted) return;
setState(() {
loading = false;
});
Navigator.pop(context);
}
}
}),
),
]),
),
),
),
);
}
void _addTextField() {
final notesController = TextEditingController();
_textFields.add(
TextField(
decoration: InputDecoration(
prefix: Icon(
Icons.circle,
size: 8,
color: Colors.black,
),
),
autofocus: true,
controller: notesController,
onSubmitted: (_) => setState(() => _addTextField()),
),
);
_controllers.add(notesController);
}
}
class FirestoreServiceEdit{
FirebaseFirestore firestore = FirebaseFirestore.instance;
Future insertNote(String title, String notes, String? userId,)async{
try{
await firestore.collection('notes').add({
"title":title,
"notes":notes,
"userId":userId
});
} catch (e) {}
}
}
class NoteModelEdit {
String id;
String title;
String notes;
String userId;
NoteModelEdit({
required this.id,
required this.title,
required this.notes,
required this.userId
});
factory NoteModelEdit.fromJson(DocumentSnapshot snapshot){
return NoteModelEdit(
id: snapshot.id,
title: snapshot['title'],
notes: snapshot['notes'],
userId: snapshot['userId']
);
}
}
Home screen:
body: StreamBuilder(
stream: FirebaseFirestore.instance
.collection("notes")
.where('userId', isEqualTo: user.uid)
.snapshots(),
builder: (context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
if (snapshot.data.docs.length > 0) {
return ListView.builder( // HERE
itemCount: snapshot.data.docs.length,
itemBuilder: (context, index) {
NoteModelEdit note =
NoteModelEdit.fromJson(snapshot.data.docs[index]);
return Card(
margin: EdgeInsets.only(top: 18, left: 15, right: 15),
child: Column(children: [
ListTile(
title: Center(
child: Container(
padding: EdgeInsets.only(bottom: 10),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(width: 0.5),
),
),
child: Text(
note.title,
textWidthBasis: TextWidthBasis.longestLine,
style: TextStyle(
fontSize: 40,
fontWeight: FontWeight.w600),
textAlign: TextAlign.center,
),
),
),
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => EditNoteScreen(),
));
},
),
SizedBox(
height: 15,
),
Align(
alignment: Alignment.centerLeft,
child: Text(
note.notes,
textAlign: TextAlign.left,
style: TextStyle(
fontSize: 18, fontWeight: FontWeight.w700),
),
),
SizedBox(
height: 15,
),
]),
);
});
Thank you for your time!
You will need to augment your logic to look at all the TextFields at the same time rather than one at a time and inserting a note for each.
if (titleController.text.isEmpty ||
_controllers.any((element) => element.text.isEmpty)) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content:
Text("All fields are required")));
} else {
setState(() {
loading = true;
});
}
await FirestoreServiceEdit().insertNote(
titleController.text,
_controllers.map((element) => element.text).join("\n"),
widget.user.uid);
you can do like this :
Widget listInCard() {
List testList = ["note1", "note2", "note3"];
return Card(
color: Colors.blue.shade200,
elevation: 5,
child: ListView.builder(
itemCount: testList.length,
itemBuilder: (context, index) {
return Text(testList[index]);
}),
);
}
The blue color is the Card and inside it, it is a list of notes.
You can also use Container instead of Card.

Flutter Saving button state on device

I have a search screen where users can search for a county and a list of vaccination posts in said county is shown. Some counties have many some have very few.
In the list of vaccination posts, there is a button that when pressed, the button is disabled. All is good until here, but when I re-search the same county, the button that was once disabled is no longer disabled, meaning it can be pressed again. I would like to avoid that.
I have a list of bools, "true" for each vaccination post. When button is pressed, respective index in the list is changed to "false" thus disabling the button.
Question: How can I keep the button disable? (Whether the same county is re-searched or the app is re-opened)
import 'package:colour/colour.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart';
import 'dart:async';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
// import 'package:shared_preferences/shared_preferences.dart';
class VaccineCenterList extends StatefulWidget {
const VaccineCenterList({key}) : super(key: key);
static const String idScreen = "VaccineCenterList";
#override
_VaccineCenterListState createState() => _VaccineCenterListState();
}
class _VaccineCenterListState extends State<VaccineCenterList> {
TextEditingController hospitalCountyEditingController =
TextEditingController();
final databaseReference = FirebaseDatabase.instance.reference();
final firestoreInstance = FirebaseFirestore.instance;
FirebaseAuth auth = FirebaseAuth.instance;
List<Hospitals> driverList = [];
List<bool> buttonPressed = [];
// Map<String, List> buttonPressed = {};
buttonControls(numOfLocations) {
print(numOfLocations);
int checker = 0;
if (numOfLocations > buttonPressed.length) {
try {
while (numOfLocations >= checker) {
buttonPressed.add(true);
checker = checker + 1;
}
} catch (e) {
print("$e");
}
} else {}
print(buttonPressed);
}
#override
void initState() {
super.initState();
print("I'm in the vaccine list search screen");
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[100],
appBar: AppBar(
backgroundColor: Colors.grey[100],
centerTitle: true,
elevation: 0,
iconTheme: const IconThemeData(
color: Colors.black,
),
title: Text(
"Pamoja",
style: GoogleFonts.lexendMega(
fontWeight: FontWeight.bold,
color: Colors.black,
fontSize: 35,
),
),
),
body: GestureDetector(
onTap: () {
FocusScope.of(context).requestFocus(FocusNode());
},
child: SingleChildScrollView(
child: Column(
children: [
Container(
// textfield
padding: const EdgeInsets.all(8.0),
child: TextField(
controller: hospitalCountyEditingController,
keyboardType: TextInputType.text,
textCapitalization: TextCapitalization.words,
decoration: InputDecoration(
border: const OutlineInputBorder(
borderSide: BorderSide(
color: Colors.black,
style: BorderStyle.solid,
width: 1,
),
),
labelText: "Search County",
labelStyle: const TextStyle(
fontSize: 14.0,
color: Colors.blueGrey,
),
hintStyle: GoogleFonts.lexendMega(
color: Colors.grey,
fontSize: 10,
),
),
style: GoogleFonts.lexendMega(
fontSize: 14,
color: Colors.black,
),
),
),
ElevatedButton(
// search button
onPressed: () {
setState(() {
FocusScope.of(context).requestFocus(
FocusNode(),
);
driverList.clear();
if (hospitalCountyEditingController.text == "" ||
hospitalCountyEditingController.text == " ") {
isTrueOrFalse = "False";
} else {
isTrueOrFalse = "True";
}
});
getHospitalDetails();
},
child: Text(
"Search",
style: GoogleFonts.lexendMega(
fontWeight: FontWeight.bold,
),
),
),
SingleChildScrollView(
child: Column(
children: [
SizedBox(
height: MediaQuery.of(context).size.height,
// height: 50,
// color: Colors.black,
child: Padding(
padding: const EdgeInsets.only(
right: 12.0,
left: 12.0,
bottom: 12.0,
),
child: driverList.isEmpty
? Center(
// child: CircularProgressIndicator(),
child: (isTrueOrFalse == "True")
? const CircularProgressIndicator()
: Column(
mainAxisAlignment:
MainAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
"Search for one of the counties below",
style:
GoogleFonts.lexendMega()),
),
Text(
"Nairobi, Baringo, Busia, Bomet, Bungoma, Elgeyo Marakwet, Embu, Garissa, Homa Bay, Isiolo, Kajiado, Kakamega, Kericho, Kiambu, Kilifi, Kirinyaga, Kisii, Kisumu, Kitui, Kwale, Laikipia, Lamu, Machakos, Makueni, Mandera, Marsabit, Meru, Migori, Mombasa, Muranga, Nakuru, Nandi, Narok, Nyamira, Nyandarua, Nyeri, Samburu, Siaya County, Taita Taveta, Tana River County, Tharaka Nithi, Trans Nzoia, Turkana, Uasin Gishu, Vihiga, Wajir, West Pokot",
textAlign: TextAlign.center,
style: GoogleFonts.lexendMega(
fontWeight: FontWeight.bold,
),
),
],
),
)
: ListView.builder(
itemCount: driverList.length,
itemBuilder: (context, index) {
final Hospitals hospitals = driverList[index];
final String hospitalLocaiton =
hospitals.location;
final String hospitalPhone = hospitals.phone;
final String hospitalName = hospitals.name;
positiveCount = hospitals.positiveCount;
negativeCount = hospitals.negativeCount;
final int setpercentage =
calculatePositivePercentage(
positiveCount, negativeCount);
buttonControls(driverList.length);
return Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
elevation: 0,
child: ExpansionTile(
title: Text(
hospitalName.toUpperCase(),
style: GoogleFonts.lexendMega(),
textAlign: TextAlign.center,
),
children: [
Column(
children: [
Container(
child: (hospitalPhone
.isNotEmpty)
? ElevatedButton(
onPressed: () {
Clipboard.setData(
ClipboardData(
text:
hospitalPhone,
),
);
ScaffoldMessenger.of(
context)
.showSnackBar(
const SnackBar(
backgroundColor:
Colors.green,
content: Text(
"Number Copied",
textAlign:
TextAlign
.center,
),
),
);
},
child: Text(
hospitalPhone,
textAlign:
TextAlign.center,
style: GoogleFonts
.lexendMega(
fontSize: 13),
),
style: ElevatedButton
.styleFrom(
elevation: 0,
),
)
: const Text(""),
),
const SizedBox(
height: 5,
),
hospitalLocaiton.isNotEmpty
? Container(
padding:
const EdgeInsets.all(
8),
decoration: BoxDecoration(
border: Border.all(
color: Colors.black,
),
borderRadius:
BorderRadius
.circular(10),
),
child: Text(
hospitalLocaiton,
textAlign:
TextAlign.center,
style: GoogleFonts
.lexendMega(
fontSize: 12,
),
),
)
: Text(
hospitalLocaiton,
textAlign:
TextAlign.center,
style: GoogleFonts
.lexendMega(
fontSize: 12,
),
),
const SizedBox(
height: 10,
),
Text(
"$setpercentage% (percent) of voters say this hospital administer vaccines.",
textAlign: TextAlign.center,
style: GoogleFonts.lexendMega(
fontWeight: FontWeight.bold,
fontSize: 12,
color: Colors.deepPurple[400],
),
),
const SizedBox(
height: 10,
),
const Divider(
// thickness: 1,
indent: 20,
endIndent: 20,
color: Colors.black87,
),
const SizedBox(
height: 10,
),
Text(
"Does this Hospital administer Vaccines?\n(To help the public, please vote only if you know.)",
textAlign: TextAlign.center,
style: GoogleFonts.lexendMega(
fontSize: 12,
fontWeight: FontWeight.bold,
),
),
Column(
children: [
Row(
mainAxisAlignment:
MainAxisAlignment
.spaceEvenly,
children: [
ElevatedButton(
onPressed:
buttonPressed[index]
? () {
positiveIncrement(
hospitalName,
index);
buttonPressed[
index] =
false;
ScaffoldMessenger.of(
context)
.showSnackBar(
const SnackBar(
backgroundColor:
Colors.redAccent,
content:
Text(
"Voted",
textAlign:
TextAlign.center,
),
),
);
}
: null,
child: Text(
"Yes",
style: GoogleFonts
.lexendMega(),
),
style: ElevatedButton
.styleFrom(
primary:
Colour("#87D68D"),
),
),
ElevatedButton(
onPressed:
buttonPressed[index]
? () {
negativeIncrement(
hospitalName,
index);
buttonPressed[
index] =
false;
ScaffoldMessenger.of(
context)
.showSnackBar(
const SnackBar(
backgroundColor:
Colors.redAccent,
content:
Text(
"Voted",
textAlign:
TextAlign.center,
),
),
);
}
: null,
child: Text(
"No",
style: GoogleFonts
.lexendMega(),
),
style: ElevatedButton
.styleFrom(
primary:
Colour("#E3655B"),
),
),
],
),
const SizedBox(
height: 10,
),
Text(
"1 - To vote, tap once\n2 - To Undo vote, tap and hold",
style:
GoogleFonts.lexendMega(
fontSize: 12,
),
textAlign: TextAlign.start,
),
const SizedBox(
height: 10,
),
],
),
],
),
],
),
),
);
},
),
),
),
// SizedBox(height: 40),
],
),
),
],
),
),
),
);
}
}
class Hospitals {
final String name;
final String phone;
final String location;
// final String county;
final int positiveCount;
final int negativeCount;
// final int intPercentage;
// final int totalVotes;
Hospitals({
required this.name,
required this.phone,
required this.location,
// required this.county,
required this.positiveCount,
required this.negativeCount,
// required this.intPercentage,
// required this.totalVotes,
});
static Hospitals fromJson(Map<String, dynamic> json) {
return Hospitals(
name: json['HospitalName'],
phone: json['HospitalPhone'],
// county: json['county'],
location: json['HospitalAddres'],
positiveCount: json['poitiveCount'],
negativeCount: json['negativeCount'],
// intPercentage: json['intPercentage'],
// totalVotes: json['totalVotes']
);
}
}
I did that this way: use the provider to set value, make boolean value
late bool isMyButtonEnabled;
//in initState
setState(() {
isMyButtonEnabled=
myProvider.checkIfButtonShouldBeEnabled(widget.Id);
}
//in build
ElevatedButton(
child: Text('SUBMIT'),
onPressed: !isMyButtonEnabled
? null
: () async => {
//some code
}
this way your boolean will be saved and available everywhere in the app using the Provider package (there are other even more advanced analogs of Provider there that can be used as well)

Flutter - Disable a button, not all buttons

I am getting a list from Firebase. The list loads as expected, However I have two issues.
1 - When the button in one item from the list is disabled, all the buttons in the other items also get disabled. I don't want this to happen. How can I get passed this?
2 - I am getting "positiveCount" and "negativeCount" from firebase RTDB. I want to get total (positiveCount + negativeCount) and then calculate the percentage of "positiveCount". (Example: positiveCount = 2, negativeCount = 2, percentage of positiveCount should be 50 percent). The problem is, ıf there is only one item that is loaded, it works perfectly. If there is more than one item loaded, I get an error.
Exception:
Exception has occurred.
UnsupportedError (Unsupported operation: Infinity or NaN toInt)
My Code:
import 'package:colour/colour.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart';
import 'dart:async';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
// import 'package:shared_preferences/shared_preferences.dart';
class VaccineCenterList extends StatefulWidget {
const VaccineCenterList({key}) : super(key: key);
static const String idScreen = "VaccineCenterList";
#override
_VaccineCenterListState createState() => _VaccineCenterListState();
}
class _VaccineCenterListState extends State<VaccineCenterList> {
final databaseReference = FirebaseDatabase.instance.reference();
final firestoreInstance = FirebaseFirestore.instance;
FirebaseAuth auth = FirebaseAuth.instance;
List<Hospitals> driverList = [];
late String isTrueOrFalse = "False";
// // double percentageInt = 0.0;
int totalVotes = 0;
// int percentage = 0;
int positiveCount = 0;
int negativeCount = 0;
bool buttonPressed = true;
TextEditingController hospitalCountyEditingController =
TextEditingController();
Future<List<Hospitals>> getHospitalDetails() async {
try {
if ((hospitalCountyEditingController.text != "") &&
(hospitalCountyEditingController.text != " ")) {
databaseReference
.child("Hospitals")
.child(hospitalCountyEditingController.text)
.onValue
.listen(
(event) {
setState(
() {
var value = event.snapshot.value;
driverList = Map.from(value)
.values
.map((e) => Hospitals.fromJson(Map.from(e)))
.toList();
},
);
},
);
} else {}
} catch (e) {
}
return driverList;
}
calculatePositivePercentage(
positiveCount, negativeCount) {
// this method gets the number of "yes" and "no" votes. Then calculates the
// percentage of people who voted "yes".
// total = positiveCount + negativeCount;
// percentage = (positiveCount * 100) ~/ total;
totalVotes = positiveCount + negativeCount;
int percentage = positiveCount * 100;
double votePercentage = percentage / totalVotes;
return votePercentage;
}
#override
void initState() {
super.initState();
print("I'm in the vaccine list search screen");
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[100],
appBar: AppBar(
backgroundColor: Colors.grey[100],
centerTitle: true,
elevation: 0,
iconTheme: const IconThemeData(
color: Colors.black,
),
title: Text(
"Pamoja",
style: GoogleFonts.lexendMega(
fontWeight: FontWeight.bold,
color: Colors.black,
fontSize: 35,
),
),
),
body: GestureDetector(
onTap: () {
FocusScope.of(context).requestFocus(FocusNode());
},
child: SingleChildScrollView(
child: Column(
children: [
Container(
padding: const EdgeInsets.all(8.0),
child: TextField(
controller: hospitalCountyEditingController,
keyboardType: TextInputType.text,
textCapitalization: TextCapitalization.words,
decoration: InputDecoration(
border: const OutlineInputBorder(
borderSide: BorderSide(
color: Colors.black,
style: BorderStyle.solid,
width: 1,
),
),
labelText: "Search County",
labelStyle: const TextStyle(
fontSize: 14.0,
color: Colors.blueGrey,
),
hintStyle: GoogleFonts.lexendMega(
color: Colors.grey,
fontSize: 10,
),
),
style: GoogleFonts.lexendMega(
fontSize: 14,
color: Colors.black,
),
),
),
ElevatedButton(
onPressed: () {
buttonPressed = false;
setState(() {
FocusScope.of(context).requestFocus(
FocusNode(),
);
driverList.clear();
if (hospitalCountyEditingController.text == "" ||
hospitalCountyEditingController.text == " ") {
isTrueOrFalse = "False";
} else {
isTrueOrFalse = "True";
}
});
getHospitalDetails();
},
child: Text(
"Search",
style: GoogleFonts.lexendMega(
fontWeight: FontWeight.bold,
),
),
),
SizedBox(
height: MediaQuery.of(context).size.height,
// color: Colors.black,
child: Padding(
padding: const EdgeInsets.all(12.0),
child: driverList.isEmpty
? Center(
// child: CircularProgressIndicator(),
child: (isTrueOrFalse == "True")
? const CircularProgressIndicator()
: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
"Search for one of the counties below",
style: GoogleFonts.lexendMega()),
),
Text(
"Nairobi, Baringo, Busia, Bomet, Bungoma, Elgeyo Marakwet, Embu, Garissa, Homa Bay, Isiolo, Kajiado, Kakamega, Kericho, Kiambu, Kilifi, Kirinyaga, Kisii, Kisumu, Kitui, Kwale, Laikipia, Lamu, Machakos, Makueni, Mandera, Marsabit, Meru, Migori, Mombasa, Muranga, Nakuru, Nandi, Narok, Nyamira, Nyandarua, Nyeri, Samburu, Siaya County, Taita Taveta, Tana River County, Tharaka Nithi, Trans Nzoia, Turkana, Uasin Gishu, Vihiga, Wajir, West Pokot",
textAlign: TextAlign.center,
style: GoogleFonts.lexendMega(
fontWeight: FontWeight.bold,
),
),
],
),
)
: ListView.builder(
itemCount: driverList.length,
itemBuilder: (context, int index) {
final Hospitals hospitals = driverList[index];
final String hospitalLocaiton = hospitals.location;
final String hospitalPhone = hospitals.phone;
// final int totalVotes = hospitals.totalVotes;
final String hospitalName = hospitals.name;
// final String county = hospitals.county;
positiveCount = hospitals.positiveCount;
negativeCount = hospitals.negativeCount;
// final int percentage = positiveCount * 100;
// final double percentageInt =
// percentage / totalVotes;
// ignore: unused_local_variable
final double setpercentage =
calculatePositivePercentage(positiveCount, negativeCount);
**final percentageInt = setpercentage.toInt();**
return Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
elevation: 0,
child: ExpansionTile(
title: Text(
hospitalName.toUpperCase(),
style: GoogleFonts.lexendMega(),
textAlign: TextAlign.center,
),
children: [
Column(
children: [
Container(
child: (hospitalPhone.isNotEmpty)
? ElevatedButton(
onPressed: () {
Clipboard.setData(
ClipboardData(
text: hospitalPhone,
),
);
ScaffoldMessenger.of(
context)
.showSnackBar(
const SnackBar(
backgroundColor:
Colors.green,
content: Text(
"Number Copied",
textAlign:
TextAlign.center,
),
),
);
},
child: Text(
hospitalPhone,
textAlign: TextAlign.center,
style:
GoogleFonts.lexendMega(
fontSize: 13),
),
style:
ElevatedButton.styleFrom(
elevation: 0,
),
)
: const Text(""),
),
const SizedBox(
height: 5,
),
hospitalLocaiton.isNotEmpty
? Container(
padding:
const EdgeInsets.all(8),
decoration: BoxDecoration(
border: Border.all(
color: Colors.black,
),
borderRadius:
BorderRadius.circular(10),
),
child: Text(
hospitalLocaiton,
textAlign: TextAlign.center,
style: GoogleFonts.lexendMega(
fontSize: 12,
),
),
)
: Text(
hospitalLocaiton,
textAlign: TextAlign.center,
style: GoogleFonts.lexendMega(
fontSize: 12,
),
),
const SizedBox(
height: 10,
),
Text(
"$percentageInt% (percent) of voters say this hospital administer vaccines.",
textAlign: TextAlign.center,
style: GoogleFonts.lexendMega(
fontWeight: FontWeight.bold,
fontSize: 12,
color: Colors.deepPurple[400],
),
),
const SizedBox(
height: 10,
),
const Divider(
// thickness: 1,
indent: 20,
endIndent: 20,
color: Colors.black87,
),
const SizedBox(
height: 10,
),
Text(
"Does this Hospital administer Vaccines?\n(To help the public, please vote only if you know.)",
textAlign: TextAlign.center,
style: GoogleFonts.lexendMega(
fontSize: 12,
fontWeight: FontWeight.bold,
),
),
// Container(
// child: (positiveCount == 0)
// ? Text("Votes: $positiveCount")
// : Text("Votes: " +
// positiveCount.toString()),
// ),
Column(
children: [
Row(
mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
onLongPress: buttonPressed
? () {
buttonPressed = false;
ScaffoldMessenger.of(
context)
.showSnackBar(
const SnackBar(
backgroundColor:
Colors
.purpleAccent,
content: Text(
"Vote Removed",
textAlign:
TextAlign
.center,
),
),
);
undoPositiveIncrement(
hospitalName);
}
: null,
onPressed: buttonPressed ? () {
ScaffoldMessenger.of(
context)
.showSnackBar(
const SnackBar(
backgroundColor:
Colors.greenAccent,
content: Text(
"Voted Yes",
textAlign:
TextAlign.center,
),
),
);
positiveIncrement(
hospitalName);
} : null,
child: Text(
"Yes - $positiveCount",
style: GoogleFonts
.lexendMega(),
),
style:
ElevatedButton.styleFrom(
primary: Colour("#87D68D"),
),
),
ElevatedButton(
onLongPress: buttonPressed ? () {
ScaffoldMessenger.of(
context)
.showSnackBar(
const SnackBar(
backgroundColor:
Colors.purpleAccent,
content: Text(
"Vote Removed",
textAlign:
TextAlign.center,
),
),
);
undoNegativeIncrement(
hospitalName);
} : null,
onPressed: buttonPressed ? () {
ScaffoldMessenger.of(
context)
.showSnackBar(
const SnackBar(
backgroundColor:
Colors.redAccent,
content: Text(
"Voted",
textAlign:
TextAlign.center,
),
),
);
negativeIncrement(
hospitalName);
} : null,
child: Text(
"No - $negativeCount",
style: GoogleFonts
.lexendMega(),
),
style:
ElevatedButton.styleFrom(
primary: Colour("#E3655B"),
),
),
],
),
const SizedBox(
height: 10,
),
Text(
"Total No. of Votes: ",
style: GoogleFonts.lexendMega(
fontSize: 12),
),
const SizedBox(
height: 10,
),
Text(
"1 - To vote, tap once\n2 - To Undo vote, tap and hold",
style: GoogleFonts.lexendMega(
fontSize: 12,
),
textAlign: TextAlign.start,
),
const SizedBox(
height: 10,
),
],
),
],
),
],
),
),
);
},
),
),
),
],
),
),
),
);
}
}
class Hospitals {
final String name;
final String phone;
final String location;
// final String county;
final int positiveCount;
final int negativeCount;
// final int intPercentage;
// final int totalVotes;
Hospitals({
required this.name,
required this.phone,
required this.location,
// required this.county,
required this.positiveCount,
required this.negativeCount,
// required this.intPercentage,
// required this.totalVotes,
});
static Hospitals fromJson(Map<String, dynamic> json) {
return Hospitals(
name: json['HospitalName'],
phone: json['HospitalPhone'],
// county: json['county'],
location: json['HospitalAddres'],
positiveCount: json['poitiveCount'],
negativeCount: json['negativeCount'],
// intPercentage: json['intPercentage'],
// totalVotes: json['totalVotes']
);
}
}
Solution for issue 2:
calculatePositivePercentage(positiveCount, negativeCount) {
// this method gets the number of "yes" and "no" votes. Then calculates the
// percentage of people who voted "yes".
double votePercentage = 0;
if (positiveCount == 0 && negativeCount == 0) {
try {
return votePercentage.toInt();
} catch (e) {
print(e);
}
} else {
try {
totalVotes = positiveCount + negativeCount;
int percentage = positiveCount * 100;
votePercentage = percentage / totalVotes;
return votePercentage.toInt();
} catch (e) {
print(e);
}
}
}
To prevent all buttons to be disabled instead of
bool buttonPressed = true;
use
List<bool> buttonPressed = [true];
and your 2nd error is because may be you are not getting an int value from the response try
int.parse();
to parse a String to int

Unhandled Exception: This widget has been unmounted, so the State no longer has a context (and should be considered defunct)

#override
void initState() {
super.initState();
_loadData();
}
void _loadData() async {
await StorageUtil.getInstance();
String cookie = StorageUtil.getString('sess');
String page = currentPage.toString();
if (cookie != null) {
ApiService.getEstimateList(cookie, page, myAllestimate, search)
.then((value) {
if (value.data != null) {
if (count < _totalRecords) {
setState(() {
invoicelist.addAll(value.data);
print(value.data);
_totalRecords = value.recordsTotal;
});
print(
'List size is $count and TotalRecord - ${value.recordsTotal} , TotalFiltered - ${value.recordsFiltered}');
}
}
});
}
}
Future<bool> _loadMoreData() async {
print('_loadMoreData()');
await Future.delayed(Duration(seconds: 0, milliseconds: 1000));
currentPage += 1;
_loadData();
return true;
}
Future<void> _refresh() async {
currentPage = 1;
_totalRecords = 100;
invoicelist.clear();
_loadData();
}
getCustomFormattedDateTime(String givenDateTime, String dateFormat) {
// dateFormat = 'MM/dd/yy';
final DateTime docDateTime = DateTime.parse(givenDateTime);
return DateFormat(dateFormat).format(docDateTime);
}
onSearchTextChanged(String text) async {
String search = text.toLowerCase();
searchResult.clear();
if (text.isEmpty) {
setState(() {});
return;
}
if (_selectedIndex == 0) {
myAllestimate = 'my';
} else {
myAllestimate = 'all';
}
currentPage = 1;
String cookie = StorageUtil.getString('sess');
String page = currentPage.toString();
if (cookie != null) {
ApiService.getEstimateList(cookie, page, myAllestimate, search)
.then((value) {
if (value.data.length > 0) {
if (count < _totalRecords) {
setState(() {
searchResult.addAll(value.data);
_totalRecords = value.recordsTotal;
});
print(
'searchResult size is $count and TotalRecord - ${value.recordsTotal} , TotalFiltered - ${value.recordsFiltered}');
}
} else {
searchResult.clear();
setState(() {});
}
});
}
}
#override
Widget build(BuildContext context) {
return new Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(
context,
new MaterialPageRoute(
builder: (context) =>
new CatalogService(pageDirection: pageDirection)));
},
backgroundColor: Colors.orange[600],
elevation: 2.0,
child: Icon(
Icons.add,
color: Colors.white,
),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
bottomNavigationBar: _bottomTab(),
appBar: new AppBar(
title: appBarTitle,
actions: [
new IconButton(
icon: actionIcon,
onPressed: () {
setState(() {
if (this.actionIcon.icon == Icons.search) {
this.actionIcon = new Icon(Icons.close);
this.appBarTitle = new TextField(
controller: controller,
onChanged: onSearchTextChanged,
style: new TextStyle(
color: Colors.white,
),
decoration: new InputDecoration(
prefixIcon:
new Icon(Icons.search, color: Colors.white),
hintText: "Search...",
hintStyle: new TextStyle(color: Colors.white)),
);
} else {
controller.clear();
searchResult.clear();
this.actionIcon = new Icon(Icons.search);
this.appBarTitle = new Text("Manage Estimate");
}
});
},
),
],
),
body: Stack(
children: [
Center(
child: Visibility(
visible: (search.length > 0 && searchResult.length > 0)
? true
: false,
child: Text('No Data Found'),
),
),
Container(
child: searchResult.length != 0 || controller.text.isNotEmpty
? searchResults()
: buildResults()),
],
));
}
Widget searchResults() {
return RefreshIndicator(
child: LoadMore(
isFinish: count >= _totalRecords,
onLoadMore: _loadMoreData,
child: ListView.builder(
itemBuilder: (BuildContext context, int index) {
final item = searchResult[index];
String date = item.invDate.toString();
String strDate = getCustomFormattedDateTime(date, 'dd-MM-yyyy');
return Container(
padding: EdgeInsets.only(
top: 10.0, left: 20.0, right: 20.0, bottom: 10.0),
child: GestureDetector(
onTap: () {
print(searchResult[index].id);
String bmaster = StorageUtil.getString('bmaster');
String cookie = StorageUtil.getString('sess');
String id = searchResult[index].id.toString();
String mobile = searchResult[index].mobile.toString();
int custId = invoicelist[index].custId;
var weburl = '', pdfUrl;
ApiService.viewInvoice(cookie, id, bmaster, 'estimate')
.then((value) {
if (value != null) {
var result = jsonDecode(value);
if (result['status'].toString() == '1') {
var decode = Uri.decodeFull(result['url']);
var pdf_url = Uri.decodeFull(result['pdf_url']);
pdfUrl = pdf_url.toString();
weburl = decode.toString();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => WebViewContainer(
weburl, 'Estimate', pdfUrl, mobile, id, custId),
),
);
}
}
});
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
width: ScreenUtil().setSp(150),
child: Text(
item.custName,
style: TextStyle(
fontSize: 14.0,
color: Colors.black,
fontFamily: 'montserratbold',
fontWeight: FontWeight.w500,
),
),
),
Padding(
padding:
EdgeInsets.only(top: 2.0, bottom: 2.0)),
Text(
"EST-" + item.invNumber,
style: TextStyle(
fontSize: ScreenUtil().setSp(12.0),
fontFamily: 'montserrat',
color: Colors.black),
),
Padding(padding: EdgeInsets.only(top: 2.0)),
Text(
strDate,
style: TextStyle(
fontSize: ScreenUtil().setSp(12.0),
fontFamily: 'montserrat',
color: Colors.black),
),
// Padding(padding: EdgeInsets.only(top: 2.0)),
// Text(
// 'Party Balance-' +
// item.p.toString(),
// style: TextStyle(
// fontSize: 12.0, color: Colors.black),
// ),
],
),
Column(
children: <Widget>[
Text(
'Rs.' + item.totalAmt,
style: TextStyle(
fontSize: ScreenUtil().setSp(12.0),
fontFamily: 'montserrat',
color: Colors.black),
),
Padding(padding: EdgeInsets.only(top: 10.0)),
Container(
width: ScreenUtil().setSp(100),
height: ScreenUtil().setSp(25),
decoration: BoxDecoration(
color:
Color(0xffffcdd2), // border: Border.all(
// color: Colors.red[500],
// ),
borderRadius:
BorderRadius.all(Radius.circular(5))),
child: Container(
alignment: Alignment.center,
child: Text(
(item.status == 0) ? 'Paid' : 'Not Paid',
style: TextStyle(
fontWeight: FontWeight.bold,
fontFamily: 'montserrat',
fontSize: ScreenUtil().setSp(12),
color: Colors.red),
),
),
),
],
),
],
),
Padding(padding: EdgeInsets.only(top: 15)),
Container(
margin: EdgeInsets.only(top: 5, bottom: 5),
child: const Divider(
height: 2,
thickness: 1,
),
),
// Text(item.custName),
],
),
),
);
},
itemCount: searchResult.length,
),
whenEmptyLoad: true,
delegate: DefaultLoadMoreDelegate(),
textBuilder: DefaultLoadMoreTextBuilder.english,
),
onRefresh: _refresh,
);
}
Widget buildResults() {
return RefreshIndicator(
child: LoadMore(
isFinish: count >= _totalRecords,
onLoadMore: _loadMoreData,
child: ListView.builder(
itemBuilder: (BuildContext context, int index) {
final item = invoicelist[index];
String date = item.invDate.toString();
String strDate = getCustomFormattedDateTime(date, 'dd-MM-yyyy');
return Container(
padding: EdgeInsets.only(
top: 10.0, left: 20.0, right: 20.0, bottom: 10.0),
child: GestureDetector(
onTap: () {
print(invoicelist[index].id);
String bmaster = StorageUtil.getString('bmaster');
String cookie = StorageUtil.getString('sess');
String id = invoicelist[index].id.toString();
String estNumber = invoicelist[index].invNumber.toString();
String mobile = invoicelist[index].mobile.toString();
int custId = invoicelist[index].custId;
var weburl = '', pdfUrl;
ApiService.viewInvoice(cookie, id, bmaster, 'estimate')
.then((value) {
if (value != null) {
var result = jsonDecode(value);
if (result['status'].toString() == '1') {
var decode = Uri.decodeFull(result['url']);
var pdf_url = Uri.decodeFull(result['pdf_url']);
pdfUrl = pdf_url.toString();
weburl = decode.toString();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => WebViewContainer(weburl,
'Estimate', pdfUrl, mobile, estNumber, custId),
),
);
}
}
});
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
width: ScreenUtil().setSp(150),
child: Text(
item.custName,
style: TextStyle(
fontSize: 14.0,
color: Colors.black,
fontFamily: 'montserratbold',
fontWeight: FontWeight.w500,
),
),
),
Padding(
padding:
EdgeInsets.only(top: 2.0, bottom: 2.0)),
Text(
"EST-" + item.invNumber,
style: TextStyle(
fontSize: ScreenUtil().setSp(12.0),
fontFamily: 'montserrat',
color: Colors.black),
),
Padding(padding: EdgeInsets.only(top: 2.0)),
Text(
strDate,
style: TextStyle(
fontSize: ScreenUtil().setSp(12.0),
fontFamily: 'montserrat',
color: Colors.black),
),
// Padding(padding: EdgeInsets.only(top: 2.0)),
// Text(
// 'Party Balance-' +
// item.p.toString(),
// style: TextStyle(
// fontSize: 12.0, color: Colors.black),
// ),
],
),
Column(
children: <Widget>[
Text(
'Rs.' + item.totalAmt,
style: TextStyle(
fontSize: ScreenUtil().setSp(12.0),
fontFamily: 'montserrat',
color: Colors.black),
),
Padding(padding: EdgeInsets.only(top: 10.0)),
Container(
width: ScreenUtil().setSp(100),
height: ScreenUtil().setSp(25),
decoration: BoxDecoration(
color:
Color(0xffffcdd2), // border: Border.all(
// color: Colors.red[500],
// ),
borderRadius:
BorderRadius.all(Radius.circular(5))),
child: Container(
alignment: Alignment.center,
child: Text(
'Not Paid',
style: TextStyle(
fontWeight: FontWeight.bold,
fontFamily: 'montserrat',
fontSize: ScreenUtil().setSp(12),
color: Colors.red),
),
),
),
],
),
],
),
Padding(padding: EdgeInsets.only(top: 15)),
Container(
margin: EdgeInsets.only(top: 5, bottom: 5),
child: const Divider(
height: 2,
thickness: 1,
),
),
// Text(item.custName),
],
),
),
);
},
itemCount: count,
),
whenEmptyLoad: true,
delegate: DefaultLoadMoreDelegate(),
textBuilder: DefaultLoadMoreTextBuilder.english,
),
onRefresh: _refresh,
);
}
I am implementing search in my loadmore listview which is causing error when I am searching data from API.
Error:
Unhandled Exception: This widget has been unmounted, so the State no longer has a context (and should be considered defunct).
E/flutter (21599): Consider canceling any active work during "dispose" or using the "mounted" getter to determine if the State is still active.
you can check for mounted before call setState()
if (mounted) {
setState(() => {});
}
bool mounted
Whether this State object is currently in a tree.
After creating a State object and before calling initState, the
framework "mounts" the State object by associating it with a
BuildContext. The State object remains mounted until the framework
calls dispose, after which time the framework will never ask the State
object to build again.
It is an error to call setState unless mounted is true.
https://api.flutter.dev/flutter/widgets/State/mounted.html

Inserting new Widgets as List on Pressing Button in Flutter

I am making a screen like this which could select contacts from the phone book and insert the names as lists in my application. I want is that when I press Add caregiver(+) button it should select a contact and show the name.
I made a Widget for the MOM part but whenever I click the button it rewrites the MOM to any contact that I select from the phone book.
I made this screen:
I also want to add Dad and Sister's Contact in the same manner as mom, but I am unable to do it
This is my code for the screen:
import 'package:epicare/NavigBar.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_switch/flutter_switch.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:contact_picker/contact_picker.dart';
//Check contacts permission
Future<PermissionStatus> _getPermission() async {
final PermissionStatus permission = await Permission.contacts.status;
if (permission != PermissionStatus.granted &&
permission != PermissionStatus.denied) {
final Map<Permission, PermissionStatus> permissionStatus =
await [Permission.contacts].request();
return permissionStatus[Permission.contacts] ??
PermissionStatus.undetermined;
} else {
return permission;
}
}
class CaregiverScreen extends StatefulWidget {
#override
_CaregiverScreenState createState() => _CaregiverScreenState();
}
class _CaregiverScreenState extends State<CaregiverScreen> {
final ContactPicker _contactPicker = new ContactPicker();
Contact _contact;
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
bool isSwitched = true;
#override
Widget build(BuildContext context) {
//Size size = MediaQuery.of(context).size;
return Scaffold(
key: _scaffoldKey,
backgroundColor: Colors.white,
appBar: AppBar(
backgroundColor: const Color(0xffE5E0A1),
elevation: 0,
centerTitle: true,
title: Text(
"Add Caregiver",
style: TextStyle(
fontSize: 15.0,
color: Colors.black,
fontFamily: 'Montserrat',
fontWeight: FontWeight.normal,
),
),
leading: IconButton(
icon: Icon(
Icons.arrow_back,
color: Colors.black,
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return Homepage();
},
),
);
},
),
),
body: SingleChildScrollView(
child: Container(
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 40),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
MaterialButton(
onPressed: () async {
final PermissionStatus permissionStatus = await _getPermission();
if (permissionStatus == PermissionStatus.granted) {
//We can now access our contacts here
// var contactNumber = openContactBook();
Contact contact = await _contactPicker.selectContact();
setState(() {
_contact = contact;
});
}
else {
//If permissions have been denied show standard cupertino alert dialog
showDialog(
context: context,
builder: (BuildContext context) => CupertinoAlertDialog(
title: Text('Permissions error'),
content: Text('Please enable contacts access '
'permission in system settings'),
actions: <Widget>[
CupertinoDialogAction(
child: Text('OK'),
onPressed: () => Navigator.of(context).pop(),
)
],
));
}
},
color: const Color(0xffd4d411),
textColor: Colors.white,
child: Icon(
Icons.add,
size: 32,
),
padding: EdgeInsets.all(3),
shape: CircleBorder(),
),
Text(
'Add a Caregiver',
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 13,
color: const Color(0xff000000),
height: 1.5384615384615385,
fontWeight: FontWeight.w600),
textHeightBehavior:
TextHeightBehavior(applyHeightToFirstAscent: false),
textAlign: TextAlign.left,
)
],
),
_contact == null ? Container() : CaregiversList(_contact.fullName),
],
),
),
),
);
}
Widget CaregiversList(String name){
print(name);
var c = name.split(' ');
print(c[0]);
var caregiver = c[0];
var output = getInitials(string: caregiver, limitTo: 1);
print(output);
// var i = caregiver.codeUnitAt(0);
// print(i);
return Container(
padding: EdgeInsets.symmetric(vertical: 20, horizontal: 27),
child: Row(
//crossAxisAlignment: CrossAxisAlignment.center,
//mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
CircleAvatar(
radius: 24,
backgroundColor: const Color(0xffd4d411),
child: CircleAvatar(
radius: 22,
backgroundColor: Colors.white,
child: Text(
output,
style: TextStyle(
fontFamily: 'Segoe UI',
fontSize: 20,
color: const Color(0xff000000),
),
),
),
),
SizedBox(width: 19),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
caregiver,
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 13,
color: const Color(0xff000000),
height: 1.5384615384615385,
fontWeight: FontWeight.w600),
textHeightBehavior: TextHeightBehavior(
applyHeightToFirstAscent: false),
textAlign: TextAlign.left,
),
isSwitched
? Text(
"Activated",
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 10,
color: const Color(0x80232425),
fontWeight: FontWeight.w500),
textAlign: TextAlign.left,
)
: Text(
"Disabled",
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 10,
color: const Color(0x80232425),
fontWeight: FontWeight.w500),
textAlign: TextAlign.left,
),
],
),
SizedBox(width: 143),
FlutterSwitch(
width: 40.0,
height: 20.0,
value: isSwitched,
toggleSize: 15,
borderRadius: 40.0,
padding: 2.0,
showOnOff: false,
activeColor: const Color(0xffd4d411),
activeToggleColor: Colors.white,
inactiveColor: const Color(0xffDDDBAF),
inactiveToggleColor: Colors.white,
onToggle: (value) {
setState(() {
isSwitched = value;
print(isSwitched);
});
},
),
],
),
);
}
String getInitials({String string, int limitTo}) {
var buffer = StringBuffer();
var split = string.split(' ');
for (var i = 0 ; i < (limitTo ?? split.length); i ++) {
buffer.write(split[i][0]);
}
return buffer.toString();
}
}
Please help me out as i am new to Flutter.
Thank you in advance :)
You need to manage Caregiverlist you've selected from contacts. for example
class Caregiver {
String name;
bool isActive;
Caregiver({this.name, this.isActive});
factory Caregiver.fromJson(Map<String, dynamic> map) {
if (map == null) return null;
return Caregiver(name: map['name'] ?? "",
isActive: map['isActive']);
}
}
initialize caregiver list
List<Caregiver> _careList = [];
add Caregiver
Contact contact = await _contactPicker.selectContact();
setState(() {
_careList.add(Caregiver(name: contact, isActive: true));
});
show Caregiver list (To show ListView inside of Scrollview, add the following 3 lines.
ListView.separated(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
primary: false,
itemBuilder: (context, index) {
return _caregiverWidget(index);
},
separatorBuilder: (_, __) => Divider(),
itemCount: _careList.length);
Add new function
Widget _caregiverWidget(int index) {
Caregiver _caregiver = _careList[index];
print(_caregiver.name);
var c = _caregiver.name.split(' ');
print(c[0]);
var caregiver = c[0];
var output = getInitials(string: caregiver, limitTo: 1);
print(output);
// var i = caregiver.codeUnitAt(0);
// print(i);
return Container(
padding: EdgeInsets.symmetric(vertical: 20, horizontal: 27),
child: Row(
//crossAxisAlignment: CrossAxisAlignment.center,
//mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
CircleAvatar(
radius: 24,
backgroundColor: const Color(0xffd4d411),
child: CircleAvatar(
radius: 22,
backgroundColor: Colors.white,
child: Text(
output,
style: TextStyle(
fontFamily: 'Segoe UI',
fontSize: 20,
color: const Color(0xff000000),
),
),
),
),
SizedBox(width: 19),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
caregiver,
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 13,
color: const Color(0xff000000),
height: 1.5384615384615385,
fontWeight: FontWeight.w600),
textHeightBehavior:
TextHeightBehavior(applyHeightToFirstAscent: false),
textAlign: TextAlign.left,
),
_caregiver.isActive
? Text(
"Activated",
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 10,
color: const Color(0x80232425),
fontWeight: FontWeight.w500),
textAlign: TextAlign.left,
)
: Text(
"Disabled",
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 10,
color: const Color(0x80232425),
fontWeight: FontWeight.w500),
textAlign: TextAlign.left,
),
],
),
SizedBox(width: 143),
FlutterSwitch(
width: 40.0,
height: 20.0,
value: _caregiver.isActive,
toggleSize: 15,
borderRadius: 40.0,
padding: 2.0,
showOnOff: false,
activeColor: const Color(0xffd4d411),
activeToggleColor: Colors.white,
inactiveColor: const Color(0xffDDDBAF),
inactiveToggleColor: Colors.white,
onToggle: (value) {
setState(() {
_caregiver.isActive = value;
_careList.removeAt(index);
_careList.insert(index, _caregiver);
});
},
),
],
),
);
}