how to save and load shared preference towards an other page in flutter - sharedpreferences

I tried to Save and share a variable Phone number string from a tabbar page to homepage. Currently my variable is display only after reload. I tried to display variable just after saved it.
my code :
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String _variable;
#override
void initState() {
super.initState();
_loadvariable();
}
_loadvariable() async { // load variable
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
_variable = (prefs.getString('variable'));
}
);
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
bottomNavigationBar: BottomAppBar(
color: Colors.blue,
elevation: 20.0,
child: ButtonBar(
alignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
IconButton(
icon: Icon(Icons.phone),
color: Colors.white,
onPressed: () {
Navigator.push(
context,
new MaterialPageRoute(builder: (context) => new Phone_Page()),
);
},
),
],
),
),
body: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text(
'$_variable',
style: Theme.of(context).textTheme.display1,
),
],
),
),
);
}
}
here is my seconde page class, I can clic on the phone icon to show a dialog box, and I can write on the text field. After clic on save button my textfield is save, the dialog box is close and my variable is display on the card. But after return on the Homepage my variable isn't display. I need to reload the app to display it :(
class Phone_Page extends StatefulWidget {
#override
Phone_PageState createState() => Phone_PageState();
}
class Phone_PageState extends State<Phone_Page> {
final TextEditingController controller = new TextEditingController();
String _variable;
_loadvariable() async { // load variable
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
_variable = (prefs.getString('variable'))?? "";
});
}
_savevariable() async { // save variable
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
prefs.setString('variable', controller.text);
});
}
_deletevariable() async { //delete variable
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
prefs.remove('variable');
});
}
#override
void initState() {
super.initState();
_loadvariable()?? "";
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Phone"),
),
body: new Center(
child: new ListView(
children: <Widget>[
new Card(
child: new Container(
padding: const EdgeInsets.all(20.0),
child: new Row(
children: [
new Expanded(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
new Text(
'$_variable',
style: new TextStyle(
color: Colors.grey[500],
),
),
],
),
),
new IconButton(
icon: new Icon(Icons.add_call),
onPressed: ()
{
_showDialog();
}
),
new IconButton(
icon: new Icon(Icons.delete),
onPressed: () { setState(() {
_deletevariable();
_savevariable();
_loadvariable();
}
);
},
),
],
),
),
),
]
)
)
);
}
_showDialog() async {
await showDialog<String>(
context: context,
child: new AlertDialog(
// contentPadding: const EdgeInsets.all(16.0),
content: new Row(
children: <Widget>[
new Expanded(
child: new TextField(
controller: controller,
autofocus: true,
decoration: new InputDecoration(
labelText: 'number', hintText: '06 - - - - - - - -'),
// keyboardType: TextInputType.number,
),
)
],
),
actions: <Widget>[
new FlatButton(
child: const Text('save'),
onPressed: (){
setState(() { {
_savevariable();
Navigator.pop(context);
}
}
);
}
)
],
),
);
}
}

To achieve what you want, you need to call _loadvariable() function of class MyHomePage from PhonePage class. To do that:
Refactor and remove _ from _loadvariable() and _MyHomePageState so that it won't be private anymore.
Pass MyHomePageState class instance to PhonePage as follows:
Navigator.push(
context,
new MaterialPageRoute(builder: (context) => new PhonePage(
myHomePageState: this,
)),
);
Call loadvariable() in _savevariable() like
_savevariable() async {
// save variable
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
prefs.setString('variable', controller.text);
});
widget.myHomePageState.loadvariable();
}
Make sure the myHomePageState type is var so that you won't get type error:
class PhonePage extends StatefulWidget {
var myHomePageState;
PhonePage({this.myHomePageState});
#override
PhonPageState createState() => PhonPageState();
}

Related

A resource failed to call close -flutter/tflite error

