How to navigate without context in List widget Flutter - firebase

I am developing a flutter web app in which I have developed custom navbar but I am struggling to add navigation in the navbar items. I've tried Get to navigate without context but unfortunately it isn't working on the list I've created. I did tried to create function and put navigation as required for it but still no luck.
import 'package:animated_text_kit/animated_text_kit.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:get/get.dart';
import 'package:shimmer/shimmer.dart';
import 'package:customweb/about.dart';
double collapsableHeight = 0.0;
Color selected = Color(0xffffffff);
Color notSelected = Color(0xafffffff);
class Nav extends StatefulWidget {
#override
_NavState createState() => _NavState();
}
class _NavState extends State<Nav> {
#override
Widget build(BuildContext context) {
double width = MediaQuery.of(context).size.width;
return SafeArea(
child: Scaffold(
body: Stack(
children: [
Align(
alignment: Alignment.topCenter,
child: Padding(
padding: EdgeInsets.only(top: 250),
child: Image.asset(
"assets/logo.png",
scale: 2,
)),
),
Align(
alignment: Alignment.bottomCenter,
child: Padding(
padding: EdgeInsets.only(bottom: 120),
child: Text(
"Download now available on",
style: TextStyle(fontSize: 30),
))),
Align(
alignment: Alignment.bottomCenter,
child: Padding(
padding: EdgeInsets.only(right: 200, bottom: 50),
child: Image.asset(
"assets/1200px-Google_Play_Store_badge_EN.png",
scale: 8,
))),
Align(
alignment: Alignment.bottomCenter,
child: Padding(
padding: EdgeInsets.only(left: 200, bottom: 50),
child: Image.asset(
"assets/1200px-Download_on_the_App_Store_Badge.png",
scale: 8,
))),
AnimatedContainer(
margin: EdgeInsets.only(top: 79.0),
duration: Duration(milliseconds: 375),
curve: Curves.ease,
height: (width < 800.0) ? collapsableHeight : 0.0,
width: double.infinity,
color: Color(0xff121212),
child: SingleChildScrollView(
child: Column(
children: navBarItems,
),
),
),
Container(
color: Colors.amber,
height: 80.0,
padding: EdgeInsets.symmetric(horizontal: 24.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
AnimatedTextKit(
animatedTexts: [
FadeAnimatedText(
'Get It',
textStyle: TextStyle(fontSize: 26, color: Colors.white),
),
FadeAnimatedText(
'All Amazing Stuff',
textStyle: TextStyle(fontSize: 22, color: Colors.white),
),
FadeAnimatedText(
'One Platform',
textStyle: TextStyle(fontSize: 24, color: Colors.white),
),
FadeAnimatedText(
'Endless Services',
textStyle: TextStyle(fontSize: 24, color: Colors.white),
),
FadeAnimatedText(
'Available Soon',
textStyle: TextStyle(fontSize: 24, color: Colors.white),
),
],
onTap: () {
print("");
},
),
LayoutBuilder(builder: (context, constraints) {
if (width < 800.0) {
return NavBarButton(
onPressed: () {
if (collapsableHeight == 0.0) {
setState(() {
collapsableHeight = 240.0;
});
} else if (collapsableHeight == 240.0) {
setState(() {
collapsableHeight = 0.0;
});
}
},
);
} else {
return Row(
children: navBarItems,
);
}
})
],
),
),
],
),
),
);
}
}
List<Widget> navBarItems = [
NavBarItem(
text: 'About',
onPressed: () {
Get.to(AboutPage());
},
),
NavBarItem(
text: 'Services',
onPressed: () {
Get.to(AboutPage());
},
),
NavBarItem(
text: 'FAQ',
onPressed: () {
Get.to(AboutPage());
},
),
];
class NavBarItem extends StatefulWidget {
final String text;
final Function onPressed;
NavBarItem({
required this.text,
required this.onPressed,
});
#override
_NavBarItemState createState() => _NavBarItemState();
}
class _NavBarItemState extends State<NavBarItem> {
Color color = notSelected;
#override
Widget build(BuildContext context) {
return MouseRegion(
onEnter: (value) {
setState(() {
color = selected;
});
},
onExit: (value) {
setState(() {
color = notSelected;
});
},
child: Material(
color: Colors.transparent,
child: InkWell(
splashColor: Colors.white60,
onTap: () {},
child: Container(
height: 60.0,
alignment: Alignment.centerLeft,
margin: EdgeInsets.symmetric(horizontal: 24.0),
child: Text(
widget.text,
style: TextStyle(
fontSize: 16.0,
color: color,
),
),
),
),
),
);
}
}
class NavBarButton extends StatefulWidget {
final Function onPressed;
NavBarButton({
required this.onPressed,
});
#override
_NavBarButtonState createState() => _NavBarButtonState();
}
class _NavBarButtonState extends State<NavBarButton> {
Widget build(BuildContext context) {
return Container(
height: 55.0,
width: 60.0,
decoration: BoxDecoration(
border: Border.all(
color: Color(0xcfffffff),
width: 2.0,
),
borderRadius: BorderRadius.circular(15.0),
),
child: Material(
color: Colors.transparent,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.0),
),
child: InkWell(
splashColor: Colors.white60,
onTap: () {
setState(() {
widget.onPressed();
});
},
child: Icon(
Icons.menu,
size: 30.0,
color: Color(0xcfffffff),
),
),
),
);
}
}
Any help will be highly appreciated

