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
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,
)
],
),
),
),
);
},
),
)
],
),
),
),
);
}
}
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!
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(),
),
),
)
],
),
],
),
),
);
}
}
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'.
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),
// ...
)