I want to do image processing in flutter. I load the ml model(tflite) in flutter. Here I successfully take the image from gallery/camera . I stuck in processing part of the image .I didnt get the required ouput. please help me
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:tflite/tflite.dart';
void main() {
runApp(new MaterialApp(
title: "corona",
home: LandingScreen(),
));
}
class LandingScreen extends StatefulWidget {
#override
_LandingScreenState createState() => _LandingScreenState();
}
class _LandingScreenState extends State<LandingScreen> {
File imageFile;
String result;
String path;
_openGallery(BuildContext context) async {
var picture = await ImagePicker.pickImage(source: ImageSource.gallery);
this.setState(() {
imageFile = picture;
path = picture.path;
});
Navigator.of(context).pop();
}
_openCamera(BuildContext context) async {
var picture = await ImagePicker.pickImage(source: ImageSource.camera);
this.setState(() {
imageFile = picture;
path = picture.path;
});
Navigator.of(context).pop();
}
// **classifyimage function to process the image from tflite**
Future classifyImage() async {
await Tflite.loadModel(
model: "assets/covid19_densenet.tflite",
labels: "assets/x.txt",
);
var output = await Tflite.runModelOnImage(path: path);
setState(() {
result = output.toString();
});
}
// Other functions
Future<void> _showChoiceDialog(BuildContext context) {
return showDialog(context: context, builder: (BuildContext context) {
return AlertDialog(
title: Text("Make a Choose!"),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
GestureDetector(
child: Text("Gallery"),
onTap: () {
_openGallery(context);
},
),
Padding(padding: EdgeInsets.all(8.0)),
GestureDetector(
child: Text("Camera"),
onTap: () {
_openCamera(context);
},
)
],
),
),
);
});
}
Widget _decideImageView() {
if (imageFile == null) {
return Text("No Image Selected!");
} else {
return Image.file(imageFile, width: 400, height: 400);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("CORONA DETECTION"),
),
body: Container(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
_decideImageView(),
RaisedButton(
onPressed: () {
_showChoiceDialog(context);
},
child: Text("select image!"),
),
Container(
margin: EdgeInsets.fromLTRB(0, 0, 0, 0),
child: RaisedButton(
onPressed: () => classifyImage(),
child: Text('Classify Image'),
textColor: Colors.white,
color: Colors.blue,
padding: EdgeInsets.fromLTRB(12, 12, 12, 12),
),
),
result == null ? Text('Result') : Text(result)
],
),
),
),
);
}
}
This is an UI of application. when i tap on the classify image button
Here i am trying to upload image to model by this button and then it processing and returns the output
The tflite seems to be throwing a BufferOverflowException due to lack of grayscale support on onFrame methods. The issue should have been fixed as mentioned on this GitHub issue ticket.

How to wait for variable to not equal to null in a future builder (Flutter/Dart)?