Hi Asver Seb you are following wrong method. I've recently done a job on flutter web here use my code of navbar/header to build what you are looking for it will do perfectly fine.
class Header extends StatelessWidget {
const Header({
Key? key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.symmetric(vertical: 20, horizontal: 40),
child: Row(
children: <Widget>[
Image.asset(
'assets/images/logo.png',
width: 50,
),
SizedBox(width: 10),
Shimmer.fromColors(
baseColor: Colors.transparent,
highlightColor: Colors.amber,
child: Text(
"Webster",
style: TextStyle(fontSize: 32, fontWeight: FontWeight.w800),
)),
Spacer(),
NavItem(
title: 'Home',
tapEvent: () {
Get.to(HomeScreen());
},
),
NavItem(
title: 'About',
tapEvent: () {
Get.to(About());
},
),
NavItem(
title: 'FAQ',
tapEvent: () {
Get.to(Faq());
},
),
],
),
);
}
}
class NavItem extends StatelessWidget {
const NavItem({Key? key, required this.title, required this.tapEvent})
: super(key: key);
final String title;
final GestureTapCallback tapEvent;
#override
Widget build(BuildContext context) {
return InkWell(
onTap: tapEvent,
hoverColor: Colors.transparent,
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 15),
child: Text(
title,
style: TextStyle(fontWeight: FontWeight.w300),
),
),
);
}
}

Related

How to update the Circular Percentage Indicator once we click each Checkbox List

I want to do the checklist section which have circular percentage indicator. The percentage should updated once the list of checklist(checkbox) is clicked. Each Checkbox should hold 25% because have 4 checklist and the overall percentage is 100. Please help me how to update the percentage.
This is the interface
class ReportForm extends StatefulWidget {
final int itemIndex;
final Project project;
const ReportForm({this.itemIndex, this.project});
#override
State<ReportForm> createState() => _ReportFormState();
}
class _ReportFormState extends State<ReportForm> {
FirebaseFirestore _firebaseFirestore = FirebaseFirestore.instance;
UserModel loggedInUser = UserModel();
double progress = 0.0;
currentProgressColor() {
if (progress >= 0.6 && progress < 0.8) {
return Colors.red;
}
if(progress >= 0.8){
return Colors.green;
}
else{
return Colors.orange;
}
}
final checklist = [
CheckBoxState(title: 'Attendance'),
CheckBoxState(title: 'Equipment Used'),
CheckBoxState(title: 'Work Performed'),
CheckBoxState(title: 'Remarks'),
];
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Container(
height: 650,
width: 370,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(13),
boxShadow: [
BoxShadow(
offset: Offset(0, 1),
blurRadius: 17,
spreadRadius: -23,
color: kShadowColor,
),
],
),
child: Column(
children: <Widget>[
SizedBox(
height:40,
),
CircularPercentIndicator(
radius: 200.0,
circularStrokeCap: CircularStrokeCap.round,
lineWidth: 25.0,
progressColor: currentProgressColor(),
percent: progress,
animation: true,
animationDuration: 1500,
center: new Text("${this.progress * 100}%", style: TextStyle(
fontSize: 30,
),),
footer: new Text("Daily Report Completion",
style: TextStyle(
fontSize: 15,
color: Colors.green,
),),),
SizedBox(
height:20,
),
StreamBuilder<QuerySnapshot>(
stream: _firebaseFirestore.collection("Attendance").snapshots(),
builder: (context, snapshot) {
return GestureDetector(
onTap: () {
Navigator.push(context, MaterialPageRoute(
builder: (context) => Attendance(
),
));
},
child: Card(
clipBehavior: Clip.antiAlias,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(13.0)
),
elevation: 10,
margin: EdgeInsets.fromLTRB(10.0, 2.0, 10.0, 2.0),
child: Container(
color: Colors.white,
width: 350,
height:60,
child: Padding(
padding: const EdgeInsets.all(2.0),
child: buildSingleCheckbox(CheckBoxState(title: 'Attendance')),
),
),
),
);
}
),
SizedBox(
height:18,
),
GestureDetector(
onTap: () {
Navigator.push(context, MaterialPageRoute(
builder: (context) => DetailsForm(project: widget.project, itemIndex: widget.itemIndex),
));
},
child: Card(
clipBehavior: Clip.antiAlias,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(13.0)
),
elevation: 10,
margin: EdgeInsets.fromLTRB(10.0, 2.0, 10.0, 2.0),
child: Container(
color: Colors.white,
width: 350,
height: 60,
child: Padding(
padding: const EdgeInsets.all(2.0),
child: buildSingleCheckbox(CheckBoxState(title: 'Equipment Used')),
),
),
),
),
SizedBox(
height:18,
),
GestureDetector(
onTap: () {
Navigator.push(context, MaterialPageRoute(
builder: (context) => HomeScreen(),
));
},
child: Card(
clipBehavior: Clip.antiAlias,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(13.0)
),
elevation: 10,
margin: EdgeInsets.fromLTRB(10.0, 2.0, 10.0, 2.0),
child: Container(
color: Colors.white,
width: 350,
height: 60,
child: Padding(
padding: const EdgeInsets.all(2.0),
child: buildSingleCheckbox(CheckBoxState(title: 'Work Performed')),
),
),
),
),
SizedBox(
height:18,
),
GestureDetector(
onTap: () {
Navigator.push(context, MaterialPageRoute(
builder: (context) => Remarks(),
));
},
child: Card(
clipBehavior: Clip.antiAlias,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(13.0)
),
elevation: 10,
margin: EdgeInsets.fromLTRB(10.0, 2.0, 10.0, 2.0),
child: Container(
color: Colors.white,
width: 350,
height: 60,
child: Padding(
padding: const EdgeInsets.all(2.0),
child: buildSingleCheckbox(CheckBoxState(title: 'Remarks')),
),
),
),
),
],
),
),
);
}
Widget buildSingleCheckbox(CheckBoxState checkbox) => StatefulBuilder(
builder: (context, _setState) => CheckboxListTile(
activeColor: Colors.green,
value: checkbox.value,
title: Text(checkbox.title),
onChanged: (value) =>
_setState(() => checkbox.value = value),
),
);
}
class CheckBoxState{
final String title;
bool value;
CheckBoxState({
#required this.title,
this.value = false,});
}
I did a small test you can apply according to your need
import 'package:flutter/material.dart';
import 'package:percent_indicator/circular_percent_indicator.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Teste',
debugShowCheckedModeBanner: false,
home: Teste(),
);
}
}
class Teste extends StatefulWidget {
const Teste({Key? key}) : super(key: key);
#override
_TesteState createState() => _TesteState();
}
class _TesteState extends State<Teste> {
List<bool> checkboxStatus = [];
double percentage = 0.0;
final checklist = ['Attendance', 'Equipment Used', 'Work Performed', 'Remarks'];
#override
void initState() {
super.initState();
checklist.forEach((element) => checkboxStatus.add(false));
}
currentProgressColor() {
if (percentage >= 0.6 && percentage < 0.8) {
return Colors.red;
}
if (percentage >= 0.8) {
return Colors.green;
} else {
return Colors.orange;
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Container(
height: 650,
width: 370,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(13),
boxShadow: [BoxShadow(offset: Offset(0, 1), blurRadius: 17, spreadRadius: -23, color: Colors.orange)],
),
child: Column(
children: <Widget>[
SizedBox(height: 40),
CircularPercentIndicator(
animateFromLastPercent: true,
radius: 200.0,
circularStrokeCap: CircularStrokeCap.round,
lineWidth: 25.0,
progressColor: currentProgressColor(),
percent: percentage,
animation: true,
animationDuration: 1500,
center: Text('${percentage * 100} %'),
footer: Text("Daily Report Completion", style: TextStyle(fontSize: 15, color: Colors.green)),
),
SizedBox(height: 20),
Expanded(
child: ListView.builder(
itemCount: checklist.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
clipBehavior: Clip.antiAlias,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(13.0)),
elevation: 10,
child: ElevatedButton(
onPressed: () {
if (checklist[index] == 'Attendance') {
Navigator.push(context, MaterialPageRoute(builder: (context) => Attendance()));
} else if() {
/// other page
}
},
style: ElevatedButton.styleFrom(primary: Colors.white),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(checklist[index], style: TextStyle(color: Colors.black)),
Checkbox(
value: checkboxStatus[index],
onChanged: (value) {
if (checkboxStatus[index] == false) {
percentage += (1 / checklist.length);
} else {
percentage -= (1 / checklist.length);
}
setState(() => checkboxStatus[index] = !checkboxStatus[index]);
},
checkColor: Colors.white,
)
],
),
),
),
);
},
),
)
],
),
),
),
);
}
}

