I am at the first few screens of designing my flutter application, currently using setState
to manage the state. Well, I need to shift from this and use provider
instead.
Below code is sample for the my account
screen, where users can change their profile information. Below is what it does.
- Load user data in
init
- Update user data on button press
I am thinking of better managing the state
, because I need to display waiting message when the data is being saved and save success message when data saved. I am already using Loading Data message at init
data load.
Below is my code
AccountPage
import 'package:flutter/material.dart';
import 'package:xxx/models/company.dart';
import 'package:xxx/models/user.dart';
import 'package:xxx/services/user/user_impl.dart';
import 'package:xxx/services/user/user_interface.dart';
class AccTest extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("My App"),
),
body: AccTestForm(),
);
}
}
class AccTestForm extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return AccTestState();
}
}
class AccTestState extends State<AccTestForm> {
final _formKey = GlobalKey<FormState>();
TextEditingController nameController = TextEditingController();
UserInterface userinterface = UserImpl();
int userID = 0;
int companyID = 0;
@override
Widget build(BuildContext context) {
/**
* here i am checking for `userID` which was set via `setState`
*/
if (userID > 0) {
return ListView(
children: <Widget>[
Container(
child: Text(
"This is your account section. You can update and change information as you prefer.",
style: Theme.of(context).textTheme.subhead,
),
margin: EdgeInsets.only(left: 10, right: 10, top: 30),
),
Container(
child: FutureBuilder(
future: userinterface.getUserWithCompanyInfo(userID),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.done &&
snapshot != null) {
nameController.text = snapshot.data.name;
companyID = snapshot.data.company.idcompany;
print("BUILD FORM PRINTED");
return _buildForm();
} else {
return Center(
child: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
CircularProgressIndicator(),
Container(
height: 10,
),
Text(
"Loading Data... Please Wait",
style: Theme.of(context).textTheme.body1,
)
],
),
),
);
}
},
),
margin: EdgeInsets.only(left: 10, right: 10, top: 30),
)
],
);
} else {
return Center(
child: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
CircularProgressIndicator(),
Container(
height: 10,
),
Text(
"Loading Data... Please Wait",
style: Theme.of(context).textTheme.body1,
)
],
),
),
);
}
}
Widget _buildForm() {
return Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
margin: EdgeInsets.only(left: 8, bottom: 5),
child: Text(
"Name",
style: Theme.of(context).textTheme.subtitle,
)),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Expanded(
child: TextFormField(
controller: nameController,
keyboardType: TextInputType.text,
),)
],
),
Container(
margin: EdgeInsets.only(top: 40, left: 20, right: 20, bottom: 20),
child: RaisedButton(
color: Color.fromRGBO(0, 72, 128, 100),
textColor: Colors.white,
child: Text(
"Save Information",
style: Theme.of(context).textTheme.button,
),
onPressed: () {
if (_formKey.currentState.validate()) {
String saveState = null;
/**
* Updating the `user`
*/
Company company = Company(idcompany: companyID);
User user = User(
iduser: userID,
name: nameController.text,
company: company,
phone: "something",
email: "test@test.com",
companyDesignation: "something",
);
UserInterface userInterface = UserImpl();
userInterface.updateUser(user).then((val) {
print("User Update: " + val);
Scaffold.of(context).showSnackBar(
SnackBar(content: Text("ssdsd")));
});
}
},
),
)
],
),
);
}
@override
void initState() {
super.initState();
/**
* Here i get user information by email, then assign them to `userID` global variable
*/
userinterface.getUserByEmail("test@test.com").then((val) {
setState(() {
userID = val.iduser;
});
print("user id: " + val.iduser.toString());
});
}
}
UserImpl
import 'package:flutter/material.dart';
import 'package:xxx/models/user.dart';
import 'package:xxx/services/nav_links.dart';
import 'package:xxx/services/user/user_interface.dart';
import 'package:http/http.dart' as http;
import 'dart:convert' as convert;
class UserImpl implements UserInterface
{
NavLinks navLinks = NavLinks();
/**
* Get user with company information
*/
@override
Future <User> getUserWithCompanyInfo(int userID) async {
var data = await http.get(navLinks.getUserWithCompanyInfo(userID));
if (data.statusCode == 200) {
return User.fromJson(convert.json.decode(data.body));
} else {
throw Exception('Failed to load post');
}
}
@override
Future<User> getUserByEmail(String email) async{
var data = await http.get(navLinks.getUserByEmail(email));
if (data.statusCode == 200) {
return User.fromJson(convert.json.decode(data.body));
} else {
throw Exception('Failed to load post');
}
}
Future<String> updateUser(User body) async {
print("BODY: " + body.toJson().toString());
return http.post(navLinks.updateUser(), body: convert.json.encode(body.toJson()), headers: {
"Accept": "application/json",
"content-type": "application/json"
}).then((http.Response response) {
final int statusCode = response.statusCode;
print("RESPONSE: " + response.body);
print("STATUS CODE: " + statusCode.toString());
if (statusCode < 200 || statusCode > 400 || response.body == null) {
throw new Exception("Error while fetching data");
} else {
return response.body;
}
});
}
}
I feel very confused when trying to apply provider
into this, because I have to deal with couple of Future
and its returning data.
Any support on converting this to provider
please?