I have a simple app with two dart files: main.dart and bukalapak.dart
For demonstration purposes the app only has two Future Text() widgets. Basically one Text widget gets the name of a certain html, the other widget gets the total of the same html. Don't ask why but the future builder for "name" has to be in a separate stateful widget in bukalapak.dart. My question is how can I wait until the html is not null then display the total Text widget, because I can easily just call the url again but that would be doing twice the work. I only want to have to call the http.get once.
Here is the code for main.dart:
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark(),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
Bukalapak bukalapak = Bukalapak();
return Scaffold(
appBar: AppBar(
title: Text('data'),
),
body: Container(
child: Column(
children: <Widget>[
RandomWidget(
bukalapak: bukalapak,
),
FutureBuilder(
builder: (context, snapshot) {
return Container(
color: Colors.grey,
height: 28.0,
padding: EdgeInsets.only(left: 20.0),
child: Align(
alignment: Alignment.centerLeft,
child: Text('Total results: ${snapshot.data}')),
);
},
future: bukalapak.getTotal(),
)
],
),
),
);
}
}
The code for bukalapak.dart:
class Bukalapak {
var html;
Future<dynamic> getTotal() async {
// wait until html != null, then perform this
var a = html.querySelectorAll(
'#display_product_search > div.product-pagination-wrapper > div.pagination > span.last-page');
dynamic total = int.parse(a[0].text) * 50;
total = '$total'.replaceAllMapped(
new RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))'), (Match m) => '${m[1]},');
return total;
}
Future<dynamic> getName() async {
http.Response response = await http.get(
'https://www.bukalapak.com/products/s?from=omnisearch&from_keyword_history=false&page=0&search%5Bkeywords%5D=paper&search_source=omnisearch_organic&source=navbar&utf8=✓');
if (response.statusCode == 200) {
String data = response.body;
html = parse(data);
var nameElement = html.querySelector(
'li.col-12--2 > div.product-card > article > div.product-media > a');
String title = nameElement.attributes['title'];
return title;
} else {
throw Exception('Bukalapak error: statusCode= ${response.statusCode}');
}
}
}
class RandomWidget extends StatefulWidget {
RandomWidget({this.bukalapak});
final Bukalapak bukalapak;
#override
_TextState createState() => _TextState();
}
class _TextState extends State<RandomWidget> {
#override
Widget build(BuildContext context) {
return FutureBuilder(
builder: (context, snapshot) {
return Container(
color: Colors.grey,
height: 28.0,
padding: EdgeInsets.only(left: 20.0),
child: Align(
alignment: Alignment.centerLeft,
child: Text('Name results: ${snapshot.data}')),
);
},
future: widget.bukalapak.getName(),
);
}
}
you can pass any function which notify parent widget to build future.
Following code will help you more:
class DeleteWidget extends StatefulWidget {
#override
_DeleteWidgetState createState() => _DeleteWidgetState();
}
class _DeleteWidgetState extends State<DeleteWidget> {
Bukalapak bukalapak = Bukalapak();
Widget first;
bool isBuild = false;
nowbuildtotal() async {
await Future.delayed(Duration(microseconds: 1));
setState(() {
isBuild = true;
});
}
#override
void initState() {
super.initState();
first = RandomWidget(
bukalapak: bukalapak,
buildnow: nowbuildtotal,
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('data'),
),
body: Container(
child: Column(
children: <Widget>[
first,
isBuild
? FutureBuilder(
builder: (context, snapshot) {
return Container(
color: Colors.grey,
height: 28.0,
padding: EdgeInsets.only(left: 20.0),
child: Align(
alignment: Alignment.centerLeft,
child: Text('Total results: ${snapshot.data}')),
);
},
future: bukalapak.getTotal(),
)
: Container()
],
),
),
);
}
}
class RandomWidget extends StatefulWidget {
RandomWidget({this.bukalapak, this.buildnow});
final Bukalapak bukalapak;
final Function buildnow;
#override
_TextState createState() => _TextState();
}
class _TextState extends State<RandomWidget> {
#override
Widget build(BuildContext context) {
return FutureBuilder(
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
widget.buildnow();
}
return Container(
color: Colors.grey,
height: 28.0,
padding: EdgeInsets.only(left: 20.0),
child: Align(
alignment: Alignment.centerLeft,
child: Text('Name results: ${snapshot.data}')),
);
},
future: widget.bukalapak.getName(),
);
}
}
class Bukalapak {
var html;
Future<dynamic> getTotal() async {
// wait until html != null, then perform this
var a = await html.querySelectorAll(
'#display_product_search > div.product-pagination-wrapper > div.pagination > span.last-page');
dynamic total = int.parse(a[0].text) * 50;
total = '$total'.replaceAllMapped(
new RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))'), (Match m) => '${m[1]},');
return total;
}
Future<dynamic> getName() async {
print("object");
http.Response response = await http.get(
'https://www.bukalapak.com/products/s?from=omnisearch&from_keyword_history=false&page=0&search%5Bkeywords%5D=paper&search_source=omnisearch_organic&source=navbar&utf8=✓');
if (response.statusCode == 200) {
String data = response.body;
html = parse(data);
var nameElement = html.querySelector(
'li.col-12--2 > div.product-card > article > div.product-media > a');
String title = nameElement.attributes['title'];
return title;
} else {
throw Exception('Bukalapak error: statusCode= ${response.statusCode}');
}
}
}