Flutter/Firebase: How to reduce StreamBuilder call on push/pop call?

I have a screen with a bottomNavigationBar:
class AttendantMainPage extends StatefulWidget {
final String? email;
AttendantMainPage({
Key? key,
this.email,
}) : super(key: key);
#override
_AttentdantMainPageState createState() => _AttentdantMainPageState();
}
class _AttentdantMainPageState extends State<AttendantMainPage> {
var user = FirebaseAuth.instance.currentUser;
int _currentIndex = 1;
late final List<Widget> _children;
#override
void initState() {
_children = [
ProfilePage(),
AttendantHomePage(),
ChatListPage(),
];
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: _children[_currentIndex],
bottomNavigationBar: BottomNavigationBar(
backgroundColor: Colors.white,
selectedItemColor: Color(0xffe96cbd),
onTap: onTabPressed,
currentIndex: _currentIndex,
items: [
BottomNavigationBarItem(
icon: new Icon(
CustomIcons.user,
),
label: 'Profile'),
BottomNavigationBarItem(
icon: new Icon(
CustomIcons.home,
),
label: 'Home'),
BottomNavigationBarItem(
icon: new Icon(
Icons.mail,
),
label: 'Messages'),
],
),
);
}
void onTabPressed(int index) {
setState(() {
_currentIndex = index;
});
}
}
And i have streamBuilder in all of the screens. When I'm changing screens my stream builders are being called again and again. It may be really expensive using firebase i guess. Here is code of one of the screens, can someone tell me how to avoid unneccessary calls after switching between pages?
class ProfilePage extends StatefulWidget {
#override
_ProfilePageState createState() => _ProfilePageState();
}
class _ProfilePageState extends State<ProfilePage> {
bool enabled = false;
late FocusNode myFocusNode;
var user = FirebaseAuth.instance.currentUser;
late Stream<DocumentSnapshot> stream;
#override
void initState() {
stream = FirebaseFirestore.instance
.collection('users')
.doc(user!.uid)
.snapshots();
myFocusNode = FocusNode();
super.initState();
}
#override
void dispose() {
// Clean up the focus node when the Form is disposed.
myFocusNode.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
double _width = MyUtility(context).width;
double _height = MyUtility(context).height;
return Scaffold(
backgroundColor: Color(0xfff0eded),
body: SingleChildScrollView(
physics: NeverScrollableScrollPhysics(),
child: Container(
width: _width,
height: _height,
child: Column(
children: [
Stack(
alignment: AlignmentDirectional.topCenter,
children: [
Container(
width: _width,
height: _height * 0.4,
),
Container(
height: _height * 0.25,
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topRight,
end: Alignment.bottomLeft,
colors: [
Color(0xff4d629f),
Color(0xffe96cbd),
],
),
),
),
Positioned(
bottom: _height * 0.02,
child: ProfileImage(
width: _width * 0.5,
height: _height * 0.25,
userEmail: user!.email!,
),
),
Positioned(
right: _width * 0.25,
bottom: _height * 0.05,
child: ClipOval(
child: Container(
color: Colors.white,
child: Padding(
padding: const EdgeInsets.all(2),
child: ClipOval(
child: Material(
color: Color(0xffe96cbd), // button color
child: InkWell(
splashColor: Color(0xffffc2ea), // inkwell color
child: SizedBox(
width: _width * 0.08,
height: _height * 0.04,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Icon(
Icons.edit,
color: Colors.white,
size: MyUtility(context).width * 0.04,
),
)),
onTap: () {
getImage().then((value) {
uploadFile(value);
});
},
),
),
),
),
),
),
),
],
),
Stack(
alignment: AlignmentDirectional.topCenter,
children: [
Padding(
padding: EdgeInsets.symmetric(
vertical: 10,
horizontal: _width * 0.05,
),
child: OverlayPanel(
width: _width * 0.9,
child: Padding(
padding: EdgeInsets.all(
_height * 0.04,
),
child: Column(
children: [
StreamBuilder<DocumentSnapshot>(
stream: stream,
builder: (context, snapshot) {
if (snapshot.hasData) {
return TextFormField(
focusNode: myFocusNode,
enabled: enabled,
initialValue: snapshot.data!['username'],
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 30,
color: Color(0xff273150),
),
onFieldSubmitted: (input) {
setState(() {
enabled = false;
});
print(input);
FirebaseFirestore.instance
.collection('users')
.doc(user!.uid)
.update({'username': input});
},
);
} else
return TextField(
enabled: false,
style: TextStyle(fontSize: 30),
);
}),
SizedBox(
height: _height * 0.02,
),
Text(user!.email!,
style: TextStyle(
fontSize: 18.0,
color: Color(0xff273150),
)),
Text(
//TODO great idea to use currentUser: user!.displayName as a user Type to check it all easier and faster
'Type: ${'Attendant'}',
style: TextStyle(
fontSize: 14.0,
color: Color(0xff273150),
),
),
],
),
),
),
),
Positioned(
right: _width * 0.1,
top: _height * 0.025,
child: ClipOval(
child: Container(
color: Colors.white,
child: Padding(
padding: const EdgeInsets.all(2),
child: ClipOval(
child: Material(
color: Color(0xffe96cbd), // button color
child: InkWell(
splashColor: Color(0xffffc2ea), // inkwell color
child: SizedBox(
width: _width * 0.08,
height: _width * 0.08,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Icon(
Icons.edit,
color: Colors.white,
size: _width * 0.04,
),
)),
onTap: () async {
setState(() {
enabled = !enabled;
});
await Future.delayed(
Duration(milliseconds: 10),
() => {
FocusScope.of(context)
.requestFocus(myFocusNode),
});
},
),
),
),
),
),
),
),
],
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10.0),
child: Container(
width: _width,
decoration: BoxDecoration(
color: Color(0xfff0eded),
),
child: Container(
child: Column(
children: [
CustomButton(
width: _width * 0.9,
icon: Icons.lock,
text: 'Change Password',
onPressed: () {
//TODO add possibility to change password
},
),
CustomButton(
width: _width * 0.9,
icon: Icons.delete,
text: 'Delete Account',
onPressed: () {},
),
CustomButton(
width: _width * 0.9,
icon: Icons.logout,
text: 'Log Out',
onPressed: () async {
await FirebaseAuth.instance.signOut();
Navigator.pop(context);
},
),
],
),
),
),
),
],
),
),
),
);
}
}
Changing body in my AttendantMainPage from:
body: _children[_currentIndex],
to
body: IndexedStack(
index: _currentIndex,
children: _children,
),
Solved the problem.
Thanks for help guys!

