I am trying to fetch data from my create and showing those data into my update page data are coming. I am able to update from normal textformfield, but am not able to edit data from my drop down table. Please anyone give suggestion that where am doing mistake.
class UpdateEdic extends StatefulWidget {
final String docId;
const UpdateEdic({
Key? key,
required this.docId,
}) : super(key: key);
#override
_UpdateEdicState createState() => _UpdateEdicState();
}
class _UpdateEdicState extends State<UpdateEdic> {
final _formKey = GlobalKey<FormState>();
CollectionReference devtradecalls =
FirebaseFirestore.instance.collection('dev-trade-calls');
List<String> tslList = ['T', 'F'];
String imageUrl = "";
List<String> archivedList = ['T', 'F'];
List<String> targetAchivedList = ['T', 'F'];
DateTime tgtachtime = DateTime.now();
DateTime calltime = DateTime.now();
List tools = [];
List indicators = [];
String imageFilePath = "";
File? _imageFile;
final _picker = ImagePicker();
final format = DateFormat("HH:mm dd-MM-yyyy");
Future<void> updateEdicData(id, tsl, pattern, indicators, tools, img, notes,
targetAchieved, targetAchievedTime, archived, callTime) {
return devtradecalls
.doc(id)
.update({
'tsl': tsl,
'tslList': tslList,
'pattern': pattern,
'indicators': indicators,
'tools': tools,
'img': img,
'notes': notes,
'targetAchieved': targetAchieved,
'targetAchievedTime': targetAchievedTime,
'archived': archived,
'callTime': callTime
})
.then((value) => Navigator.pop(context))
.catchError((error) => print('Failed to update: $error'));
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Update Edic'),
),
body: Form(
key: _formKey,
child: FutureBuilder<DocumentSnapshot<Map<String, dynamic>>>(
future: FirebaseFirestore.instance
.collection('dev-trade-calls')
.doc(widget.docId)
.get(),
builder: (_, snapshot) {
if (snapshot.hasData) {
var data = snapshot.data!.data();
var tsl = data!['tsl'];
var pattern = data['pattern'];
List indicators = data['indicators'];
List tools = data['tools'];
var imgUrl = data['img'];
var notes = data['notes'];
var targetAchieved = data['targetAchieved'];
DateTime? targetAchievedTime =
(data['targetAchievedTime'] as Timestamp).toDate();
var archived = data['archived'];
DateTime? callTime = (data['callTime'] as Timestamp).toDate();
return Padding(
padding: const EdgeInsets.all(16.0),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Trailing Stop Loss',
style: labelStyle.copyWith(color: primaryColor)),
DropdownButton<String>(
isExpanded: true,
value: tsl,
items: tslList.map((String items) {
return DropdownMenuItem(
value: items,
child: Text(kEdictsl[items]!),
);
}).toList(),
onChanged: (String? newValue) {
setState(() {
tsl = newValue;
});
},
),
SizedBox(
height: 24,
),
Text('Pattern',
style: labelStyle.copyWith(color: primaryColor)),
TextFormField(
autocorrect: true,
enableSuggestions: true,
initialValue: pattern,
onChanged: (value) {
pattern = value;
},
keyboardType: TextInputType.multiline,
),
SizedBox(
height: 24,
),
Text('Indicators',
style: labelStyle.copyWith(color: primaryColor)),
MultiSelectDialogField(
listType: MultiSelectListType.CHIP,
searchable: true,
initialValue: indicators,
items: kEdicIndicators
.map((t) => MultiSelectItem<dynamic>(t, t))
.toList(),
buttonIcon: Icon(
Icons.candlestick_chart,
color: Colors.blue,
),
onConfirm: (value) => indicators = value,
chipDisplay: MultiSelectChipDisplay(
onTap: (value) {
indicators.remove(value);
},
),
),
SizedBox(height: 24.0),
Text('Tools',
style: labelStyle.copyWith(color: primaryColor)),
MultiSelectDialogField(
listType: MultiSelectListType.CHIP,
searchable: true,
items: kEdicTools
.map((t) => MultiSelectItem<dynamic>(t, t))
.toList(),
initialValue: tools,
buttonIcon: Icon(
Icons.settings_sharp,
color: Colors.blue,
),
onConfirm: (results) {
tools = results;
},
chipDisplay: MultiSelectChipDisplay(
onTap: (value) {
tools.remove(value);
},
),
),
SizedBox(
height: 24,
),
Text('Notes',
style: labelStyle.copyWith(color: primaryColor)),
TextFormField(
initialValue: notes,
autocorrect: true,
onChanged: (value) {
notes = value;
},
enableSuggestions: true,
keyboardType: TextInputType.multiline,
minLines: 1,
maxLines: 3,
),
SizedBox(
height: 24,
),
Text('Target Achived',
style: labelStyle.copyWith(color: primaryColor)),
DropdownButton<String>(
isExpanded: true,
value: targetAchieved,
hint: const Text('True/False'),
items: targetAchivedList.map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(kEdicTargetAchived[value]!),
);
}).toList(),
onChanged: (value) => targetAchieved = value,
// {
// setState(() {
// // targetAchived = value!;
// });
// },
),
const SizedBox(height: 24.0),
Text('Target Achieved Time',
style: labelStyle.copyWith(color: primaryColor)),
SizedBox(
height: 24,
),
DateTimeField(
format: format,
onShowPicker: (context, currentValue) async {
final date = await showDatePicker(
context: context,
firstDate: DateTime(1900),
initialDate: currentValue ?? DateTime.now(),
lastDate: DateTime(2100));
if (date != null) {
final time = await showTimePicker(
context: context,
initialTime: TimeOfDay.fromDateTime(
currentValue ?? DateTime.now()),
);
return DateTimeField.combine(date, time);
} else {
return currentValue;
}
},
validator: (date) =>
date == null ? 'Invalid date' : null,
initialValue: targetAchievedTime,
onChanged: (value) => targetAchievedTime = value,
onSaved: (date) => setState(() {
// savedCount++;
}),
),
const SizedBox(
height: 24,
),
Text('Archived',
style: labelStyle.copyWith(color: primaryColor)),
DropdownButton<String>(
isExpanded: true,
value: archived,
hint: const Text('True/False'),
items: archivedList.map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(kEdicArchived[value]!),
);
}).toList(),
onChanged: (value) => archived = value,
),
SizedBox(
height: 24,
),
Text('Call Time',
style: labelStyle.copyWith(color: primaryColor)),
SizedBox(
height: 24,
),
DateTimeField(
format: format,
onShowPicker: (context, currentValue) async {
final date = await showDatePicker(
context: context,
firstDate: DateTime(1900),
initialDate: currentValue ?? DateTime.now(),
lastDate: DateTime(2100));
if (date != null) {
final time = await showTimePicker(
context: context,
initialTime: TimeOfDay.fromDateTime(
currentValue ?? DateTime.now()),
);
return DateTimeField.combine(date, time);
} else {
return currentValue;
}
},
validator: (date) =>
date == null ? 'Invalid date' : null,
initialValue: callTime,
onChanged: (value) => callTime = value,
),
const SizedBox(
height: 24,
),
Text('Image URL',
style: labelStyle.copyWith(color: primaryColor)),
TextFormField(
autocorrect: true,
enableSuggestions: true,
initialValue: imgUrl,
onChanged: (value) {
imgUrl = value;
},
keyboardType: TextInputType.multiline,
minLines: 1,
maxLines: 3,
),
Text('Add Image',
style: labelStyle.copyWith(color: primaryColor)),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
ElevatedButton.icon(
onPressed: () async {
await pickImageFromCamera();
},
icon: Icon(
Icons.add_a_photo,
),
label: const Text('Camera'),
),
ElevatedButton.icon(
onPressed: () async {
await pickImageFromGallery();
},
icon: Icon(
Icons.collections,
),
label: const Text('Gallery'),
),
],
),
_previewImage(),
SizedBox(height: 24.0),
ElevatedButton(
style: ElevatedButton.styleFrom(
minimumSize: Size(
double.infinity,
48,
), // double.infinity is the width and 30 is the height
),
onPressed: () {
if (_formKey.currentState!.validate()) {
updateEdicData(
widget.docId,
tsl,
pattern,
indicators,
tools,
imgUrl,
notes,
targetAchieved,
targetAchievedTime,
archived,
callTime);
Navigator.pop(context);
}
},
child: Text('Update'),
)
],
),
),
);
}
if (snapshot.hasError) {
return const Text('"Something Went Wrong"');
}
return const Center(
child: CircularProgressIndicator(),
);
},
)),
);
}
}
Related
How can I update a specific field in my Datatable. I am using this package: https://pub.dev/packages/responsive_table
When I tap on one item in my Datatable it opens a Dialog where I have my TextController and a ElevatedButton for updating my values. All that seems to work, I click on one item, the right name of that item is stored in my TextController. But when I press my button, it's updating some random item in my Firebase and not the value that i clicked in the first place.
Here is my code:
class _UsersPageState extends State<UsersPage> {
var nameController = TextEditingController();
#override
Widget build(BuildContext context) {
final UserTableProvider usertablesProvider = Provider.of<UserTableProvider>(context);
return SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: [
Container(
margin: EdgeInsets.all(10),
padding: EdgeInsets.all(0),
constraints: BoxConstraints(
maxHeight: 700,
),
child: Card(
elevation: 1,
shadowColor: Colors.black,
clipBehavior: Clip.none,
child: ResponsiveDatatable(
title: TextButton.icon(
onPressed: () => {
addUserDialog(context),
},
icon: Icon(Icons.add),
label: Text("Legg til bruker"),
),
reponseScreenSizes: [ScreenSize.xs],
actions: [
if (usertablesProvider.isSearch)
Expanded(
child: TextField(
decoration: InputDecoration(
hintText: 'Søk på ansattnr..',
prefixIcon: IconButton(
icon: Icon(Icons.cancel),
onPressed: () {
setState(() {
usertablesProvider.isSearch = false;
});
}),
suffixIcon: IconButton(
icon: Icon(Icons.search), onPressed: () {})),
onSubmitted: (value) {
usertablesProvider.filterData(value);
},
)),
if (!usertablesProvider.isSearch)
IconButton(
icon: Icon(Icons.search),
onPressed: () {
setState(() {
usertablesProvider.isSearch = true;
});
}),
],
headers: usertablesProvider.userTableHeader,
source: usertablesProvider.source,
selecteds: usertablesProvider.selecteds,
showSelect: usertablesProvider.showSelect,
autoHeight: false,
onSort: (value) {
setState(() => usertablesProvider.isLoading = true);
setState(() {
usertablesProvider.sortColumn = value;
usertablesProvider.sortAscending = !usertablesProvider.sortAscending;
if (usertablesProvider.sortAscending) {
usertablesProvider.sourceFiltered.sort((a, b) =>
b["${usertablesProvider.sortColumn}"].compareTo(a["${usertablesProvider.sortColumn}"]));
} else {
usertablesProvider.sourceFiltered.sort((a, b) =>
a["${usertablesProvider.sortColumn}"].compareTo(b["${usertablesProvider.sortColumn}"]));
}
var _rangeTop = usertablesProvider.currentPerPage! < usertablesProvider.sourceFiltered.length
? usertablesProvider.currentPerPage!
: usertablesProvider.sourceFiltered.length;
usertablesProvider.source = usertablesProvider.sourceFiltered.getRange(0, _rangeTop).toList();
usertablesProvider.searchKey = value;
usertablesProvider.isLoading = false;
});
},
expanded: usertablesProvider.expanded,
sortAscending: usertablesProvider.sortAscending,
sortColumn: usertablesProvider.sortColumn,
isLoading: usertablesProvider.isLoading,
onTabRow: (data){
updateUserDialog(context);
print(data);
nameController.text = data['name'];
},
onSelect: (value, item) {
print("$value $item ");
if (value!) {
setState(() => usertablesProvider.selecteds.add(item));
} else {
setState(
() => usertablesProvider.selecteds.removeAt(usertablesProvider.selecteds.indexOf(item)));
}
},
onSelectAll: (value) {
if (value!) {
setState(() => usertablesProvider.selecteds =
usertablesProvider.source.map((entry) => entry).toList().cast());
} else {
setState(() => usertablesProvider.selecteds.clear());
}
},
footers: [
Container(
padding: EdgeInsets.symmetric(horizontal: 15),
child: Text("Rader per side:"),
),
if (usertablesProvider.perPages.isNotEmpty)
Container(
padding: EdgeInsets.symmetric(horizontal: 15),
child: DropdownButton<int>(
value: usertablesProvider.currentPerPage,
items: usertablesProvider.perPages
.map((e) => DropdownMenuItem<int>(
child: Text("$e"),
value: e,
))
.toList(),
onChanged: (dynamic value) {
setState(() {
usertablesProvider.currentPerPage = value;
usertablesProvider.currentPage = 1;
usertablesProvider.resetData();
});
},
isExpanded: false,
),
),
Container(
padding: EdgeInsets.symmetric(horizontal: 15),
child:
Text("${usertablesProvider.currentPage} - ${usertablesProvider.currentPerPage} of ${usertablesProvider.total}"),
),
IconButton(
icon: Icon(
Icons.arrow_back_ios,
size: 16,
),
onPressed: usertablesProvider.currentPage == 1
? null
: () {
var _nextSet = usertablesProvider.currentPage - usertablesProvider.currentPerPage!;
setState(() {
usertablesProvider.currentPage = _nextSet > 1 ? _nextSet : 1;
usertablesProvider.resetData(start: usertablesProvider.currentPage - 1);
});
},
padding: EdgeInsets.symmetric(horizontal: 15),
),
IconButton(
icon: Icon(Icons.arrow_forward_ios, size: 16),
onPressed: usertablesProvider.currentPage + usertablesProvider.currentPerPage! - 1 > usertablesProvider.total
? null
: () {
var _nextSet = usertablesProvider.currentPage + usertablesProvider.currentPerPage!;
setState(() {
usertablesProvider.currentPage = _nextSet < usertablesProvider.total
? _nextSet
: usertablesProvider.total - usertablesProvider.currentPerPage!;
usertablesProvider.resetData(start: _nextSet - 1);
});
},
padding: EdgeInsets.symmetric(horizontal: 15),
)
],
),
),
),
])
);
}
updateUserDialog(BuildContext context){
return showDialog(context: context, builder: (context) {
return Dialog(
child: Container(
child: SizedBox(
width: 600,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text('Endre bruker', style: TextStyle(
fontWeight: FontWeight.bold
),),
SizedBox(
height: 10,
),
TextField(
controller: nameController,
decoration: const InputDecoration(
labelText: 'Navn',
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.grey,
),
),
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.grey)
)
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.grey,
),
),
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.grey)
)
),
),
ElevatedButton(
onPressed: () async {
var name = nameController.text.trim();
FirebaseFirestore firebaseFirestore = FirebaseFirestore.instance;
FirebaseAuth auth = FirebaseAuth.instance;
User? user = auth.currentUser;
await firebaseFirestore.collection('users').doc(user!.uid).update({
'navn': name,
});
nameController.text = '';
},
child: const Text('Save')),
const SizedBox(
height: 10,
),
],
),
),
),
);
});
}
class UserTableProvider with ChangeNotifier {
List<DatatableHeader> userTableHeader = [
DatatableHeader(
text: "Ansattnr",
value: "empnumber",
show: true,
flex: 1,
sortable: true,
textAlign: TextAlign.left),
DatatableHeader(
text: "Navn",
value: "name",
show: true,
flex: 6,
sortable: true,
textAlign: TextAlign.left),
DatatableHeader(
text: "Epost",
value: "email",
show: true,
flex: 4,
sortable: true,
textAlign: TextAlign.left),
DatatableHeader(
text: "",
value: "uid",
show: false,
sortable: true,
textAlign: TextAlign.center),
DatatableHeader(
text: "Tlf",
value: "tlfnumber",
show: true,
flex: 2,
sortable: true,
textAlign: TextAlign.left),
DatatableHeader(
text: "Eget verktøy",
value: "owntool",
show: false,
sortable: true,
textAlign: TextAlign.left),
];
final List<int> perPages = [10, 20, 50, 100];
int total = 100;
int? currentPerPage = 10;
int currentPage = 1;
List<bool>? expanded;
String? searchKey = "empnumber";
bool isSearch = false;
List<Map<String, dynamic>> sourceOriginal = [];
List<Map<String, dynamic>> sourceFiltered = [];
List<Map<String, dynamic>> source = [];
List<Map<String, dynamic>> selecteds = [];
// ignore: unused_field
final String selectableKey = "id";
String? sortColumn;
bool sortAscending = true;
bool isLoading = true;
final bool showSelect = true;
final UserServices _userServices = UserServices();
List<UserModel> _users = <UserModel>[];
List<UserModel> get users => _users;
Future _loadFromFirebase() async {
_users = await _userServices.getAllUsers();
}
List<Map<String, dynamic>> _getUsersData() {
isLoading = true;
List<Map<String, dynamic>> temps = [];
var i = users.length;
if (kDebugMode) {
print(i);
}
// ignore: unused_local_variable
for (UserModel userData in users) {
if (kDebugMode) {
print(userData.name);
}
if (kDebugMode) {
print(userData.email);
}
temps.add({
"empnumber": userData.empnumber,
"email": userData.email,
"name": userData.name,
"uid": userData.uid,
"owntool": userData.owntool,
"tlfnumber": userData.tlfnumber,
});
i++;
}
return temps;
}
_initData() async {
await _loadFromFirebase();
mockPullData();
notifyListeners();
}
mockPullData() async {
expanded = List.generate(currentPerPage!, (index) => false);
isLoading = true;
Future.delayed(const Duration(seconds: 3)).then((value) {
sourceOriginal.clear();
sourceOriginal.addAll(_getUsersData());
sourceFiltered = sourceOriginal;
total = sourceFiltered.length;
source = sourceFiltered.getRange(0, _users.length).toList();
isLoading = false;
notifyListeners();
});
}
resetData({start: 0}) async {
isLoading = true;
var expandedLen =
total - start < currentPerPage! ? total - start : currentPerPage;
Future.delayed(const Duration(seconds: 0)).then((value) {
expanded = List.generate(expandedLen as int, (index) => false);
source.clear();
source = sourceFiltered.getRange(start, start + expandedLen).toList();
isLoading = false;
notifyListeners();
});
}
filterData(value) {
isLoading = true;
try {
if (value == "" || value == null) {
source = sourceOriginal;
} else {
sourceFiltered = sourceOriginal
.where((data) => data[searchKey!]
.toString()
.toLowerCase()
.contains(value.toString().toLowerCase()))
.toList();
}
total = sourceFiltered.length;
var _rangeTop = total < currentPerPage! ? total : currentPerPage!;
expanded = List.generate(_rangeTop, (index) => false);
source = sourceFiltered.getRange(0, _rangeTop).toList();
} catch (e) {
print(e);
}
isLoading = false;
notifyListeners();
}
UserTableProvider.init() {
_initData();
}
}
The problem is the user id you are using to update the firestore document, the current user's id not the user id from the data.
Please edit your updateUserDialog method, add the data as a parameter for the function. Something like updateUserDialog(BuildContext context, Map<String, dynamic> data).
This will avail the whole data Map within the method. This will expose the uid for you to use to update the right document. You can then pass uid from the data Map as the doc as shown below.
await firebaseFirestore.collection('users').doc(userId).update({
'navn': name,
});
For the snippet above, the uid is stored in a variable userId.
Below is the complete updated method you can work with.
updateUserDialog(BuildContext context, Map<String, dynamic> data) {
nameController.text = data['name'];
String userId = data['uid'].toString();
return showDialog(
context: context,
builder: (context) {
return Dialog(
child: Container(
child: SizedBox(
width: 600,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Text(
'Endre bruker',
style: TextStyle(fontWeight: FontWeight.bold),
),
const SizedBox(
height: 10,
),
TextField(
controller: nameController,
decoration: const InputDecoration(
labelText: 'Navn',
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.grey,
),
),
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.grey))),
),
ElevatedButton(
onPressed: () async {
var name = nameController.text.trim();
FirebaseFirestore firebaseFirestore =
FirebaseFirestore.instance;
await firebaseFirestore
.collection('users')
.doc(userId)
.update({
'navn': name,
});
nameController.text = '';
},
child: const Text('Save')),
const SizedBox(
height: 10,
),
],
),
),
),
);
},
);
}
You might as well update your onTabRow function to
onTabRow: (data) {
updateUserDialog(context, data);
},
That should solve your issue.
My app is for the driver, who delivers orders through this application. In this, I am listening to all the orders assigned to the driver from the firebase realtime database. The onChildAdded.listen adds the order to a list named ongoingList of class Ongoing which means assigned to him. I am then displaying the length of the list as count in the dashboard. Now sometimes I am getting unexpected counts in the dashboard and also the list contains duplicate entries.
I am adding the code below
class Dashboard extends StatefulWidget {
const Dashboard({Key? key}) : super(key: key);
#override
_DashboardState createState() => _DashboardState();
}
class _DashboardState extends State<Dashboard>
with SingleTickerProviderStateMixin {
bool isLoading = false;
bool isOnline = true;
var OngoingDetails;
List<Ongoing> ongoingList = [];
List<OpenRequest> openRequestList = [];
DatabaseReference databaseReference = FirebaseDatabase.instance.reference();
late StreamSubscription<Event> ongoingStream;
late StreamSubscription<Event> openRequestStream;
late StreamSubscription<Event> removeOpenNodes;
late LocationData currentLoc;
double currentLat = 0;
double currentLng = 0;
DriverDetail _driverData = DriverDetail();
// late Timer timer;
#override
void initState() {
super.initState();
// timer =
// Timer.periodic(Duration(seconds: 300), (Timer t) => reloadPageAuto());
getDriverData();
countOpenRequest = 0;
ongoingCount = 0;
}
reloadPageAuto() {
// Navigator.pop(context); // pop current page
Navigator.pushReplacementNamed(context, '/dashboard'); // push it back in
}
getDriverData() async {
setState(() {
isLoading = true;
});
_driverData = await getDriverDetails();
print("${_driverData.driverName}");
setState(() {
isLoading = false;
});
//getCurrentLocation();
}
getCurrentLocation() async {
currentLoc = await getLoc();
setState(() {
currentLat = currentLoc.latitude!;
currentLng = currentLoc.longitude!;
isLoading = false;
});
// checkOpenRequest();
}
#override
void dispose() {
// timer.cancel();
super.dispose();
}
#override
Widget build(BuildContext context) {
DateTime timeBackPressed = DateTime.now();
return isLoading == false
? DefaultTabController(
child: WillPopScope(
onWillPop: () async {
final difference = DateTime.now().difference(timeBackPressed);
timeBackPressed = DateTime.now();
if (difference >= Duration(seconds: 1)) {
final String msg = 'Press the back button again to exit';
showToast(msg);
return false;
} else {
Fluttertoast.cancel();
SystemNavigator.pop();
return true;
}
},
child: Scaffold(
appBar: AppBar(
leading: Switch(
materialTapTargetSize: MaterialTapTargetSize.padded,
activeTrackColor: Colors.grey,
value: isOnline,
activeColor: kWagonColour,
onChanged: (value) async {
setState(() {
isOnline = value;
//print(isOnline);
Fluttertoast.showToast(
msg: isOnline == true
? "You are now Online"
: "You are now Offline",
gravity: ToastGravity.BOTTOM,
textColor: Colors.white,
backgroundColor: kWagonColour,
);
});
if (isOnline == true) {
await OneSignal.shared.disablePush(false);
OneSignal.shared
.setAppId("abd31b6b-5fc4-4769-8684-224a439e422e");
final status = await OneSignal.shared.getDeviceState();
var playerId = status!.userId;
OSCreateNotification notification =
OSCreateNotification(
androidChannelId:
"1ff1eb80-0316-419f-bd37-0992145ee37d",
heading: "Go Wagon Driver",
playerIds: [playerId.toString()],
content: "Background Service Active",
androidSound: "onesignal_default_sound.wav",
iosSound: "onesignal_default_sound.wav",
);
OneSignal.shared.postNotification(notification);
SystemChrome.setSystemUIOverlayStyle(
SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
));
} else {
//print('else');
await OneSignal.shared.disablePush(true);
}
},
),
actions: [
Padding(
padding: const EdgeInsets.only(right: 15.0),
child: GestureDetector(
child: CircleAvatar(
backgroundImage: NetworkImage(_driverData.image),
),
onTap: () {
Navigator.pushNamed(context, '/profile');
},
),
),
],
centerTitle: true,
title: Image.asset(
'images/app_icon.png',
height: 50.0,
width: 50.0,
),
bottom: TabBar(
tabs: [
Tab(
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.home,
color: kWagonColour,
),
Padding(
padding: const EdgeInsets.only(left: 5),
child: Text('Home'),
),
],
),
),
Tab(
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.price_change_outlined,
color: kWagonColour,
),
Padding(
padding: const EdgeInsets.only(left: 5),
child: Text('Earnings'),
),
],
),
),
],
labelColor: kWagonColour,
indicator: UnderlineTabIndicator(
borderSide: BorderSide(width: 2.0, color: kWagonColour),
insets: EdgeInsets.symmetric(horizontal: 25.0),
),
indicatorColor: kWagonColour,
unselectedLabelColor: Colors.grey,
indicatorSize: TabBarIndicatorSize.tab,
labelStyle: TextStyle(
fontSize: 16.0,
),
),
),
backgroundColor: Color(0xFFF5F5F5),
body: isLoading
? ColorLoader()
: GestureDetector(
child: TabBarView(
children: [
Status(
details: ongoingList,
),
Earnings(),
],
),
),
floatingActionButtonLocation:
FloatingActionButtonLocation.startFloat,
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => QRCodeScanner(),
));
},
child: Icon(
Icons.qr_code_scanner,
color: kWagonColour,
),
backgroundColor: Colors.white,
),
),
),
length: 2,
initialIndex: 0,
)
: Scaffold(
body: ColorLoader(),
);
}
}
class Status extends StatefulWidget {
const Status({Key? key, required this.details}) : super(key: key);
final List details;
#override
_StatusState createState() => _StatusState();
}
class _StatusState extends State<Status>
with AutomaticKeepAliveClientMixin<Status> {
#override
bool get wantKeepAlive => true;
var top = 10.0;
var left = 10.0;
DriverDetail _driverData = DriverDetail();
bool isLoading = false;
bool isLoadingCount = true;
List<Ongoing> ongoingList = [];
List<OpenRequest> openRequestList = [];
DatabaseReference databaseReference = FirebaseDatabase.instance.reference();
late StreamSubscription<Event> ongoingStream;
late StreamSubscription<Event> openRequestStream;
late StreamSubscription<Event> removeOpenNodes;
late LocationData currentLoc;
double currentLat = 0;
double currentLng = 0;
bool _enabled = true;
#override
void initState() {
super.initState();
getDriverData();
}
getCurrentLocation() async {
currentLoc = await getLoc();
setState(() {
currentLat = currentLoc.latitude!;
currentLng = currentLoc.longitude!;
});
setState(() {
isLoading = false;
});
checkOpenRequest();
}
checkOpenRequest() async {
print("checking open request");
if (countOpenRequest == 0) {
setState(() {
isOpenRequest = false;
});
}
print("open count $countOpenRequest");
countOpenRequest = 0;
openRequestStream = FirebaseDatabase.instance
.reference()
.child('shipments')
.child('open_requests')
.orderByChild('model_id')
.equalTo(double.parse(_driverData.modelId))
.onChildAdded.listen(_onEntryAddedOpen);
// .listen((event) {
// double total_distance = distance(
// currentLat,
// currentLng,
// double.parse(event.snapshot.value['pickup_latitude']),
// double.parse(event.snapshot.value['pickup_longitude']),
// 'K');
// print("distance for ${event.snapshot.key} $total_distance");
//
// if (total_distance <= 50) {
// HapticFeedback.heavyImpact();
// setState(() {
// // print("New request received: ${event.snapshot.value}");
// ++countOpenRequest;
// isOpenRequest = true;
// });
// }
// });
checkOngoing();
}
checkOngoing() async {
print("checking ongoing");
ongoingStream = FirebaseDatabase.instance
.reference()
.child('shipments')
.child('driver_shipments')
.child(_driverData.vehicleId)
.onChildAdded
.listen(_onEntryAddedOngoing);
setState(() {
isLoadingCount = false;
});
}
getDriverData() async {
setState(() {
isLoading = true;
});
_driverData = await getDriverDetails();
getCurrentLocation();
}
#override
void dispose() {
// timer.cancel();
openRequestStream.cancel();
ongoingStream.cancel();
super.dispose();
}
#override
Widget build(BuildContext context) {
super.build(context);
var deviceWidth = MediaQuery.of(context).size.width;
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 15.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
height: 100.0,
padding: EdgeInsets.symmetric(vertical: 8.0),
width: double.infinity,
child: Card(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
AutoSizeText(
'Hi, ${_driverData.driverName}',
minFontSize: 16,
maxFontSize: 20,
overflow: TextOverflow.visible,
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
SizedBox(
height: 10.0,
),
Text(
'What do you want to do today?',
style: TextStyle(
fontSize: 16.0,
),
),
],
),
SizedBox(
width: 50.0,
),
GestureDetector(
child: Icon(
Icons.replay_circle_filled,
color: kWagonColour,
size: 40.0,
semanticLabel: 'Refresh',
),
onTap: _enabled ? refreshCounts : null,
),
],
),
),
),
Container(
height: 100,
width: MediaQuery.of(context).size.width,
child: Stack(
children: [
Positioned(
child: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
OngoingShipments(ongoingDetails: ongoingList),
),
);
},
child: Row(
children: [
Container(
width: deviceWidth / 7,
height: 40,
child: Center(
child: isLoadingCount == false
? Text(
ongoingList.length.toString(),
style: TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.bold,
),
)
: CircularProgressIndicator(
color: Colors.white,
),
),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: kWagonColour,
),
),
SizedBox(
width: 5,
),
ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => OngoingShipments(
ongoingDetails: ongoingList),
),
);
},
child: Text(
'ONGOING',
style: TextStyle(
color: kWagonColour,
),
),
style: ElevatedButton.styleFrom(
primary: Colors.white,
),
)
],
),
),
),
Positioned(
top: 20,
left: deviceWidth / 1.8,
child: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => TestFirebase()));
},
child: Row(
children: [
ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => TestFirebase()));
},
child: Text(
'OPEN',
style: TextStyle(
color: kWagonColour,
),
),
style: ElevatedButton.styleFrom(
primary: Colors.white,
),
),
SizedBox(
width: 5,
),
Container(
width: 60,
height: 40,
child: Center(
child: isLoadingCount == false
? Text(
openRequestList.length.toString(),
style: TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.bold,
),
)
: CircularProgressIndicator(
color: Colors.white,
),
),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: kWagonColour,
),
),
],
),
),
),
],
),
),
],
),
);
}
refreshCounts() {
setState(() {
isLoadingCount = true;
_enabled = false;
});
isLoadingCount = true;
ongoingList = [];
openRequestList = [];
ongoingCount = 0;
countOpenRequest = 0;
Timer(Duration(seconds: 1), () {
setState(() {
_enabled = true;
});
checkOpenRequest();
});
}
_onEntryAddedOngoing(Event event) async {
setState(() {
ongoingList.add(Ongoing.fromSnapshot(event.snapshot));
});
}
_onEntryAddedOpen(Event event) async {
double totalDistance = distance(
currentLat,
currentLng,
double.parse(event.snapshot.value['pickup_latitude']),
double.parse(event.snapshot.value['pickup_longitude']),
'K');
print("distance for ${event.snapshot.key} $totalDistance");
if (totalDistance <= 50) {
HapticFeedback.heavyImpact();
setState(() {
openRequestList.add(OpenRequest.fromFirebase(event.snapshot));
});
}
}
}
Below is the code for my class Ongoing
Ongoing(
{this.baseFare,
this.cancelationFee,
this.customerId,
this.customerName,
this.distanceTotal,
this.driverId,
this.driverImage,
this.driverName,
this.driverNumber,
this.driverNumberCode,
this.dropAddress,
this.dropLatitude,
this.dropLongitude,
this.estimatedTime,
this.helpCount,
this.helpTotal,
this.isPayable,
this.itemCount,
this.masterFlag,
this.minHr,
this.minKm,
this.modelId,
this.payableFlag,
this.paymentMethod,
this.paymentStatus,
this.perHr,
this.perKm,
this.pickPayPaymentStatus,
this.pickupAddress,
this.pickupCode,
this.pickupLatitude,
this.pickupLongitude,
this.pickupTime,
this.price,
this.pricePerHr,
this.pricePerKm,
this.receiverName,
this.receiverPhone,
this.receiverPhoneCode,
this.senderName,
this.senderPhone,
this.senderPhoneCode,
this.shipmentId,
this.shipmentLabel,
this.shipmentLabelAr,
this.shipmentOtp,
this.shipmentPackageInstruction,
this.shipmentPackageName,
this.shipmentPackagePropertyId,
this.shipmentPackageTypeId,
this.shipmentPolyline,
this.status,
this.total,
this.type,
this.vehicleId,
this.vehicleName,
this.wagoncut,
this.isCashShipment,
this.invoiceNumber,
this.invoiceDate,
this.invoiceAmount,
this.operationMobile, this.packageName});
Ongoing.fromSnapshot(DataSnapshot snapshot) {
baseFare = snapshot.value['base_fare'];
cancelationFee = snapshot.value['cancelation_fee'];
customerId = snapshot.value['customer_id'];
customerName = snapshot.value['customer_name'];
distanceTotal = snapshot.value['distance_total'];
driverId = int.parse(snapshot.value['driver_id'].toString());
driverImage = snapshot.value['driver_image'];
driverName = snapshot.value['driver_name'];
driverNumber = snapshot.value['driver_number'];
driverNumberCode = snapshot.value['driver_number_code'];
dropAddress = snapshot.value['drop_address'];
dropLatitude = snapshot.value['drop_latitude'];
dropLongitude = snapshot.value['drop_longitude'];
estimatedTime = snapshot.value['estimated_time'];
helpCount = snapshot.value['help_count'];
helpTotal = snapshot.value['help_total'];
isPayable = snapshot.value['is_payable'];
itemCount = snapshot.value['item_count'];
masterFlag = snapshot.value['master_flag'];
minHr = snapshot.value['min_hr'];
minKm = snapshot.value['min_km'];
modelId = snapshot.value['model_id'];
payableFlag = snapshot.value['payable_flag'];
paymentMethod = snapshot.value['payment_method'];
paymentStatus = snapshot.value['payment_status'];
perHr = snapshot.value['per_hr'];
perKm = snapshot.value['per_km'];
pickPayPaymentStatus = snapshot.value['pick_pay_payment_status'];
pickupAddress = snapshot.value['pickup_address'];
pickupCode = snapshot.value['pickup_code'];
pickupLatitude = snapshot.value['pickup_latitude'];
pickupLongitude = snapshot.value['pickup_longitude'];
pickupTime = snapshot.value['pickup_time'];
price = snapshot.value['price'];
pricePerHr = snapshot.value['price_per_hr'];
pricePerKm = snapshot.value['price_per_km'];
receiverName = snapshot.value['receiver_name'];
receiverPhone = snapshot.value['receiver_phone'];
receiverPhoneCode = snapshot.value['receiver_phone_code'].toString();
senderName = snapshot.value['sender_name'];
senderPhone = snapshot.value['sender_phone'];
senderPhoneCode = snapshot.value['sender_phone_code'].toString();
shipmentId = snapshot.value['shipment_id'];
shipmentLabel = snapshot.value['shipment_label'];
shipmentLabelAr = snapshot.value['shipment_label_ar'];
shipmentOtp = snapshot.value['shipment_otp'];
shipmentPackageInstruction = snapshot.value['shipment_package_instruction'];
shipmentPackageName = snapshot.value['shipment_package_name'];
shipmentPackagePropertyId = snapshot.value['shipment_package_property_id'];
shipmentPackageTypeId = snapshot.value['shipment_package_type_id'];
shipmentPolyline = snapshot.value['shipment_polyline'];
status = snapshot.value['status'];
total = snapshot.value['total'];
type = snapshot.value['type'];
vehicleId = snapshot.value['vehicle_id'];
vehicleName = snapshot.value['vehicle_name'];
wagoncut = snapshot.value['wagoncut'];
isCashShipment = snapshot.value['is_cash_shipment'].toString();
invoiceAmount = snapshot.value['invoice_amount'].toString();
invoiceNumber = snapshot.value['invoice_no'].toString();
invoiceDate = snapshot.value['invoice_date'].toString();
operationMobile = snapshot.value['operation_mobile'].toString();
}
}
If anyone has relevant suggestion regarding it, please help me through it. Thank you in advance
In my app, any user can add an Ad and, in home screen, with all Ads showing up in a list view, I get info of every single Ad from the table of cars in firebase; but I want to show the profile images of this user by sending the user id and getting the image from users table.
My function to get data from firebase:
Future<DocumentSnapshot> getAdData(String uid)async{
return await FirebaseFirestore.instance.collection('users').doc(uid).
get();
}
My homescreen:
import 'package:cargaaaalery/functions.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'globalVar.dart';
class HomeScreen extends StatefulWidget {
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
FirebaseAuth auth = FirebaseAuth.instance;
String? username;
String? userNumber;
String? carPrice;
String? carModel;
String? description;
String? urlImage;
String? carLocation;
String? carColor;
QuerySnapshot? cars;
// DocumentSnapshot? users;
String? usersImg;
CarMethods carobj = new CarMethods();
dynamic carUserId;
Future<bool?> showDialogForAddingData() async {
return showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: Text(
"post a new AD",
style: TextStyle(
fontSize: 22, fontFamily: "Bebas", letterSpacing: 2),
),
content: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextField(
decoration: InputDecoration(hintText: "Enter your number"),
onChanged: (val) {
userNumber = val;
},
),
SizedBox(
height: 5,
),
TextField(
decoration:
InputDecoration(hintText: "Enter your car price"),
onChanged: (val) {
carPrice = val;
},
),
SizedBox(
height: 5,
),
TextField(
decoration:
InputDecoration(hintText: "Enter your car name"),
onChanged: (val) {
carModel = val;
},
),
SizedBox(
height: 5,
),
TextField(
decoration:
InputDecoration(hintText: "Enter your car Color"),
onChanged: (val) {
carColor = val;
},
),
SizedBox(
height: 5,
),
TextField(
decoration:
InputDecoration(hintText: "Enter your car description"),
onChanged: (val) {
description = val;
},
),
SizedBox(
height: 5,
),
TextField(
decoration:
InputDecoration(hintText: "Enter your car Image"),
onChanged: (val) {
urlImage = val;
},
),
SizedBox(
height: 5,
),
TextField(
decoration:
InputDecoration(hintText: "Enter your car Location"),
onChanged: (val) {
carLocation = val;
},
),
SizedBox(
height: 5,
),
],
),
),
actions: [
ElevatedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text("Cancel"),
),
ElevatedButton(
onPressed: () {
Map<String, dynamic> carData = {
'username': getUsername,
'uId': userId,
'userNumber': this.userNumber,
'carPrice': this.carPrice,
'carModel': this.carModel,
'carLocation': this.carLocation,
'carColor': this.carColor,
'description': this.description,
'urlImage': this.urlImage,
'imgPro': userImageUrl,
'time': DateTime.now(),
};
carobj.addData(carData).then((value) {
print("data add successfuly");
Navigator.push(context,
MaterialPageRoute(builder: (context) {
return HomeScreen();
}));
}).catchError((onError) {
print(onError);
});
},
child: Text("Add Now"),
),
],
);
});
}
getimage()async{
await carobj.getAdData(carUserId).then((res){
setState(() {
usersImg=(res.data() as Map)['imgPro'].toString();
});
});
}
getMyData() async {
await FirebaseFirestore.instance
.collection('users')
.doc(userId)
.get()
.then((result) {
setState(() {
userImageUrl = result.data()!['imgPro'];
getUsername = result.data()!['username'];
});
});
}
#override
void initState() {
super.initState();
userId = FirebaseAuth.instance.currentUser!.uid;
userEmail = FirebaseAuth.instance.currentUser!.email!;
print("userid is $userId and email is $userEmail");
carobj.getData().then((results) {
setState(() {
cars = results;
});
});
getMyData();
}
#override
Widget build(BuildContext context) {
Widget? showCarsList() {
if (cars != null) {
return ListView.builder(
itemCount: cars!.docs.length,
padding: EdgeInsets.all(8),
itemBuilder: (context,index) {
carUserId= (cars!.docs[index].data() as Map)['uId'];
getimage();
return Card(
child: Column(
children: [
ListTile(
leading:GestureDetector(
onTap: (){},
child: Container(
width: 60,
height:60,
decoration: BoxDecoration(
shape: BoxShape.circle,
image: DecorationImage(
image: NetworkImage(
((usersImg!)),scale: 0.9),
fit:BoxFit.fill
)
),
),
) ,
title: GestureDetector(
onTap: (){
},
child: Text((cars!.docs[index].data() as Map)['username'].toString()),
),
subtitle: GestureDetector(
onTap: (){},
child:
Row(
children: [
((cars!.docs[index].data() as Map)['carLocation'] != null)
? Text((cars!.docs[index].data() as Map)['carLocation'] ,
style:TextStyle(color: Colors.black.withOpacity(0.6))
):Text("unknown" ,
style:TextStyle(color: Colors.black.withOpacity(0.6))
),
SizedBox(width: 4.0,),
Icon(Icons.location_pin,color: Colors.grey,)
],
),
),
trailing:
(cars!.docs[index].data() as Map)['uId']==userId?
Row(
mainAxisSize: MainAxisSize.min,
children: [
GestureDetector(
onTap: (){
},
child: Icon(Icons.edit),
),
SizedBox(width: 20,),
GestureDetector(
onDoubleTap: (){
},
child: Icon(Icons.delete_forever),
),
],
):
Row( mainAxisSize: MainAxisSize.min,
children: [],
)
,
)
],
),
);
},
);
}
}
return Scaffold(
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.refresh, color: Colors.white),
onPressed: () {},
),
actions: [
TextButton(
onPressed: () {},
child: Padding(
padding: EdgeInsets.all(10),
child: Icon(
Icons.person,
color: Colors.white,
),
)),
TextButton(
onPressed: () {},
child: Padding(
padding: EdgeInsets.all(10),
child: Icon(
Icons.search,
color: Colors.white,
),
)),
TextButton(
onPressed: () {},
child: Padding(
padding: EdgeInsets.all(10),
child: Icon(
Icons.login_outlined,
color: Colors.white,
),
))
],
flexibleSpace: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.blueAccent, Colors.redAccent])),
),
title: Text("home page"),
),
body: Center(
child: showCarsList(),
),
floatingActionButton: FloatingActionButton(
tooltip: 'add post',
child: Icon(Icons.add),
onPressed: () {
showDialogForAddingData();
},
),
);
}
}
Where I get image (from home screen code):
getimage()async{
await carobj.getAdData(carUserId).then((res){
setState(() {
usersImg=(res.data() as Map)['imgPro'].toString();
});
});
}
Where I set image to listview (from home screen code):
#override
Widget build(BuildContext context) {
Widget? showCarsList() {
if (cars != null) {
return ListView.builder(
itemCount: cars!.docs.length,
padding: EdgeInsets.all(8),
itemBuilder: (context,index) {
carUserId= (cars!.docs[index].data() as Map)['uId'];
getimage();
return Card(
child: Column(
children: [
ListTile(
leading:GestureDetector(
onTap: (){},
child: Container(
width: 60,
height:60,
decoration: BoxDecoration(
shape: BoxShape.circle,
image: DecorationImage(
image: NetworkImage(
((usersImg!)),scale: 0.9),
fit:BoxFit.fill
)
),
),
) ,
Output of the code:
You're getting the behaviour because you are calling setState in the build method. This causes the build method to get called again and it makes the network request and calls the build method again...
You can fix this by using a FutureBuilder to get the data. Follow these steps:
Update the getimage method to return the image url instead of changing the state:
Future<String> getimage() async {
var res = await carobj.getAdData(carUserId);
return (res.data() as Map)['imgPro'].toString();
}
Declare a variable _imageFuture to hold the result of the getimage network request:
Future<String> _imageFuture;
Assign the getimage method to _imageFuture in the initState:
#override
void initState() {
...
_imageFuture = getimage();
}
Update the ListTile to use a FutureBuilder which gets the image from the _imageFuture Future:
ListTile(
leading:GestureDetector(
onTap: (){},
child: FutureBuilder<String>(
future: _imageFuture,
builder: (context, AsyncSnapshot<String> snapshot) {
if (snapshot.data == null) {
return Center(child: CircularProgressIndicator());
} else {
String usersImg = snapshot.data;
return Container(
width: 60,
height:60,
decoration: BoxDecoration(
shape: BoxShape.circle,
image: DecorationImage(
image: NetworkImage(
((usersImg!)),scale: 0.9),
fit:BoxFit.fill
)
),
),
);
}
}
),
),
)
This question already has an answer here:
Flutter Error: The Method toDouble() was called on null, Tried calling toDouble
(1 answer)
Closed 1 year ago.
I am stuck on the error saying toDouble was called on null. I have checked my code many times and I can't figure out whats happening.
This is the code for bottom_sheet_panel
import 'package:flutter/material.dart';
import 'package:freezeria/Screens/services/database.dart';
import 'package:freezeria/common_code/common.dart';
import 'package:freezeria/common_code/loader.dart';
import 'package:freezeria/req_info/shakes.dart';
import 'package:freezeria/req_info/user.dart';
import 'package:provider/provider.dart';
class bottomSheetPanel extends StatefulWidget {
#override
_bottomSheetPanelState createState() => _bottomSheetPanelState();
}
class _bottomSheetPanelState extends State<bottomSheetPanel> {
final _formkey = GlobalKey<FormState>();
final List<String> blending = ['1', '2', '3', '4', '5'];
final List<String> cupsize = ['Select', 'Small', 'Medium', 'Large'];
final List<String> flavour = [
'Chocolate',
'Vanilla',
'Strawberry',
'Blueberry',
'Raspberry',
'Kiwi',
'Select'
];
final List<String> cream = [
'Whipped',
'Caramel',
'Chocolate',
'Strawberry',
'Select'
];
final List<String> toppings = [
'Oreo',
'Cherry',
'Strawberry',
'Sweet Lime',
'Waffle',
'Blackberries',
'Select'
];
String _currentName;
String _currentCupSize;
int _currentBlend;
String _currentFlavour;
String _currentCream;
String _currentToppings;
#override
Widget build(BuildContext context) {
final receiveUser = Provider.of<User>(context);
return StreamBuilder<UserData>(
stream: Database(uid: receiveUser.uid).userDataStream,
builder: (context, snapshot) {
if (snapshot.hasData) {
UserData recentData = snapshot.data;
return Form(
key: _formkey,
child: SingleChildScrollView(
child: Column(
children: [
Text(
"Update Your Data",
style: TextStyle(fontSize: 20.0),
),
SizedBox(
height: 20.0,
),
TextFormField(
initialValue: recentData.Name,
decoration:
decorationCode.copyWith(hintText: 'Enter your name'),
validator: (val) =>
val.isEmpty ? 'Please enter a name' : null,
onChanged: (val) => setState(() {
return _currentName = val;
}),
),
SizedBox(
height: 20.0,
),
DropdownButtonFormField(
value: _currentCupSize ?? recentData.CupSize,
items: cupsize.map((size) {
return DropdownMenuItem(
value: size,
child: Text('$size Size'),
);
}).toList(),
onChanged: (val) => setState(() {
return _currentCupSize = val;
}),
),
SizedBox(
height: 20.0,
),
Slider(
value: (_currentBlend ?? recentData.Blend).toDouble(),
activeColor:
Colors.grey[_currentBlend ?? recentData.Blend],
inactiveColor:
Colors.grey[_currentBlend ?? recentData.Blend],
min: 100.0,
max: 700.0,
divisions: 6,
onChangeEnd: (val) => setState(() {
return _currentBlend = val.round();
}),
),
SizedBox(
height: 20.0,
),
DropdownButtonFormField(
value: _currentFlavour ?? recentData.Flavour,
items: flavour.map((flav) {
return DropdownMenuItem(
value: flav,
child: Text('$flav Flavour'),
);
}).toList(),
onChanged: (val) => setState(() {
return _currentFlavour = val;
}),
),
SizedBox(
height: 20.0,
),
DropdownButtonFormField(
value: _currentCream ?? recentData.Cream,
items: cream.map((crem) {
return DropdownMenuItem(
value: crem,
child: Text('$crem Cream'),
);
}).toList(),
onChanged: (val) => setState(() {
return _currentCream = val;
}),
),
SizedBox(
height: 20.0,
),
DropdownButtonFormField(
value: _currentToppings ?? recentData.Toppings,
items: toppings.map((top) {
return DropdownMenuItem(
value: top,
child: Text('$top Toppings'),
);
}).toList(),
onChanged: (val) => setState(() {
return _currentToppings = val;
}),
),
SizedBox(
height: 20.0,
),
ElevatedButton(
onPressed: () async {
print(_currentName);
print(_currentBlend);
print(_currentCupSize);
print(_currentFlavour);
print(_currentToppings);
},
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all<Color>(
Colors.purple[300]),
foregroundColor:
MaterialStateProperty.all<Color>(Colors.white),
),
child: Text(
'UPDATE',
style: TextStyle(color: Colors.white),
),
)
],
),
),
);
} else {
Loading();
}
});
}
}
The toDouble() in Slider Function is giving error, also recentData.name is not updating the name in the bottom sheet.
It is seen that _currentBlend and recentData are giving null values, how do I correct it?
Any help will be much appreciated:)
The problem is in this line value: (_currentBlend ?? recentData.Blend).toDouble(),
and the error is saying that you called the toDouble() function on a null object (_currentBlend ?? recentData.Blend) this portion of code giving null so you can not cal toDouble() on it.
Solution: first of all you should make sure that (_currentBlend ?? recentData.Blend) this code must not be null. or you can handle it by using null safety.
try: replace
value: (_currentBlend ?? recentData.Blend).toDouble(), this line with
value: (_currentBlend ?? recentData.Blend)?.toDouble(),
I'm trying to read my UserData into form fields when the user tried to edit their information. I can write to Firebase, but I can't read and display user data into the built fields. Each userData is stored with the signed in user's mid as the userData's id, for distinctiveness.
What am I missing? See below for what I've attempted.
Here's my UserData model:
class UserData {
String id;
String firstName;
String lastName;
String phoneNumber;
String role;
String businessName;
String businessType;
String streetAddress;
String city;
String state;
String postcode;
String country;
String businessTradingCurrency;
Timestamp createdAt;
Timestamp updatedAt;
UserData(
this.id,
this.firstName,
this.businessTradingCurrency,
this.businessType,
this.businessName,
this.city,
this.country,
this.createdAt,
this.lastName,
this.phoneNumber,
this.postcode,
this.role,
this.state,
this.streetAddress,
this.updatedAt,
);
UserData.fromMap(Map<String, dynamic> data) {
id = data['id'];
firstName = data['first_name'];
lastName = data['last_name'];
phoneNumber = data['phone_number'];
businessTradingCurrency = data['trading_currency'];
role = data['role'];
businessName = data['business_name'];
businessType = data['business_type'];
streetAddress = data['street_address'];
city = data['city'];
postcode = data['postcode'];
state = data['state'];
country = data['country'];
createdAt = data['created_at'];
updatedAt = data['updated_at'];
}
Map<String, dynamic> toMap() {
return {
'id': id,
'first_name': firstName,
'last_name': lastName,
'phone_number': phoneNumber,
'role': role,
'trading_currency': businessTradingCurrency,
'business_name': businessName,
'business_type': businessType,
'street_address': streetAddress,
'city': city,
'postcode': postcode,
'state': state,
'country': country,
'created_at': createdAt,
'updated_at': updatedAt,
};
}
}
Here's my UserData notifier class:
class UserDataNotifier with ChangeNotifier {
UserData _currentLoggedInUserData;
CollectionReference userDataRef = Firestore.instance.collection('userData');
UserData get currentLoggedInUserData => _currentLoggedInUserData;
set currentLoggedInUserData(UserData userData) {
_currentLoggedInUserData = userData;
notifyListeners();
}
Future<void> getUserData() async {
String userId = (await FirebaseAuth.instance.currentUser()).uid.toString();
DocumentSnapshot result =
await Firestore.instance.collection('userData').document(userId).get();
_currentLoggedInUserData = result.data as UserData;
print('Phone Number: ${_currentLoggedInUserData.phoneNumber}');
notifyListeners();
}
Future createOrUpdateUserData(UserData userData, bool isUpdating) async {
String userId = (await FirebaseAuth.instance.currentUser()).uid;
if (isUpdating) {
userData.updatedAt = Timestamp.now();
await userDataRef.document(userId).updateData(userData.toMap());
print('updated userdata with id: ${userData.id}');
} else {
userData.createdAt = Timestamp.now();
DocumentReference documentReference = userDataRef.document(userId);
userData.id = documentReference.documentID;
await documentReference.setData(userData.toMap(), merge: true);
print('created userdata successfully with id: ${userData.id}');
}
notifyListeners();
}
}
Here's my Edit User Profile Form:
class ProfileFormScreen extends StatefulWidget {
static const String id = 'profile_form';
#override
_ProfileFormScreenState createState() => _ProfileFormScreenState();
}
class _ProfileFormScreenState extends State<ProfileFormScreen> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
UserData _currentLoggedInUserData;
bool showSpinner = false;
//global declarations
String selectedBusinessTypeDropDownValue = 'Fashion';
String selectedCurrencyDropDownValue = 'AUD: Australian Dollar';
String selectedCountryDropDownValue = 'Australia';
String email;
#override
void initState() {
super.initState();
UserDataNotifier userDataNotifier =
Provider.of<UserDataNotifier>(context, listen: false);
if (userDataNotifier.currentLoggedInUserData != null) {
_currentLoggedInUserData = userDataNotifier.currentLoggedInUserData;
} else {
_currentLoggedInUserData = UserData(
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
);
}
}
#override
Widget build(BuildContext context) {
UserDataNotifier userDataNotifier =
Provider.of<UserDataNotifier>(context, listen: false);
print('Logged in user id: ${_currentLoggedInUserData.id}');
_saveUserData() async {
if (!_formKey.currentState.validate()) {
return;
}
_formKey.currentState.save();
userDataNotifier.createOrUpdateUserData(_currentLoggedInUserData, true);
Navigator.pop(context);
}
return Scaffold(
appBar: AppBar(
title: Text('Edit Profile'),
actions: <Widget>[
FlatButton(
onPressed: () => _saveUserData(),
child: Icon(
FontAwesomeIcons.save,
color: kThemeStyleButtonFillColour,
)),
],
),
body: ModalProgressHUD(
inAsyncCall: showSpinner,
child: SingleChildScrollView(
// padding: EdgeInsets.only(top: 20.0),
child: Form(
autovalidateMode: AutovalidateMode.always,
key: _formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
LabelTextPadding(text: 'Business Information'),
//business name
RegularTextPadding(regText: 'Business Name'),
_buildBusinessName(),
SizedBox(height: 20.0),
//business type
RegularTextPadding(regText: 'Business Type'),
Platform.isIOS
? _buildCupertinoStyleBusinessType(context)
: _buildMaterialStyleBusinessType(context),
//Trading currency
RegularTextPadding(regText: 'Trading Currency'),
Platform.isIOS
? _buildCupertinoStyleTradingCurrency(context)
: _buildMaterialStyleTradingCurrency(context),
//business location
RegularTextPadding(regText: 'Location'),
//address 1
_buildAddress(),
//city
_buildCityField(),
//postcode
_buildPostcode(),
//state
_buildStateField(),
//country
Platform.isIOS
? _buildCupertinoStyleCountry(context)
: _buildMaterialStyleCountry(context),
SizedBox(
height: 20.0,
),
DividerClass(),
SizedBox(
height: 20.0,
),
//Personal information
LabelTextPadding(
text: 'Personal Information',
),
_buildFirstNameField(),
_buildLastNameField(),
_buildPhoneNumberField(),
// _buildEmailField(),
//cancel and save buttons
Padding(
padding: const EdgeInsets.fromLTRB(15.0, 10.0, 15.0, 10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Buttons(
onPressedButton: () {
Navigator.pop(context);
},
buttonLabel: 'Cancel',
buttonColour: kThemeStyleButtonFillColour,
buttonTextStyle: kThemeStyleButton),
SizedBox(
width: 15.0,
),
Buttons(
onPressedButton: () => _saveUserData(),
buttonLabel: 'Save',
buttonColour: kThemeStyleButtonFillColour,
buttonTextStyle: kThemeStyleButton),
],
),
),
],
),
),
),
),
);
}
//business information
Widget _buildBusinessName() {
return Container(
padding: EdgeInsets.all(20.0),
child: TextFormField(
initialValue: _currentLoggedInUserData.businessName,
textAlign: TextAlign.left,
onSaved: (value) {
_currentLoggedInUserData.businessName = value;
},
validator: TextInputFieldValidator.validate,
decoration:
kTextFieldDecoration.copyWith(hintText: 'update business Name'),
),
);
}
//business type - cupertino and material styles
_buildCupertinoStyleBusinessType(BuildContext context) {
return GestureDetector(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(5.0)),
border: Border.all(
color: kThemeStyleButtonFillColour,
width: 1,
)),
padding: const EdgeInsets.fromLTRB(10.0, 12.0, 10.0, 12.0),
margin: EdgeInsets.all(20.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(selectedBusinessTypeDropDownValue),
Icon(
FontAwesomeIcons.caretDown,
color: kThemeStyleButtonFillColour,
),
],
),
),
onTap: () => showModalBottomSheet(
context: context,
builder: (BuildContext builder) {
return Container(
color: Colors.white,
height: MediaQuery.of(context).copyWith().size.height / 4,
child: CupertinoPicker(
magnification: 1.5,
children: List<Widget>.generate(businessType.length, (int index) {
return Center(
child: Text(
businessType[index].toString(),
softWrap: true,
style: TextStyle(fontSize: 15.0),
),
);
}),
itemExtent: 25,
onSelectedItemChanged: (index) {
setState(() {
selectedBusinessTypeDropDownValue = businessType[index];
});
},
),
);
},
),
);
}
_buildMaterialStyleBusinessType(BuildContext context) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5.0),
border: Border.all(
color: kThemeStyleButtonFillColour,
width: 1,
)),
margin: EdgeInsets.all(20.0),
width: MediaQuery.of(context).size.width,
child: Center(
child: DropdownButton(
value: _currentLoggedInUserData.businessType == null
? selectedBusinessTypeDropDownValue
: _currentLoggedInUserData.businessType,
elevation: 15,
iconDisabledColor: kThemeStyleButtonFillColour,
iconEnabledColor: kThemeStyleButtonFillColour,
underline: Container(),
items: businessType
.map(
(businessType) => DropdownMenuItem(
value: businessType, child: Text(businessType)),
)
.toList(),
onChanged: (newValue) {
setState(() {
selectedBusinessTypeDropDownValue = newValue;
_currentLoggedInUserData.businessType = newValue;
});
},
),
),
);
}
//trading currency - cupertino and material styles
_buildCupertinoStyleTradingCurrency(BuildContext context) {
return GestureDetector(
onTap: () => showModalBottomSheet(
context: context,
builder: (BuildContext builder) {
return Container(
color: Colors.white,
height: MediaQuery.of(context).copyWith().size.height / 4,
child: CupertinoPicker(
magnification: 1.5,
children:
List<Widget>.generate(tradingCurrency.length, (int index) {
return Center(
child: Text(
tradingCurrency[index].toString(),
softWrap: true,
style: TextStyle(fontSize: 15.0),
),
);
}),
itemExtent: 25,
onSelectedItemChanged: (index) {
setState(() {
selectedCurrencyDropDownValue = tradingCurrency[index];
});
},
),
);
},
),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(0.5)),
border: Border.all(
color: kThemeStyleButtonFillColour,
width: 1,
)),
padding: const EdgeInsets.fromLTRB(10.0, 12.0, 10.0, 12.0),
margin: EdgeInsets.all(20.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(selectedCurrencyDropDownValue),
Icon(
FontAwesomeIcons.caretDown,
color: kThemeStyleButtonFillColour,
),
],
),
),
);
}
_buildMaterialStyleTradingCurrency(BuildContext context) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5.0),
border: Border.all(
color: kThemeStyleButtonFillColour,
width: 1,
)),
margin: EdgeInsets.all(20.0),
width: MediaQuery.of(context).size.width,
child: Center(
child: DropdownButton(
value: _currentLoggedInUserData.businessType == null
? selectedCurrencyDropDownValue
: _currentLoggedInUserData.businessTradingCurrency,
icon: Icon(
FontAwesomeIcons.caretDown,
color: kThemeStyleButtonFillColour,
),
elevation: 15,
underline: Container(
color: kThemeStyleButtonFillColour,
),
items: tradingCurrency
.map(
(tradingCurrency) => DropdownMenuItem(
value: tradingCurrency, child: Text(tradingCurrency)),
)
.toList(),
onChanged: (newValue) {
setState(() {
selectedCurrencyDropDownValue = newValue;
_currentLoggedInUserData.businessTradingCurrency = newValue;
});
},
),
),
);
}
//address field
_buildAddress() {
return Container(
padding: EdgeInsets.all(20.0),
child: TextFormField(
initialValue: _currentLoggedInUserData.streetAddress,
textAlign: TextAlign.left,
onSaved: (value) {
_currentLoggedInUserData.streetAddress = value;
},
validator: TextInputFieldValidator.validate,
decoration:
kTextFieldDecoration.copyWith(hintText: 'house and street address'),
),
);
}
//city field
_buildCityField() {
return Container(
padding: EdgeInsets.all(20.0),
child: TextFormField(
initialValue: _currentLoggedInUserData.city,
textAlign: TextAlign.left,
onSaved: (value) {
_currentLoggedInUserData.city = value;
},
validator: TextInputFieldValidator.validate,
decoration: kTextFieldDecoration.copyWith(hintText: 'enter city'),
),
);
}
//postcode field
_buildPostcode() {
return Container(
padding: EdgeInsets.all(20.0),
child: TextFormField(
initialValue: _currentLoggedInUserData.postcode,
textAlign: TextAlign.left,
onSaved: (value) {
_currentLoggedInUserData.postcode = value;
},
validator: TextInputFieldValidator.validate,
decoration: kTextFieldDecoration.copyWith(hintText: 'enter postcode'),
),
);
}
//state field
_buildStateField() {
return Container(
padding: EdgeInsets.all(20.0),
child: TextFormField(
initialValue: _currentLoggedInUserData.state,
textAlign: TextAlign.left,
onSaved: (value) {
_currentLoggedInUserData.state = value;
},
validator: TextInputFieldValidator.validate,
decoration: kTextFieldDecoration.copyWith(hintText: 'enter state'),
),
);
}
//country field - cupertino and material styles
_buildCupertinoStyleCountry(BuildContext context) {
return GestureDetector(
onTap: () => showModalBottomSheet(
context: context,
builder: (BuildContext builder) {
return Container(
color: Colors.white,
height: MediaQuery.of(context).copyWith().size.height / 4,
child: CupertinoPicker(
magnification: 1.5,
children: List<Widget>.generate(country.length, (int index) {
return Center(
child: Text(
country[index].toString(),
softWrap: true,
style: TextStyle(fontSize: 15.0),
),
);
}),
itemExtent: 25,
onSelectedItemChanged: (index) {
setState(() {
selectedCountryDropDownValue = country[index];
});
},
),
);
},
),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(0.5)),
border: Border.all(
color: kThemeStyleButtonFillColour,
width: 1,
),
),
padding: const EdgeInsets.fromLTRB(10.0, 12.0, 20.0, 12.0),
margin: EdgeInsets.all(20.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(selectedCountryDropDownValue),
Icon(
FontAwesomeIcons.caretDown,
color: kThemeStyleButtonFillColour,
),
],
),
),
);
}
_buildMaterialStyleCountry(BuildContext context) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5.0),
border: Border.all(
color: kThemeStyleButtonFillColour,
width: 1,
),
),
margin: EdgeInsets.all(20.0),
width: MediaQuery.of(context).size.width,
child: Center(
child: DropdownButton(
value: _currentLoggedInUserData.country == null
? selectedCountryDropDownValue
: _currentLoggedInUserData.country,
elevation: 15,
iconDisabledColor: kThemeStyleButtonFillColour,
iconEnabledColor: kThemeStyleButtonFillColour,
underline: Container(),
items: country
.map(
(country) =>
DropdownMenuItem(value: country, child: Text(country)),
)
.toList(),
onChanged: (newValue) {
setState(() {
selectedCountryDropDownValue = newValue;
_currentLoggedInUserData.country = newValue;
});
},
),
),
);
}
//logged in user personal info build
//first name
_buildFirstNameField() {
return Container(
padding: EdgeInsets.all(20.0),
child: TextFormField(
initialValue: _currentLoggedInUserData.firstName,
textAlign: TextAlign.left,
onSaved: (value) {
_currentLoggedInUserData.firstName = value;
},
validator: TextInputFieldValidator.validate,
decoration: kTextFieldDecoration.copyWith(hintText: 'your first Name'),
),
);
}
//last name
_buildLastNameField() {
return Container(
padding: EdgeInsets.all(20.0),
child: TextFormField(
initialValue: _currentLoggedInUserData.lastName,
textAlign: TextAlign.left,
onSaved: (value) {
_currentLoggedInUserData.lastName = value;
},
validator: TextInputFieldValidator.validate,
decoration: kTextFieldDecoration.copyWith(hintText: 'your last name'),
),
);
}
//phone number
_buildPhoneNumberField() {
return Container(
padding: EdgeInsets.all(20.0),
child: TextFormField(
initialValue: _currentLoggedInUserData.phoneNumber,
textAlign: TextAlign.left,
onSaved: (value) {
_currentLoggedInUserData.phoneNumber = value;
},
validator: TextInputFieldValidator.validate,
decoration:
kTextFieldDecoration.copyWith(hintText: 'your phone number'),
),
);
}
}
class TextInputFieldValidator {
static String validate(String value) {
if (value.isEmpty) {
return 'This field can\'t be empty, you must enter a text';
}
if (value.length < 3) {
return 'You must enter at least a word';
}
return value;
}
}