how to show video with video player in flutter

how to show video in flutter?
i should recieve an api have url of video to show, but it sitll white page with my progress indicator,
I was trying for a week but couldn't do any thing,
then I tried to use assets video but it didn't work too
here is my code so what is wrong?
please help me, thank you.
class _MyHomePageState extends State<MyHomePage> {
VideoPlayerController _videoPlayerController;
Future<void> _initializedVideoPlayerFuture;
String videoUrl =
'https://storage.koolshy.co/shasha-transcoded-videos-2019/1c18ada9-a82a-4490-ad2f-87c3ba3ed251_240.mp4';
String videoTrack = 'assets/video.mp4';
#override
void initState() {
super.initState();
// _videoPlayerController = VideoPlayerController.network(videoUrl);
_videoPlayerController = VideoPlayerController.asset(videoTrack);
_videoPlayerController.setLooping(true);
_videoPlayerController.setVolume(1.0);
}
#override
void dispose() {
super.dispose();
_videoPlayerController.dispose();
}
void _incrementCounter() {
setState(() {
_videoPlayerController.value.isPlaying
? _videoPlayerController.pause()
: _videoPlayerController.play();
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
FutureBuilder(
future: _initializedVideoPlayerFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return AspectRatio(
aspectRatio: _videoPlayerController.value.aspectRatio,
child: VideoPlayer(_videoPlayerController),
);
} else {
return Center(
child: CircularProgressIndicator(),
);
}
},
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'play/pause',
child: Icon(_videoPlayerController.value.isPlaying
? Icons.pause
: Icons.play_arrow),
),
);
}
}
there is a missing statement
_initializedVideoPlayerFuture = _videoPlayerController.initialize();
should be in the initstate()
void initState() {
super.initState();
_videoPlayerController = VideoPlayerController.network(videoUrl);
// _videoPlayerController = VideoPlayerController.asset(videoTrack);
_initializedVideoPlayerFuture = _videoPlayerController.initialize();
_videoPlayerController.setLooping(true);
_videoPlayerController.setVolume(1.0);
}

Flutter : How to keep user logged in and make logout