How to display image after using Image Picker and Cropper using GetX in Flutter?

I'm using GetX to get the path of Image after the image is cropped and storing it in an RXString on one page:
RxString imageAdd = '$imagePath'.obs;
Then I'm retrieving the Path of the image on another page using:
Obx(
() => Image(
image: AssetImage(
(pollImageController.imageAdd.value)),
But the image is not displaying on the second page.
Complete Code:
ImagePickerCropper Page:
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:justpoll/Constants.dart';
import 'package:image_cropper/image_cropper.dart';
import 'package:image_picker/image_picker.dart';
import 'dart:io';
import 'package:justpoll/screens/create_poll/create_poll4.dart';
String imagePath;
class CreatePoll3 extends StatefulWidget {
#override
_CreatePoll3State createState() => _CreatePoll3State();
}
class _CreatePoll3State extends State<CreatePoll3> {
final controller = Get.put(PollImageController());
File _selectedFile;
bool _inProcess = false;
final _picker = ImagePicker();
Widget getImageWidget() {
if (_selectedFile != null) {
return Image.file(
_selectedFile,
width: 370,
height: 230,
fit: BoxFit.cover,
);
} else {
return Padding(
padding: const EdgeInsets.only(bottom: 20),
child: Image.asset(
"assets/Images/placeholder.png",
width: 370,
height: 230,
fit: BoxFit.cover,
),
);
}
}
getImage(ImageSource source) async {
this.setState(() {
_inProcess = true;
});
PickedFile image = await _picker.getImage(source: source);
if (image != null) {
File cropped = await ImageCropper.cropImage(
sourcePath: image.path,
aspectRatio: CropAspectRatio(ratioX: 2, ratioY: 1.5),
compressQuality: 100,
maxWidth: 700,
maxHeight: 700,
compressFormat: ImageCompressFormat.jpg,
androidUiSettings: AndroidUiSettings(
toolbarColor: Colors.white,
toolbarTitle: "Crop Image",
statusBarColor: Colors.black,
backgroundColor: Colors.white,
));
imagePath = cropped.path;
print(imagePath);
this.setState(() {
_selectedFile = cropped;
_inProcess = false;
});
} else {
this.setState(() {
_inProcess = false;
});
}
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
backgroundColor: MyColors.white,
appBar: AppBar(
title: Padding(
padding: const EdgeInsets.all(75.0),
child: Text('New Poll'),
),
leading: GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: Icon(
Icons.arrow_back,
),
),
backgroundColor: Colors.black87,
),
body: ListView(
children: [
Column(
children: [
Center(
child: Padding(
padding: const EdgeInsets.only(top: 18, bottom: 28),
child: Text("3/4"),
),
),
// Padding(
// padding: const EdgeInsets.only(right: 230.0, top: 30, bottom: 30),
// child: Text(
// "Add Image",
// style: TextType.regularDarkText,
// ),
// ),
getImageWidget(),
Padding(
padding: const EdgeInsets.only(top: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
MaterialButton(
onPressed: () {
getImage(ImageSource.camera);
},
color: Colors.black,
textColor: Colors.white,
child: Icon(
Icons.camera,
size: 24,
),
padding: EdgeInsets.all(16),
shape: CircleBorder(),
),
MaterialButton(
onPressed: () {
getImage(ImageSource.gallery);
},
color: Colors.black,
textColor: Colors.white,
child: Icon(
Icons.photo_album,
size: 24,
),
padding: EdgeInsets.all(16),
shape: CircleBorder(),
),
Align(
alignment: Alignment.bottomRight,
child: MaterialButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => CreatePoll4(),
),
);
},
color: Colors.black,
textColor: Colors.white,
child: Icon(
Icons.arrow_forward,
size: 24,
),
padding: EdgeInsets.all(16),
shape: CircleBorder(),
),
)
],
),
),
(_inProcess)
? Container(
color: Colors.white,
height: MediaQuery.of(context).size.height * 0.95,
child: Center(
child: CircularProgressIndicator(),
),
)
: Center()
],
),
],
),
),
);
}
}
class PollImageController extends GetxController {
RxString imageAdd = '$imagePath'.obs;
// adding .obs makes this a stream based observable String
// this onInit override can be used instead of initState in a stateful widget.
// All text editing controllers can be initialized here
#override
void onInit() {
super.onInit();
}
#override
void onClose() {
super.onClose();
}
}
Image Display Page:
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:justpoll/Constants.dart';
import 'package:justpoll/screens/home_page/nav.dart';
import 'create_poll1_static.dart';
import 'create_poll3.dart';
final pollDataController = Get.find<PollDataController>();
final pollImageController = Get.find<PollImageController>();
// final _questionController = pollDataController.questionController;
class CreatePoll4 extends StatefulWidget {
#override
_CreatePoll4State createState() => _CreatePoll4State();
}
class _CreatePoll4State extends State<CreatePoll4> {
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
backgroundColor: MyColors.white,
appBar: AppBar(
title: Padding(
padding: const EdgeInsets.all(75.0),
child: Text('Poll Preview'),
),
leading: GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: Icon(
Icons.arrow_back,
),
),
backgroundColor: Colors.black87,
),
body: ListView(
children: [
Column(
children: [
Center(
child: Padding(
padding: const EdgeInsets.only(top: 18, bottom: 28),
child: Text("4/4"),
),
),
Padding(
padding: const EdgeInsets.only(right: 240, top: 10),
child: Text(
'Select Theme',
style: TextType.regularDarkText,
),
),
Padding(
padding: const EdgeInsets.only(top: 10),
child: Row(
children: [
Expanded(
child: MaterialButton(
onPressed: () {},
color: Colors.yellow,
textColor: Colors.white,
shape: CircleBorder(),
),
),
Expanded(
child: MaterialButton(
onPressed: () {},
color: Colors.orange,
textColor: Colors.white,
shape: CircleBorder(),
),
),
Expanded(
child: MaterialButton(
onPressed: () {},
color: Colors.brown,
textColor: Colors.white,
shape: CircleBorder(),
),
),
Expanded(
child: MaterialButton(
onPressed: () {},
color: Colors.blue,
textColor: Colors.white,
shape: CircleBorder(),
),
),
Expanded(
child: MaterialButton(
onPressed: () {},
color: Colors.green,
textColor: Colors.white,
shape: CircleBorder(),
),
),
Expanded(
child: MaterialButton(
onPressed: () {},
color: Colors.black,
textColor: Colors.white,
shape: CircleBorder(),
),
),
],
),
),
Card(
child: Container(
color: Colors.blue,
child: Padding(
padding: const EdgeInsets.only(bottom: 10),
child: Column(
children: [
Row(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: CircleAvatar(
backgroundImage:
AssetImage('assets/Images/blackLogo.png'),
),
),
Padding(
padding: const EdgeInsets.only(left: 10),
child: Text('JustPoll'),
),
],
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Obx(
() => Text(pollDataController.question.value),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Obx(
() => Image(
image: AssetImage(
(pollImageController.imageAdd.value)),
height: 150,
width: 200,
),
),
),
Row(
children: [
Padding(
padding:
const EdgeInsets.only(left: 120, top: 20),
child: Obx(
() => Text(pollDataController.op1.value),
),
),
SizedBox(
width: 70,
),
Padding(
padding:
const EdgeInsets.only(left: 10, top: 20),
child: Obx(
() => Text(pollDataController.op1Emoji.value),
),
),
],
),
Row(
children: [
Padding(
padding:
const EdgeInsets.only(left: 120, top: 20),
child: Obx(
() => Text(pollDataController.op2.value),
),
),
SizedBox(
width: 70,
),
Padding(
padding:
const EdgeInsets.only(left: 10, top: 20),
child: Obx(
() => Text(pollDataController.op2Emoji.value),
),
),
],
),
Row(
children: [
Padding(
padding:
const EdgeInsets.only(left: 120, top: 20),
child: Obx(
() => Text(pollDataController.op3.value),
),
),
SizedBox(
width: 70,
),
Padding(
padding:
const EdgeInsets.only(left: 10, top: 20),
child: Obx(
() => Text(pollDataController.op3Emoji.value),
),
),
],
),
Row(
children: [
Padding(
padding:
const EdgeInsets.only(left: 120, top: 20),
child: Obx(
() => Text(pollDataController.op4.value),
),
),
SizedBox(
width: 70,
),
Padding(
padding:
const EdgeInsets.only(left: 10, top: 20),
child: Obx(
() => Text(pollDataController.op4Emoji.value),
),
),
],
),
],
),
),
),
),
Padding(
padding: const EdgeInsets.only(top: 10),
child: Align(
alignment: Alignment.bottomRight,
child: MaterialButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Nav(),
),
);
},
color: Colors.black,
textColor: Colors.white,
child: Icon(
Icons.done,
size: 24,
),
padding: EdgeInsets.all(16),
shape: CircleBorder(),
),
),
)
],
),
],
),
),
);
}
}

