I have an app that makes a post request to an API with data about drivers and orders. The initial page displays a list of drivers in individual list tiles. The list tile has a drop down option. Clicking on that option brings you to a new page with a list view of orders for that driver. Clicking on an individual order brings you to a form. On submitting and validating this form, I want to change the color of that orders text from red to green. Each Order has a submitted flag, and when it submits I would want to change that to true and then have the color change. When all the orders are green within an List View, I want the color of that driver to turn green. I've been going over riverpod tutorials and documentation but can't quite figure out how to get this done. Can someone point me in the right direction?
main.dart
void main() {
runApp(ProviderScope(child: MyApp()));
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
debugShowCheckedModeBanner: false,
home: DriversPage(),
);
}
}
drivers.dart - This is where the drivers are displayed
class DriversPage extends StatelessWidget {
final HttpService httpService = HttpService();
var colorChoice = Colors.red;
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xFFFAFAFA),
appBar: AppBar(
title: Text("Drivers")
),
body: Container(
child: FutureBuilder(
future: httpService.getOrders(),
builder: (BuildContext context, AsyncSnapshot<List<Order>> snapshot) {
if (snapshot.hasData) {
List<Order> orders = snapshot.data;
return ListView(
children: orders.map((Order order) => Card(child: ExpansionTile(
title: Text(order.driver, style: TextStyle(color: colorChoice),),
children: <Widget>[
Container(
alignment: Alignment.center,
margin: EdgeInsets.all(10.0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(2.0),
border: Border.all(color: Colors.black26)
),
child: ListTile(title: Text("Orders"),
trailing: Icon(Icons.keyboard_arrow_right),
onTap: () => Navigator.of(context).push(MaterialPageRoute(builder: (context) => OrdersState(driverName: order.driver, driverOrders: order.orders))),),
),
],
))).toList(),
);
}
return Center(child: CircularProgressIndicator());
}),
));
}
}
orders.dart - This is where the orders for a driver are displayed. I originally had it as a stateful widget but turned it into a Consumer Widget and took an attempt at making a provider but was lost on how to handle it in a listview like this. As you can see here I am using the ternary operator for the text color based on item.submitted
final driverListProvider = StateNotifierProvider((ref) => new DriverListTest());
class OrdersState extends ConsumerWidget {
final String driverName;
final List<OrderElement> driverOrders;
const OrdersState({Key key, this.driverName, this.driverOrders}) : super(key: key);
#override
Widget build(BuildContext context, ScopedReader watch) {
return Scaffold(
appBar: AppBar(
title: Text(driverName),
),
body: ListView.builder(
itemCount: driverOrders.length,
itemBuilder: (context, index){
final item = driverOrders[index];
return Card(
key: UniqueKey(),
child: ListTile(title: Text(item.order, style: TextStyle(color: item.submitted? Colors.green : Colors.red),),
subtitle: Text('${item.company}\n${item.address}'),
onTap: () => Navigator.of(context).push(MaterialPageRoute(builder: (context) => OrderForm(orderTitle: item.order,))),));
}),
);
}
}
orderform.dart - Only showing one field for the form, figured the rest was not neccessary, just need to show what happens on submit.
class OrderForm extends StatefulWidget {
final String orderTitle;
const OrderForm({this.orderTitle});
#override
_OrderFormState createState() => _OrderFormState();
}
class _OrderFormState extends State<OrderForm> {
#override
final _formKey = GlobalKey<FormState>();
final _orderModel = Order();
List<String> _pickerNames = ['Loader 1', 'Loader 2', 'Loader 3', 'Loader 4'];
String _selectedPickedBy;
String _selectedCheckedBy;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(backgroundColor: Colors.blueGrey,title: Center(
child: Text(widget.orderTitle),
),),
floatingActionButton: FloatingActionButton(
child: Icon(
Icons.delete
),
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
scrollable: true,
title: Text('Login'),
content: Padding(
padding: const EdgeInsets.all(8.0),
child: Form(
child: Column(
children: <Widget>[
TextFormField(
decoration: InputDecoration(
labelText: 'Reason',
icon: Icon(Icons.account_box),
),
),
TextFormField(
decoration: InputDecoration(
labelText: 'Reason 1',
icon: Icon(Icons.email),
),
),
TextFormField(
decoration: InputDecoration(
labelText: 'Reason 2',
icon: Icon(Icons.message),
),
),
],
),
),
),
actions: [
RaisedButton(
child: Text("Submit"),
onPressed: () {
})
],
);
});
}
),
body: Container(
padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 16.0),
child: Builder(
builder: (context) => Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
DropdownButtonFormField(
isExpanded: true,
hint: Text('Picked By'),
value: _selectedPickedBy,
onChanged: (newValue){
setState(() {
_selectedPickedBy = newValue;
});
},
validator: (value) => value == null
? 'Picked By Required' : null,
items: _pickerNames.map((picker) {
return DropdownMenuItem(
child: new Text(picker),
value: picker,
);
}).toList(),
onSaved: (value) => setState(() => _orderModel.pickedBy = value) ,
),
Container(
padding: const EdgeInsets.symmetric(
vertical: 16.0, horizontal: 16.0
),
child: RaisedButton(
onPressed: (){
final form = _formKey.currentState;
if (form.validate()){
form.save();
Navigator.pop(context,);
}
},
child: Text("Submit"),
),
)
],
)),
),
)
);
}
}
ordermodel.dart - This is the model for the drivers and orders when making http requests to my api. At the bottom you can see where I attempt at making a statenotifier and what I'm trying to with accepting a list of OrderElement(The list of orders).
List<Order> orderFromJson(String str) => List<Order>.from(json.decode(str).map((x) => Order.fromJson(x)));
String orderToJson(List<Order> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class Order {
Order({
this.driver,
this.orders,
});
String driver;
List<OrderElement> orders;
factory Order.fromJson(Map<String, dynamic> json) => Order(
driver: json["Driver"],
orders: List<OrderElement>.from(json["Orders"].map((x) => OrderElement.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"Driver": driver,
"Orders": List<dynamic>.from(orders.map((x) => x.toJson())),
};
}
class OrderElement {
OrderElement({
this.order,
this.company,
this.address,
this.submitted,
this.index,
});
String order;
String company;
String address;
bool submitted;
num index;
factory OrderElement.fromJson(Map<String, dynamic> json) => OrderElement(
order: json["Order"],
company: json["Company"],
address: json["Address"],
submitted: json["submitted"],
index: json["index"]
);
Map<String, dynamic> toJson() => {
"Order": order,
"Company": company,
"Address": address,
};
}
class DriverListTest extends StateNotifier<List<OrderElement>> {
DriverListTest([List<OrderElement> drivers1]) : super(drivers1 ?? []);
void onSubmit(num index) {
state = [
for(final currentOrder in state)
if (currentOrder.index == index)
OrderElement(
order: currentOrder.order,
company: currentOrder.company,
address: currentOrder.address,
submitted: !currentOrder.submitted,
index: currentOrder.index,
)
else
currentOrder,
];
}
}
Don't know if my Http class is necessary but let me know if it is. I tried following https://www.refactord.com/guides/riverpod-state-management-explained and How to set the state of a widget at an index in a listview.builder in flutter how to handle individual widgets but again I just got lost. Any help would be greatly appreciated! Thanks in advance.
Related
I am trying to toggle between Login Screen and HomeScreen based on the user status. The logic seems to be working as long as I don't put HomeScreen.
I replaced HomeScreen with a different screen to check and the app works as it should. It displays different screens on hot restart based on the user's login status. But as soon as I try to put HomeScreen I get null operator used on null value error.
Here is the toggle logic.
class Testing extends StatefulWidget {
const Testing({super.key});
#override
State<Testing> createState() => _TestingState();
}
class _TestingState extends State<Testing> {
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: TodoServiceHelper().checkifLoggedIn(),
builder: ((context, snapshot) {
if (!snapshot.hasData) {
return Container(
child: Center(
child: CircularProgressIndicator(),
),
);
}
if (snapshot.hasError) {
print(snapshot.hasError);
return Container(
child: Center(
child: CircularProgressIndicator(),
),
);
}
if (snapshot.data!.isNotEmpty) {
print(snapshot.data);
return RegisterPage();
// returning HomePage gives null check operator used on null value error
} else
return Login();
}),
);
}
}
Here is the HomeScreen
class HomePage extends StatefulWidget {
String? username;
HomePage({this.username});
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
final GlobalKey<FormState> formKey = GlobalKey();
TextEditingController termController = TextEditingController();
void clearText() {
termController.clear();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: <Widget>[
IconButton(
onPressed: () {
User loginUser =
User(username: widget.username.toString(), isLoggedIn: false);
TodoServiceHelper().updateUserName(loginUser);
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (BuildContext context) => Login()));
},
icon: Icon(Icons.logout),
color: Colors.white,
)
],
title: FutureBuilder(
future: TodoServiceHelper().getTheUser(widget.username!),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Container(
child: Center(
child: CircularProgressIndicator(),
),
);
}
return Text(
'Welcome ${snapshot.data!.username}',
style: TextStyle(color: Colors.white),
);
}),
),
body: SingleChildScrollView(
child: Column(children: [
Column(
children: [
Padding(
padding: const EdgeInsets.all(12.0),
child: Form(
key: formKey,
child: Column(
children: <Widget>[
TextFormField(
controller: termController,
decoration: InputDecoration(
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(),
labelText: 'search todos',
),
),
TextButton(
onPressed: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ShowingSerachedTitle(
userNamee: widget.username!,
searchTerm: termController.text,
)),
);
print(termController.text);
clearText();
setState(() {});
},
child: Text(
'Search',
)),
Divider(
thickness: 3,
),
],
),
),
),
],
),
Container(
child: Stack(children: [
Positioned(
bottom: 0,
child: Text(
' done Todos',
style: TextStyle(fontSize: 12),
),
),
IconButton(
onPressed: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
CheckingStuff(userNamee: widget.username!)),
);
setState(() {});
},
icon: Icon(Icons.filter),
),
]),
),
Divider(
thickness: 3,
),
Container(
child: TodoListWidget(name: widget.username!),
height: 1000,
width: 380,
)
]),
),
floatingActionButton: FloatingActionButton(
backgroundColor: Color.fromARGB(255, 255, 132, 0),
onPressed: () async {
await showDialog(
barrierDismissible: false,
context: context,
builder: ((context) {
return AddNewTodoDialogue(name: widget.username!);
}),
);
setState(() {});
},
child: Icon(Icons.add),
),
);
}
}
The function used to return user with loginStatus true
Future<List<User>> checkifLoggedIn() async {
final Database db = await initializeDB();
final List<Map<String, Object?>> result = await db.query(
'users',
where: 'isLoggedIn = ?',
whereArgs: ['1'],
);
List<User> filtered = [];
for (var item in result) {
filtered.add(User.fromMap(item));
}
return filtered;
}
the problem is here
you used ! sign on a nullable String , and this string is nullable,
try to use this operation (??) so make it
widget.username??"" by this line you will check if the user name is null it will be replaced by an empty string.
I'm new to flutter and really stuck.I am trying to create a search function that calls a list in my Sqfite database, using a keyword. The database all works fine, but when I insert a keyword in my searchbar that part of the app crashes with the following error:
LateInitializationError: Field 'insertFunction' has not been initialized.Im using the insertFunction and deleteFunction parameters and the constructor, but my createState throws an error then that it needs insert and deleteFunction data, which I cannto do as one cannot pass logic into createState.
Any help will be much appreciated. I need to solve my createState problem and my Lateinitialization problem.
Here is the code:
class SearchPage extends StatefulWidget {
#override
_SearchPageState createState() => _SearchPageState();//createState is throwing an error and
as that I insert insertFunction and
deleteFunction here. But if i do, it
also say I should not put logic into
createState.
}
class _SearchPageState extends State<SearchPage> {
late final Function insertFunction;
late final Function deleteFunction;
var db = DatabaseConnect();
String keyword = '';
_SearchPageState({required this.insertFunction,required this.deleteFunction,});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Search My Clients'),
leading: GestureDetector(
onTap: () {
Navigator.of(context).pushReplacementNamed('/homePage');
},
child: const Icon(
Icons.arrow_back,
),
),
),
body: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(15.0),
child: TextField(
autofocus: true,
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'keyword',
prefixIcon: Icon(Icons.search)),
onChanged: (value) {
keyword = value;
setState(() {});
},
),
),
FutureBuilder(
future: db.searchContacts(keyword),
builder: (context, AsyncSnapshot<List> snapshot) {
if (snapshot.hasError) const Text('error');
var data = snapshot.data;
var datalength = data!.length;
if (snapshot.hasData) {
return datalength == 0
? const Center(
child: Text('no data found'),
)
: Container(
child: LimitedBox(
maxHeight: 200,
child: ListView.builder(
scrollDirection: Axis.vertical,
itemCount: datalength,
shrinkWrap: true,
itemBuilder: (context, i) => CustomerCard(
id: data[i].id,
title: data[i].title,
name: data[i].name,
phone: data[i].phone,
fax: data[i].fax,
email: data[i].email,
street: data[i].street,
city: data[i].city,
town: data[i].town,
code: data[i].code,
isExpanded: data[i].isExpanded,
insertFunction: insertFunction,
deleteFunction: deleteFunction,
),
),
),
);
} else {
return const Center(
child: Text('no data found'),
);
}
}),
],
),
),
);
}
}
This is how your code should be
class SearchPage extends StatefulWidget {
#override
_SearchPageState createState() => _SearchPageState();
}
class _SearchPageState extends State<SearchPage> {
insertFunction(){
//function body goes here
}
deleteFunction(){
//function body goes here
}
var db = DatabaseConnect();
String keyword = '';
//the rest goes here
I am writing my first Flutter App with some online tutorials and I found error that I can't fix it.
I am trying to add Navigation by Navigator, but I can't understand why it doesn't work.
Once I am using Navigator in GestureDetector and it works fine, but I don't know what I supposed to do in floatingActionButton to make it work the same way. Note(NoteMode.Adding, null) probably should be something else instead null, because this null is making error (error from title). Can someone explain me what I am doing wrong and what I don't undarstand
Note List
#override
_NoteListState createState(){return _NoteListState();}
}
class _NoteListState extends State<NoteList> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Notes"),
),
body: FutureBuilder(
future: NoteProvider.getNoteList(),
builder: (context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
final notes = snapshot.data;
return ListView.builder(
itemBuilder: (context, index) {
return GestureDetector(
onTap: () {
Navigator.push(
context, MaterialPageRoute(builder: (context) =>
Note(NoteMode.Editing, (notes as dynamic)[index]))
);
},
child: Card(
child: Padding(
padding: const EdgeInsets.only(
top: 30.0, bottom: 30.0, left: 13, right: 22),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
_NoteTitle((notes as dynamic)[index]['title']),
Container(height: 3,),
_NoteText((notes as dynamic)[index]['text']),
],
),
),
),
);
},
itemCount: notes.length,
);
}
return Center(child: CircularProgressIndicator());
},
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (context) => Note(NoteMode.Adding, null)));
},
child: Icon(Icons.add),
),
);
}
}
Note
enum NoteMode{
Editing,
Adding
}
class Note extends StatefulWidget{
final NoteMode noteMode;
final Map<String, dynamic> note;
Note(this.noteMode, this.note,);
#override
State<Note> createState() => _NoteState();
}
class _NoteState extends State<Note> {
final TextEditingController _titleController = TextEditingController();
final TextEditingController _textController = TextEditingController();
List<Map<String, String>> get _notes => NoteInheritedWidget.of(context).notes;
#override
void didChangeDependencies(){
if(widget.noteMode == NoteMode.Editing){
_titleController.text = widget.note['title'];
_textController.text = widget.note['text'];
}
super.didChangeDependencies();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
widget.noteMode == NoteMode.Adding ? 'Add note' : 'Edit note',
),
),
body: Padding(
padding: const EdgeInsets.all(40.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextField(
controller: _titleController,
decoration: InputDecoration(
hintText: "Note title",
),
),
Container(height: 8,),
TextField(
controller: _textController,
decoration: InputDecoration(
hintText: "Note text",
),
),
Container(height: 15,),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
_NoteButton('SAVE', Colors.lightBlue, (){
final title = _titleController.text;
final text = _textController.text;
if(widget.noteMode == NoteMode.Adding){
NoteProvider.insertNote({
'title': title,
'text': text
});
} else if (widget.noteMode == NoteMode.Editing){
NoteProvider.updateNote( {
'id': widget.note['id'],
'title': _titleController.text,
'text': _textController.text,
});
}
Navigator.pop(context);}),
_NoteButton('DISCARD', Colors.grey, (){Navigator.pop(context);}),
widget.noteMode == NoteMode.Editing ?
_NoteButton('DELETE', Colors.redAccent, () async {
await NoteProvider.deleteNote(widget.note['id']);
Navigator.pop(context);})
: Container(),
],
)
],
),
),
);
}
}
Either you have to pass Map in place of null because you are receiving a Map on that page
Navigator.push(context, MaterialPageRoute(builder: (context) => Note(NoteMode.Adding, {"key":"value"})));
or you have to make Map nullable as
class Note extends StatefulWidget{
final NoteMode noteMode;
final Map<String, dynamic>? note;
Note(this.noteMode, this.note,);
#override
State<Note> createState() => _NoteState();
}
I'm new to flutter.
I need to get product information through a form using flutter provider.
I can get one object(like String name value only). But when I add multiple parameters, it shows the following error.
Too many positional arguments: 1 expected, but 3 found.
This is the code I wrote.
Model class
class Item {
String itemName;
String description;
double itemPrice;
Item(this.itemName, this.description, this.itemPrice);
}
ChangeNotifier class
class ItemAddNotifier extends ChangeNotifier {
List<Item> itemList = [];
addItem(String itemName, String description, double itemPrice) {
Item item = Item(itemName, description, itemPrice);
itemList.add(item);
notifyListeners();
}
}
Add items
class AddItems extends StatelessWidget {
final TextEditingController _itemNameTextEditing = TextEditingController();
final TextEditingController _itemDescriptionTextEditing =
TextEditingController();
final TextEditingController _itemPriceTextEditing = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Kavishka'),
),
body: Container(
padding: EdgeInsets.all(30.0),
child: Column(
children: [
TextField(
controller: _itemNameTextEditing,
decoration: InputDecoration(
contentPadding: EdgeInsets.all(15.0),
hintText: 'Item Name',
),
),
SizedBox(
height: 20.0,
),
TextField(
controller: _itemDescriptionTextEditing,
decoration: InputDecoration(
contentPadding: EdgeInsets.all(15.0),
hintText: 'Item Description',
),
),
SizedBox(
height: 20.0,
),
TextField(
controller: _itemPriceTextEditing,
decoration: InputDecoration(
contentPadding: EdgeInsets.all(15.0),
hintText: 'Item Price',
),
),
SizedBox(
height: 20.0,
),
RaisedButton(
child: Text('ADD ITEM'),
onPressed: () async {
if (_itemNameTextEditing.text.isEmpty) {
return;
}
await Provider.of<ItemAddNotifier>(context, listen: false)
.addItem(
_itemNameTextEditing.text,
_itemDescriptionTextEditing.text,
_itemPriceTextEditing.text);
Navigator.pop(context);
},
),
],
),
),
);
}
}
Home Screen
class HomeScreen extends StatelessWidget {
const HomeScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Kavishka'),
actions: [
IconButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
fullscreenDialog: true,
builder: (context) {
return AddItems();
},
),
);
},
icon: Icon(Icons.add))
],
),
body: Container(
padding: EdgeInsets.all(30.0),
child: Column(
children: [
Consumer<ItemAddNotifier>(builder: (context, itemAddNotifier, _) {
return ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: itemAddNotifier.itemList.length,
itemBuilder: (context, index) {
return Padding(
padding: EdgeInsets.all(15.0),
child: Column(
children: [
Text(
itemAddNotifier.itemList[index].itemName,
style:
TextStyle(fontSize: 20.0, color: Colors.black),
),
],
),
);
});
})
],
),
),
);
}
}
Main
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (BuildContext context) {
return ItemAddNotifier();
},
child: MaterialApp(
home: Container(
color: Colors.white,
child: HomeScreen(),
),
),
);
}
}
It shows the error in Item item = Item(itemName, description, itemPrice); line.
If someone can help me to fix this issue.
Thank you.
I'm pretty new to flutter and I'm trying to make a login system using providers. It seems to be working when I test the login. But when I rebuild the app the provider returns a null value. Any help would be appreciated.
The screen to check for employee data. If it exist it should redirect to the home page. And if it doesn't, it should redirect to the login authenticate page
Landing Page
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class Landing extends StatefulWidget {
#override
_LandingState createState() => _LandingState();
}
class _LandingState extends State<Landing> {
//AuthService auth = new AuthService();
#override
Widget build(BuildContext context) {
Future<Employee> getuserdata() => Employee_preferences().getEmployee();
return MultiProvider(
providers: [
ChangeNotifierProvider(
create: (_) => AuthService(),
),
ChangeNotifierProvider(
create: (_) => Employee_Provider(),
)
],
child: MaterialApp(
title: 'ClockServe',
theme: ThemeData(primarySwatch: Colors.blue),
home: FutureBuilder(
future: getuserdata(),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
return CircularProgressIndicator();
default:
if (snapshot.hasError) {
return Text('Error:${snapshot.error}');
} else if (snapshot.data.empId == null) {
return AuthenticatePage();
} else {
return HomePage(emp: snapshot.data);
}
}
}),
routes: {
'/navigatorPage': (context) => NavigatorPage(),
'/homePage': (context) => HomePage(),
'/authenticate': (context) => AuthenticatePage(),
'/attendancePage': (context) => AttendanceScanner()
},
),
);
}
}
The homepage. The page will hold employee information. Landing page is correctly redirecting to this page but for some reason the provider is returning null
HomePage
class HomePage extends StatefulWidget {
final Employee emp;
const HomePage({Key key, this.emp}) : super(key: key);
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
//to do: add back end
//use futurebuilder to return user object
//using futureprovider to get snapshot data of user object from database
#override
Widget build(BuildContext context) {
Employee emp = Provider.of<Employee_Provider>(context).emp;
print(emp.empEmail);
return Scaffold(
appBar: AppBar(
actions: <Widget>[
ElevatedButton.icon(
onPressed: () async {
Employee_preferences().removeEmployee();
Navigator.pushReplacementNamed(context, '/authenticate');
},
label: Text(
'Log Out',
style: TextStyle(color: Colors.white),
),
icon: Icon(
Icons.logout,
color: Colors.white,
),
)
],
title: Text('ClockServe'),
centerTitle: true,
),
//button to pop qr scanner camera
//after scanning a qr code it should parse the json array
//into a method, the method will take that as parameter.
//method should send http request check in the auth dart
floatingActionButton: FloatingActionButton.extended(
label: Text('Check In'),
icon: Icon(Icons.camera_alt),
onPressed: () => navigateToScanPage(context),
),
// floatingActionButton: FloatingActionButton(
// onPressed: () {},
// child: Icon(Icons.alarm_on),
// ),
body: SingleChildScrollView(
child: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Text(emp.empFirstName ?? 'emp first name'),
],
),
),
),
);
}
}
Future navigateToScanPage(context) async {
Navigator.push(
context, MaterialPageRoute(builder: (context) => AttendanceScanner()));
}
Code for login page just in case if it's relevant.
Login Page
class LoginPage extends StatefulWidget {
final Function toggleView;
LoginPage({this.toggleView});
#override
_LoginPageState createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
final _formKey = GlobalKey<FormState>();
String email = '';
String password = '';
String error = '';
bool loading = false;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: <Widget>[
ElevatedButton.icon(
onPressed: () {
widget.toggleView();
},
label: Text('Register'),
icon: Icon(Icons.person_add),
)
],
title: Text('Login'),
),
body: Container(
padding: EdgeInsets.all(30),
child: Form(
key: _formKey,
child: SingleChildScrollView(
child: Column(
children: <Widget>[
WelcomeHeader(),
SizedBox(
height: 10,
),
TextFormField(
validator: (value) => value.isEmpty ? 'Enter email' : null,
onChanged: (val) {
setState(() => email = val);
},
decoration: decorationBox.copyWith(hintText: 'Email'),
),
SizedBox(
height: 20,
),
TextFormField(
validator: (value) => value.isEmpty ? 'Enter password' : null,
onChanged: (val) {
setState(() => password = val);
},
obscureText: true,
decoration: decorationBox.copyWith(hintText: 'Password'),
),
SizedBox(
height: 20,
),
ElevatedButton(
onPressed: () async {
final form = _formKey.currentState;
if (form.validate()) {
form.save();
AuthService auth = new AuthService();
final Future<Map<String, dynamic>> successMsg =
auth.empLogin(email, password);
successMsg.then((response) {
if (response['status']) {
Employee emp = response['employee'];
print(emp);
Provider.of<Employee_Provider>(context, listen: false)
.setEmp(emp);
Navigator.pushReplacementNamed(context, '/homePage');
}
});
}
},
child: Text('Log In'),
),
SizedBox(
height: 20.0,
),
Text(
error,
style: TextStyle(color: Colors.red, fontSize: 20.0),
)
],
),
),
),
),
);
}
}
class WelcomeHeader extends StatelessWidget {
const WelcomeHeader({
Key key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: [
Text(
'Welcome To ClockServe',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 28.0,
),
),
Divider(
height: 20,
thickness: 2,
),
Text(
'Enter your credentials to login',
style: TextStyle(fontStyle: FontStyle.italic),
),
],
),
);
}
}