I am getting the csrf token and printing the response data in console but how to keep user logged in using the response data.I am making login using the status code i.e., if status code is 200 then move to login after that I want to keep user logged in and log out only when user wants to log out
I have seen lot of examples but none are helping in my case.
In my case i am using th csrf token and unable to keep it logged in, and i have also used login form.
LoginPage.dart
import 'dart:io';
import 'package:cookie_jar/cookie_jar.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:jignasa/home_screen.dart';
import 'package:jignasa/logindata.dart';
import 'package:path_provider/path_provider.dart';
class LoginPage extends StatefulWidget {
static String tag = 'login-page';
#override
_LoginPageState createState() => new _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
LoginRequestData _loginData = LoginRequestData();
bool _validate = false;
bool _obscureText = true;
var username, password;
#override
Widget build(BuildContext context) {
return Scaffold(
// backgroundColor: Colors.white,
body: SingleChildScrollView(
child: Container(
color: Colors.lightGreen[500],
child: Column(
children: <Widget>[
Center(
child: Container(
width: MediaQuery
.of(context)
.size
.width,
height: MediaQuery
.of(context)
.size
.height / 2.5,
decoration: BoxDecoration(
gradient: LinearGradient(
// begin: Alignment.topCenter,
// end: Alignment.bottomCenter,
colors: [
Color(0xFFFFFFFF),
Color(0xFFFFFFFF),
]
),
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(90)
)
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Align(
alignment: Alignment.center,
child: Image.asset('images/ic_launcher1.png'),
),
],
),
),
),
Center(
child: SingleChildScrollView(
child: new Form(
key: _formKey,
autovalidate: _validate,
child: _getFormUI(),
),
)
)
],
),
),
),
);
}
Widget _getFormUI() {
return new Column(
children: <Widget>[
SizedBox(height: 24.0),
Center(
child: Text('Login',
style: TextStyle(fontSize: 25,
fontWeight: FontWeight.bold,
color: Colors.white),),
),
new SizedBox(height: 25.0),
new TextFormField(
keyboardType: TextInputType.emailAddress,
autofocus: false,
decoration: InputDecoration(
hintText: 'Username',
contentPadding: EdgeInsets.fromLTRB(20.0, 15.0, 20.0, 15.0),
border:
OutlineInputBorder(borderRadius: BorderRadius.circular(32.0)),
),
validator: _validateName,
onSaved: (value) {
_loginData.username = value;
},
),
new SizedBox(height: 8.0),
new TextFormField(
autofocus: false,
obscureText: _obscureText,
keyboardType: TextInputType.text,
decoration: InputDecoration(
hintText: 'Password',
contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
border:
OutlineInputBorder(borderRadius: BorderRadius.circular(24.0)),
suffixIcon: GestureDetector(
child: Icon(
_obscureText ? Icons.visibility : Icons.visibility_off,
semanticLabel:
_obscureText ? 'show password' : 'hide password',
),
),
),
validator: _validatePassword,
onSaved: (String value) {
_loginData.password = value;
}
),
new SizedBox(height: 15.0),
new Padding(
padding: EdgeInsets.symmetric(vertical: 16.0),
child: RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(24),
),
onPressed: () {
_submit();
// Navigator.of(context).pushReplacementNamed('/home');
},
padding: EdgeInsets.all(12),
color: Colors.black54,
child: Text('Log In', style: TextStyle(color: Colors.white)),
),
),
new FlatButton(
child: Text(
'Forgot password?',
style: TextStyle(color: Colors.black54),
),
onPressed: () {},
),
new FlatButton(
onPressed: _sendToRegisterPage,
child: Text('Not a member? Sign up now',
style: TextStyle(color: Colors.black54)),
),
Text(''),
Text(''),
Text(''),
],
);
}
_sendToRegisterPage() {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => HomeScreen()),
);
}
String _validateName(String value) {
if (value.isEmpty) {
return "Username is Required";
} else {
username = value.toString();
}
}
String _validatePassword(String value) {
if (value.isEmpty) {
return "Password is Required";
} else {
password = value.toString();
}
}
_submit() {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
print("Username ${_loginData.username}");
print("Password ${_loginData.password}");
return SessionId();
} else {
setState(() {
bool _validate = false;
});
}
}
final Dio _dio = Dio();
PersistCookieJar persistentCookies;
final String url = "https://www.xxxx.in/rest/user/login.json";
Future<String> get _localPath async {
final directory = await getApplicationDocumentsDirectory();
print(directory.path);
return directory.path;
}
Future<Directory> get _localCoookieDirectory async {
final path = await _localPath;
final Directory dir = new Directory('$path/cookies');
await dir.create();
print(dir);
return dir;
}
Future<String> getCsrftoken() async{
try {
String csrfTokenValue;
final Directory dir = await _localCoookieDirectory;
final cookiePath = dir.path;
persistentCookies = new PersistCookieJar(dir: '$cookiePath');
persistentCookies.deleteAll(); //clearing any existing cookies for a fresh start
_dio.interceptors.add(
CookieManager(persistentCookies) //this sets up _dio to persist cookies throughout subsequent requests
);
_dio.options = new BaseOptions(
baseUrl: url,
contentType: ContentType.json,
responseType: ResponseType.plain,
// connectTimeout: 5000,
// receiveTimeout: 100000,
headers: {
HttpHeaders.userAgentHeader: "dio",
"Connection": "keep-alive",
},
); //BaseOptions will be persisted throughout subsequent requests made with _dio
_dio.interceptors.add(
InterceptorsWrapper(
onResponse:(Response response) {
List<Cookie> cookies = persistentCookies.loadForRequest(Uri.parse(url));
csrfTokenValue = cookies.firstWhere((c) => c.name == 'csrftoken', orElse: () => null)?.value;
if (csrfTokenValue != null) {
_dio.options.headers['X-CSRF-TOKEN'] = csrfTokenValue; //setting the csrftoken from the response in the headers
}
print(response);
return response;
}
)
);
await _dio.get("https://www.xxxx.in/rest/user/login.json");
print(csrfTokenValue);
return csrfTokenValue;
} catch (error, stacktrace) {
print(error);
// print("Exception occured: $error stackTrace: $stacktrace");
return null;
}
}
SessionId() async {
try {
final csrf = await getCsrftoken();
FormData formData = new FormData.from({
"username": "${_loginData.username}",
"password": "${_loginData.password}",
"csrfmiddlewaretoken" : '$csrf'
});
Options optionData = new Options(
contentType: ContentType.parse("application/json"),
);
Response response = await _dio.post("https://www.xxxx.in/rest/user/login.json", data: formData, options: optionData);
print("StatusCode:${response.statusCode}");
// print(response.data);
if (response.statusCode == 200){
return Navigator.of(context).pushReplacement(MaterialPageRoute(
builder: (context) => HomeScreen(),
));
}
else{
throw Exception();
}
} on DioError catch(e) {
if(e.response != null) {
print( e.response.statusCode.toString() + " " + e.response.statusMessage);
print(e.response.data);
print(e.response.headers);
print(e.response.request);
} else{
print(e.request);
print(e.message);
}
}
catch (error, stacktrace) {
print("Exception occured: $error stackTrace: $stacktrace");
return null;
}
}
}
You can make an entry in Shared preference after getting response code 200 from api.
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs?.setBool("isLoggedIn", true);
then you can navigate user after checking status from shared preference
Future<void> main() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
var status = prefs.getBool('isLoggedIn') ?? false;
print(status);
runApp(MaterialApp(home: status == true ? Login() : Home()));
}
Update :-
Another way of doing it is you can also add your logic into splash screen and splash screen should be entry point in your app
class SplashScreen extends StatefulWidget {
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return _SplashScreenState();
}
}
class _SplashScreenState extends State<SplashScreen> {
#override
void initState() {
// TODO: implement initState
super.initState();
startTimer();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/images/clinician_splash.png"),
fit: BoxFit.cover),
),
),
);
}
void startTimer() {
Timer(Duration(seconds: 3), () {
navigateUser(); //It will redirect after 3 seconds
});
}
void navigateUser() async{
SharedPreferences prefs = await SharedPreferences.getInstance();
var status = prefs.getBool('isLoggedIn') ?? false;
print(status);
if (status) {
Navigation.pushReplacement(context, "/Home");
} else {
Navigation.pushReplacement(context, "/Login");
}
}
}
For logout add below functionality in onPress event of logout button :
void logoutUser(){
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs?.clear()
Navigator.pushAndRemoveUntil(
context,
ModalRoute.withName("/SplashScreen"),
ModalRoute.withName("/Home")
);
}
For security :-
Here in example I have used SharedPreferences which is not secure.for security you can change SharedPreferences to flutter_secure_storage.
https://pub.dev/packages/flutter_secure_storage#-readme-tab-
Future<void> main() async{
WidgetsFlutterBinding.ensureInitialized();
SharedPreferences preferences = await SharedPreferences.getInstance();
var email = preferences.getString("emailText");
runApp(
MaterialApp(
home: email == null ? LoginPage() : Dashboard(),
)
);
}