Firebase Failed assertion: line 380 pos 10: 'data != null'

import 'package:flutter/material.dart';
import 'package:flutter_myapp/AllWidgets/Divider.dart';
import 'package:flutter_myapp/AllWidgets/progressDialog.dart';
import 'package:flutter_myapp/Assistants/requestAssistant.dart';
import 'package:flutter_myapp/DataHandler/appData.dart';
import 'package:flutter_myapp/Models/address.dart';
import 'package:flutter_myapp/Models/placePredictions.dart';
import 'package:flutter_myapp/configMaps.dart';
import 'package:provider/provider.dart';
class SearchScreen extends StatefulWidget {
#override
_SearchScreenState createState() => _SearchScreenState();
}
class _SearchScreenState extends State<SearchScreen>
{
TextEditingController pickUpTextEditingController = TextEditingController();
TextEditingController dropOffTextEditingController = TextEditingController();
List<PlacePredictions> placePredictionList = [];
#override
Widget build(BuildContext context)
{
String placeAddress = Provider.of<AppData>(context).pickUpLocation.placeName ?? "";
pickUpTextEditingController.text = placeAddress;
return Scaffold(
body: Column(
children: [
Container(
height: 215.0,
decoration: BoxDecoration(
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.black,
blurRadius: 6.0,
spreadRadius: 0.5,
offset: Offset(0.7, 0.7),
),
],
),
child: Padding(
padding: EdgeInsets.only(left: 25.0, top: 25.0, bottom: 20.0),
child: Column(
children: [
SizedBox(height: 5.0),
Stack(
children: [
GestureDetector(
onTap:()
{
Navigator.pop(context);
},
child: Icon(
Icons.arrow_back
),
),
Center(
child: Text("Set Drop Off", style: TextStyle(fontSize: 18.0, fontFamily: "Brand Bold"),),
)
],
),
SizedBox(height: 16.0),
Row(
children: [
Image.asset("images/pickicon.png", height: 16.0, width: 16.0,),
SizedBox(width: 18.0,),
Expanded(
child: Container(
decoration: BoxDecoration(
color: Colors.grey[400],
borderRadius: BorderRadius.circular(5.0),
),
child: Padding(
padding: EdgeInsets.all(3.0),
child: TextField(
controller: pickUpTextEditingController,
decoration: InputDecoration(
hintText: "PickUp Location",
fillColor: Colors.grey[400],
filled: true,
border: InputBorder.none,
isDense: true,
contentPadding: EdgeInsets.only(left: 11.0, top: 8.0, bottom: 8.0),
),
),
),
),
),
],
),
SizedBox(height: 10.0),
Row(
children: [
Image.asset("images/desticon.png", height: 16.0, width: 16.0,),
SizedBox(width: 18.0,),
Expanded(
child: Container(
decoration: BoxDecoration(
color: Colors.grey[400],
borderRadius: BorderRadius.circular(5.0),
),
child: Padding(
padding: EdgeInsets.all(3.0),
child: TextField(
onChanged: (val)
{
findPlace(val);
},
controller: dropOffTextEditingController,
decoration: InputDecoration(
hintText: "Where to? ",
fillColor: Colors.grey[400],
filled: true,
border: InputBorder.none,
isDense: true,
contentPadding: EdgeInsets.only(left: 11.0, top: 8.0, bottom: 8.0),
),
),
),
),
),
],
),
],
),
),
),
//tile for predictions
SizedBox(height: 10.0,),
(placePredictionList.length > 0)
?Padding(
padding: EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0),
child: ListView.separated(
padding: EdgeInsets.all(0.0),
itemBuilder: (context, index)
{
return PredictionTile(placePredictions: placePredictionList[index],);
},
separatorBuilder: (BuildContext context, int index) => DividerWidget(),
itemCount: placePredictionList.length,
shrinkWrap: true,
physics: ClampingScrollPhysics(),
),
)
:Container(),
],
),
);
}
void findPlace(String placeName) async
{
if(placeName.length > 1)
{
String autoCompleteUrl = "https://maps.googleapis.com/maps/api/place/autocomplete/json?input=$placeName&key=$mapKey&sessiontoken=1234567890&components=country:us";
var res = await RequestAssistant.getRequest(autoCompleteUrl);
if(res == "failed")
{
return;
}
//print("Places Predictions Response :: ");
//print(res);
if(res["status"] == "OK")
{
var predictions = res["predictions"];
var placeList = (predictions as List).map((e) => PlacePredictions.fromJson(e)).toList();
setState(() {
placePredictionList = placeList;
});
}
}
}
}
class PredictionTile extends StatelessWidget
{
final PlacePredictions placePredictions;
PredictionTile({Key key,this.placePredictions}) : super(key: key);
#override
Widget build(BuildContext context)
{
return FlatButton(
padding: EdgeInsets.all(0.0),
onPressed: ()
{
getPlaceAddressDetails(placePredictions.place_id, context);
},
child: Container(
child: Column(
children: [
SizedBox(width: 10.0,),
Row(
children: [
Icon(Icons.add_location),
SizedBox(width: 14.0,),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 8.0,),
Text(placePredictions.main_text, overflow: TextOverflow.ellipsis, style: TextStyle(fontSize: 16.0),),
SizedBox(height: 2.0,),
Text(placePredictions.secondary_text, overflow: TextOverflow.ellipsis, style: TextStyle(fontSize: 12.0, color: Colors.grey),),
SizedBox(height: 8.0,),
],
),
),
],
),
SizedBox(width: 10.0,),
],
),
),
);
}
void getPlaceAddressDetails(String placeId, context) async
{
showDialog(
context: context,
builder: (BuildContext context) => ProgressDialog(message: "Setting Drop off, Please wait....",),
);
String placeDetailsUrl = "https://maps.googleapis.com/maps/api/place/details/json?place_id=$placeId&key=$mapKey";
var res = await RequestAssistant.getRequest(placeDetailsUrl);
Navigator.pop(context);
if(res == "failed")
{
return;
}
if(res["status"] == "OK")
{
Address address = Address();
address.placeName = res["result"]["name"];
address.placeId = placeId;
address.latitude = res["result"]["geometry"]["location"]["lat"];
address.longitude = res["result"]["geometry"]["location"]["lng"];
Provider.of<AppData>(context, listen: false).updateDropOffLocationAddress(address);
print("This is Drop Off Location :: ");
print(address.placeName);
Navigator.pop(context, "obtainDirection");
}
}
}
Please help me, I can't understand what's wrong.
I keep getting this error.
Exception caught by widgets library:
The following assertion was thrown building PredictionTile(dirty): A
non-null String must be provided to a Text widget.
'package:flutter/src/widgets/text.dart': Failed assertion: line 380
pos 10: 'data != null'
The Text Widget cannot contain null data, the error relies in the following lines:
Text(placePredictions.main_text, overflow: TextOverflow.ellipsis, style: TextStyle(fontSize: 16.0),),
Text(placePredictions.secondary_text, overflow: TextOverflow.ellipsis, style: TextStyle(fontSize: 12.0, color: Colors.grey),),
To fix it, we could change them to:
Text(placePredictions.main_text ?? 'n/a', overflow: TextOverflow.ellipsis, style: TextStyle(fontSize: 16.0),),
Text(placePredictions.secondary_text ?? 'n/a', overflow: TextOverflow.ellipsis, style: TextStyle(fontSize: 12.0, color: Colors.grey),),
That replaces the null data with 'n/a'.