Flutter run async operation on object creation

I'm new to flutter and I know it's a very basic question but I've been stuck on this one for three days. I just want to fetch data from an API on object creation. When you run the code it throws an exception But when you Hot Reload it, the async operation starts to work fine. Kindly tell me where I'm wrong. I myself have made extra classes although one should avoid to code with that approach.
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'dart:async';
import 'package:http/http.dart' as http;
import 'dart:convert';
void main(){
runApp(
MaterialApp(
title : "Quake",
home : HomePage()
)
);
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
void initState() {
super.initState();
dataRepository.init();
}
#override
Widget build(BuildContext context) {
return Reading();
}
}
class Reading extends StatefulWidget {
#override
_ReadingState createState() => _ReadingState();
}
class _ReadingState extends State<Reading> {
Map _data = Map();
List _features = List();
#override
void initState() {
super.initState();
_data = dataRepository.getReading();
_features = _data['features'];
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Quake"),
centerTitle: true,
backgroundColor: Colors.black,
),
body : Center(
child : ListView.builder(
itemCount: _features.length,
padding: const EdgeInsets.all(14.5),
itemBuilder: (BuildContext context, int position){
var format = DateFormat.yMMMd("en_US").add_jm();
var _date = format.format( DateTime.fromMicrosecondsSinceEpoch(_features[position]['properties']['time']*1000, isUtc: true));
return Column(
children: <Widget>[
Divider(height : 5.5),
ListTile(
title: Text("$_date",
style: TextStyle(fontSize: 16.0)),
subtitle: Text("${_features[position]['properties']['place']}",
style: TextStyle(fontSize: 13.0)),
leading: CircleAvatar(
backgroundColor : Colors.black,
child : Text("${_features[position]['properties']['mag']}", style: TextStyle( color: Colors.white))
),
onTap: () => _windowOnTapping(context, _features[position]['properties']['title']),
)],);},)));}}
Future _windowOnTapping(BuildContext context, String message){
var alert = AlertDialog(
title: Text("Quakes"),
content: Text(message),
actions: <Widget>[
FlatButton ( child: Text("OK"), onPressed: (){ Navigator.pop(context);})
],
);
showDialog( context: context, builder: (context)=> alert);
}
final DataRepository dataRepository = DataRepository._private();
class DataRepository{
DataRepository._private();
Map _data;
void init() async{
String apiUrl = 'https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_day.geojson';
http.Response response = await http.get(apiUrl);
_data = json.decode(response.body);
}
Map getReading(){
return _data;
}
}
Use a FutureBuilder to read the Future and only render the component after it returns, something like this:
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'dart:async';
import 'package:http/http.dart' as http;
import 'dart:convert';
void main() {
runApp(MaterialApp(title: "Quake", home: HomePage()));
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Reading();
}
}
class Reading extends StatefulWidget {
#override
_ReadingState createState() => _ReadingState();
}
class _ReadingState extends State<Reading> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Quake"),
centerTitle: true,
backgroundColor: Colors.black,
),
body: FutureBuilder<Map>(
future: dataRepository.getReading(),
builder: (context, snapshot) {
if (snapshot.hasData) {
var features = snapshot.data['features'];
return Center(
child: ListView.builder(
itemCount: features.length,
padding: const EdgeInsets.all(14.5),
itemBuilder: (BuildContext context, int position) {
var format = DateFormat.yMMMd("en_US").add_jm();
var _date = format.format(
DateTime.fromMicrosecondsSinceEpoch(
features[position]['properties']['time'] * 1000,
isUtc: true));
return Column(
children: <Widget>[
Divider(height: 5.5),
ListTile(
title:
Text("$_date", style: TextStyle(fontSize: 16.0)),
subtitle: Text(
"${features[position]['properties']['place']}",
style: TextStyle(fontSize: 13.0)),
leading: CircleAvatar(
backgroundColor: Colors.black,
child: Text(
"${features[position]['properties']['mag']}",
style: TextStyle(color: Colors.white))),
onTap: () => _windowOnTapping(context,
features[position]['properties']['title']),
)
],
);
},
));
} else {
return Text("Loading");
}
}));
}
}
Future _windowOnTapping(BuildContext context, String message) {
var alert = AlertDialog(
title: Text("Quakes"),
content: Text(message),
actions: <Widget>[
FlatButton(
child: Text("OK"),
onPressed: () {
Navigator.pop(context);
})
],
);
showDialog(context: context, builder: (context) => alert);
}
final DataRepository dataRepository = DataRepository._private();
class DataRepository {
DataRepository._private();
Future<Map> getReading() async {
String apiUrl =
'https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_day.geojson';
http.Response response = await http.get(apiUrl);
var data = json.decode(response.body);
print(data);
return data;
}
}