The getter 'imgUrl' was called on null

I want to get the value of (profile.imgUrl) from Firestore but I get error:
The getter 'imgUrl' was called on null.
Receiver: null
Tried calling: imgUrl
Although the user is signed in and I can get the data in the home page but when I navigate to Account page it gives me this error.
class Account extends StatelessWidget {
final Profile profile;
Account({this.profile});
final AuthService _auth = AuthService();
#override
Widget build(BuildContext context) {
print(profile.imgUrl);
return StreamProvider<List<Profile>>.value(
value: DatabaseService().profiles,
child: Scaffold(
body: Stack(
children: <Widget>[
ClipPath(
child: Container(
color: Colors.green.withOpacity(0.8),
),
clipper: getClipper(),
),
Positioned(
width: 400,
top: MediaQuery.of(context).size.height / 5,
child: Column(
children: <Widget>[
Container(
width: 150.0,
height: 150.0,
decoration: BoxDecoration(
color: Colors.green,
image: DecorationImage(
image: NetworkImage(profile.imgUrl),
fit: BoxFit.cover),
borderRadius: BorderRadius.all(Radius.circular(75.0)),
boxShadow: [
BoxShadow(blurRadius: 7.0, color: Colors.black)
]),
),
SizedBox(
height: 90.0,
),
Text(
'Alex Ali',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 30.0,
fontFamily: 'Montserrat',
letterSpacing: 1.5),
),
SizedBox(
height: 15.0,
),
Text(
'New Seller',
style: TextStyle(
fontStyle: FontStyle.italic,
fontSize: 17.0,
color: Colors.green),
),
SizedBox(
height: 25,
),
Container(
height: 30.0,
width: 95.0,
child: Material(
borderRadius: BorderRadius.circular(20.0),
shadowColor: Colors.greenAccent,
color: Colors.green,
elevation: 7.0,
child: GestureDetector(
onTap: () {
print(profile.imgUrl);
},
child: Center(
child: Text(
'Edit Name',
style: TextStyle(color: Colors.white),
),
),
),
),
),
SizedBox(
height: 25,
),
Container(
height: 30.0,
width: 95.0,
child: Material(
borderRadius: BorderRadius.circular(20.0),
shadowColor: Colors.redAccent,
color: Colors.red,
elevation: 7.0,
child: GestureDetector(
onTap: () async {
await _auth.signOut();
},
child: Center(
child: Text(
'Log out',
style: TextStyle(color: Colors.white),
),
),
),
),
)
],
),
)
],
)
),
);
}
}
class getClipper extends CustomClipper<Path> {
#override
Path getClip(Size size) {
var path = new Path();
path.lineTo(0.0, size.height / 1.9);
path.lineTo(size.width + 125, 0.0);
path.close();
return path;
}
#override
bool shouldReclip(CustomClipper<Path> oldClipper) {
return true;
}
}
and that is Home page code:
class Home extends StatefulWidget {
#override
_Home createState() => _Home();
}
class _Home extends State<Home> {
final AuthService _auth = AuthService();
#override
Widget build(BuildContext context) {
return StreamProvider<List<Profile>>.value(
value: DatabaseService().profiles,
child: Scaffold(
body: SafeArea(
child: ListView(
padding: EdgeInsets.symmetric(vertical: 30.0),
children: <Widget>[
Padding(
padding: EdgeInsets.only(left: 20.0, right: 120.0),
child: Text(
"What would you like to find?",
style: TextStyle(fontSize: 30, fontWeight: FontWeight.bold),
),
),
SizedBox(height: 20.0),
SizedBox(
height: 20.0,
),
SizedBox(height: 500, child: ProfileList()),
],
),
),
),
);
}
}
Here is the code that opens Account page through BottomNavigationBar:
class Wrapper extends StatefulWidget {
#override
_WrapperState createState() => _WrapperState();
}
class _WrapperState extends State<Wrapper> {
int _currentTab = 0;
final _page = [
Home(),
Search(),
Account(),
];
#override
Widget build(BuildContext context) {
final user = Provider.of<User>(context);
print(user);
if (user == null) {
return Authenticate();
} else {
return Scaffold(
body: _page[_currentTab],
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentTab,
onTap: (int value) {
setState(() {
_currentTab = value;
});
},
items: [
BottomNavigationBarItem(
icon: Icon(
Icons.home,
size: 30.0,
),
title: SizedBox.shrink()),
BottomNavigationBarItem(
icon: Icon(
Icons.search,
size: 30.0,
),
title: SizedBox.shrink()),
BottomNavigationBarItem(
icon: Icon(
Icons.person,
size: 30.0,
),
title: SizedBox.shrink(),
)
]),
);
}
}
}
You need to pass a Profile as a parameter when Account is created.
That should be done dynamically, so you can't use a fixed list.
Instead of doing this:
final _page = [
Home(),
Search(),
Account(),
];
Scaffold(
body: _page[_currentTab],
// ...
)
You should do something like this:
Widget _getPage(int pos, user User) {
switch (pos) {
case 0:
return Home();
case 1:
return Search();
case 2:
return Account(user.profile); // Assuming profile is a member of user
default:
return Container();
}
}
Scaffold(
body: _getPage(_currentTab, user),
// ...
)

Resources