How to store selected value in a string so that after restart app it shows last selected value? - flutter

I'm setting up flutter local notification, all is going well but i want to store the selected value in a text so if the app restart it will show selected value rather then resetting to default.
For example if I choose notification at 08:08:08 so after selecting it and restarting app whenever i go to notification selection time it should show 08:08:08(last selected value).
i have tried setstate(){};
but value always reset after restarting app.
here is my code.
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:flutter_datetime_picker/flutter_datetime_picker.dart';
import 'package:fluttertoast/fluttertoast.dart';
class SettingPage extends StatefulWidget {
#override
_SettingPage createState() => _SettingPage();
}
class _SettingPage extends State<SettingPage> {
///Flutter Local Notification
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;
String notifyTime ="your time";
String nhour ="";
String nminutes ="";
String nseconds ="";
#override
initState() {
super.initState();
// initialise the plugin. app_icon needs to be a added as a drawable
resource to the Android head project
// If you have skipped STEP 3 then change app_icon to #mipmap/ic_launcher
var initializationSettingsAndroid =
new AndroidInitializationSettings('#mipmap/ic_launcher');
var initializationSettingsIOS = new IOSInitializationSettings();
var initializationSettings = new InitializationSettings(
initializationSettingsAndroid, initializationSettingsIOS);
flutterLocalNotificationsPlugin = new FlutterLocalNotificationsPlugin();
flutterLocalNotificationsPlugin.initialize(initializationSettings);
}
Future _showNotificationWithDefaultSound() async {
var androidPlatformChannelSpecifics = new AndroidNotificationDetails(
'your channel id', 'your channel name', 'your channel description',
importance: Importance.Max, priority: Priority.High);
var iOSPlatformChannelSpecifics = new IOSNotificationDetails();
var platformChannelSpecifics = new NotificationDetails(
androidPlatformChannelSpecifics, iOSPlatformChannelSpecifics);
await flutterLocalNotificationsPlugin.show(
0,
'Learn Local Notification',
'A Local Notification On Button Click',
platformChannelSpecifics,
payload: 'Default_Sound',
);
}
Future scheuleAtParticularTime(DateTime timee) async {
var time = Time(timee.hour, timee.minute, timee.second);
print(time.toString());
var androidPlatformChannelSpecifics = new AndroidNotificationDetails(
'repeatDailyAtTime channel id',
'repeatDailyAtTime channel name',
'repeatDailyAtTime description');
var iOSPlatformChannelSpecifics = new IOSNotificationDetails();
var platformChannelSpecifics = new NotificationDetails(
androidPlatformChannelSpecifics, iOSPlatformChannelSpecifics);
flutterLocalNotificationsPlugin.showDailyAtTime(0, 'Hey! Check your
today`s horoscope ',
'Login now to see your today`s horoscope !', time,
platformChannelSpecifics);
print('scheduled');
Fluttertoast.showToast(
msg:
"Notification Scheduled for ${time.hour} : ${time.minute} :
${time.second}",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.BOTTOM,
// also possible "TOP" and "CENTER"
backgroundColor: Colors.grey,
textColor: Colors.white);
setState(() {
nhour = time.hour.toString();
nminutes=time.minute.toString();
nseconds=time.second.toString();
notifyTime=nhour+" : "+nminutes+" : "+nseconds;
});
}
//function ends
#override
Widget build(BuildContext context) {
return Scaffold(backgroundColor: Theme.of(context).primaryColor,
appBar: AppBar(backgroundColor: Theme.of(context).primaryColor,
leading: IconButton(icon: Icon(FontAwesomeIcons.arrowLeft,
//backgroundColor: Theme.of(context).primaryColor,
), onPressed: () => {
Navigator.pop(context),}),
title: Text('Setting'),
),
body: Theme( data: Theme.of(context).copyWith(
canvasColor: Theme.of(context).primaryColor, //This will change the drawer background to blue.),
child: Center(
child: Container(
height: MediaQuery
.of(context)
.size
.height - 60.0,
child: ListView(
scrollDirection: Axis.horizontal,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 60.0),
child: RaisedButton(
color: Color(0xffffffff),
child: Text('Notification time - $notifyTime',////NEED TO STORE LAST VALUE HERE////////
style: TextStyle(
color: Color(0xff6200ee),
),),
onPressed: () {
DatePicker.showTimePicker(context, showTitleActions: true,
onChanged: (date) {
print('change $date');
}, onConfirm: (date) {
print('confirm $date');
scheuleAtParticularTime(
DateTime.fromMillisecondsSinceEpoch(
date.millisecondsSinceEpoch));
}, currentTime: DateTime.now(), locale: LocaleType.en);
},
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
30.0),)
),
),
],),
),
);
}
}

you can use the shared_preferences plugin to store data on the device and use it in the app, even after it restarts.
First import the shared preferences plugin:
import 'package:shared_preferences/shared_preferences.dart';
To store data, simply do:
SharedPreferences prefs = await SharedPreferences.getInstance();
bool storedSuccessfully = await prefs.setString('<Your_Key>', <Your_String_Value>);
To get the stored data:
SharedPreferences prefs = await SharedPreferences.getInstance();
String storedValue = prefs.getString('<YOUR-KEY>');
So in your case, every time a user selects the value, you just have to store it with a key, and then every time the app restarts, simply fetch that value using the key you gave it, and use it.

Related

Flutter Schedule Notification

i've added schedule notification to my app, all code is running well without no error but the schedule is not showing anyway. Here is my code:
The code
Here i' m calling schedule notification:
onPressed: () {
NotifcationApi.showScheduleNotification(
title: "sdad",
body: "sdaasd",
payload: 'come see it',
scheduleDate:
DateTime.now().add(const Duration(seconds: 3)));
final snackBar = SnackBar(
content: Text(
"dssad",
style: TextStyle(fontSize: 24),
),
backgroundColor: Colors.green,
);
ScaffoldMessenger.of(context)
..removeCurrentSnackBar()
..showSnackBar(snackBar);
},
here i initialized
class _CalednarOrtodoxState extends State<CalednarOrtodox> {
#override
void initState() {
super.initState();
NotifcationApi.init(initScheduled: true);
}
I don't know why is not working.
Can someone pls help me in this way?

How to place a Loader on the screen while an API action is being performed in Flutter

I am trying to show a loader when a form is submitted to the server so that there isn't another submission of the same form until and unless the API sends back a response. I have tried something like the below code but it just doesn't seem to work as the Circular Progress indicator seems to not show up and rather, the screen remains as it is until the server sends back a response. As a result of this, the user gets confused as to whether or not their requests got submitted, and in the process, they end up posting the same form another time only to find out later that their were multiple submissions. I will include snippets of the code that has the CircularProgressIndicator() to prevent another submission and the widget that has the API call code.
bool isSelected = false;
isSelected
? const CircularProgressIndicator() : Container(
child: Center(
child: AppButtonStyle(
label: 'Submit',
onPressed: () {
if (_key.currentState!.validate()) { //This is the key of the Form that gets submitted
setState(() {
isSelected = true;
});
List<String> date = [
dateFormat.format(_dateTimeStart!).toString(),
dateFormat.format(_dateTimeEnd!).toString()
];
Map<String, dynamic> data = {
'leave_type': _selectedItem,
'dates': date,
'description': add
};
if (kDebugMode) {
print('DATA: $data');
}
Provider.of<LeaveViewModel>(context, listen: false)
.postLeaveRequests(data, context) //This here makes the API call
.then((value) {
setState(() {
isSelected = false;
_textController.clear();
_dateTimeStart = null;
_dateTimeEnd = null;
});
});
}
},
),
),
)
The API module:
class LeaveViewModel with ChangeNotifier {
final leaveRepository = LeaveRequestRepository();
Future<void> postLeaveRequests(dynamic data, BuildContext context) async {
SharedPreferences localStorage = await SharedPreferences.getInstance();
String authToken = localStorage.getString('token').toString();
leaveRepository.requestLeave(authToken, data).then((value) {
print('LEAVEEEEEE: $value');
Flushbar(
duration: const Duration(seconds: 4),
flushbarPosition: FlushbarPosition.BOTTOM,
borderRadius: BorderRadius.circular(10),
icon: const Icon(Icons.error, color: Colors.white),
// margin: const EdgeInsets.fromLTRB(100, 10, 100, 0),
title: 'Leave Request Submitted',
message: value.data.toString()
).show(context);
}).onError((error, stackTrace) {
Flushbar(
duration: const Duration(seconds: 4),
flushbarPosition: FlushbarPosition.BOTTOM,
borderRadius: BorderRadius.circular(10),
icon: const Icon(Icons.error, color: Colors.white),
// margin: const EdgeInsets.fromLTRB(100, 10, 100, 0),
title: 'Leave Request Failed',
message: error.toString()
).show(context);
});
}
}
Any help will be appreciated. Also, I'm open to the concept of using easy_loader 2.0.0 instead of CicularProgressIndicator() and would be very glad to read suggestions about it's usage in my code.
One problem in your code seems to be that you define isSelected in your build method. Every time you call setState, the build method is called to regenerate the widgets. And with each new call isSelected gets false as initial value. Define isSelected as class variable, so that it is not always on false.
The more elegant solution would be to work with a FutureBuilder
https://api.flutter.dev/flutter/widgets/FutureBuilder-class.html

LateInitializationError: Field 'data' has not been initialized, got error

There is no error in this code but this error is coming after running,
Can someone please provide an example code of what's needed to solve for the error below?
"LateInitializationError: Field 'data' has not been initialized, got error"
This is my_home_page.dart.
import 'package:fi_digital_earn/DashBoards/PromoCode/provider/myHomePageProvider.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class MyHomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
ChangeNotifierProvider<MyHomePageProvider>(
create: (context) => MyHomePageProvider(),
child: Consumer<MyHomePageProvider>(
builder: (context, provider, child) {
if (provider.data == null) {
// print("prov $provider.data");
provider.getData(context);
return Center(child: CircularProgressIndicator());
}
// when we have the json loaded... let's put the data into a data table widget
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
// Data table widget in not scrollable so we have to wrap it in a scroll view when we have a large data set..
child: SingleChildScrollView(
child: DataTable(
columns: [
// DataColumn(
// label: Text('Verified'),
// tooltip: 'represents if user is verified.'),
DataColumn(
label: Text('Pin ID'),
tooltip: 'represents first pin id of the user'),
DataColumn(
label: Text('Pin Name'),
tooltip: 'represents pin name of the user'),
DataColumn(
label: Text('Used/Unused'),
tooltip: 'represents Used/Unused of the user'),
DataColumn(
label: Text('Date'),
tooltip: 'represents date of the user'),
],
rows: provider.data.results
.map((data) =>
// we return a DataRow every time
DataRow(
// List<DataCell> cells is required in every row
cells: [
// DataCell((data.verified)
// ? Icon(
// Icons.verified_user,
// color: Colors.green,
// )
// : Icon(Icons.cancel, color: Colors.red)),
// I want to display a green color icon when user is verified and red when unverified
DataCell(Text(data.pin_id)),
DataCell(Text(data.pin_name)),
DataCell(
RaisedButton(
onPressed: () {},
color: data.used_pin == "1"
? Colors.green
: Colors.red,
shape: new RoundedRectangleBorder(
borderRadius:
new BorderRadius.circular(30.0),
),
// shape: Border.all(
// color: Colors.purple,
// width: 2.0,
// ),
// splashColor: Colors.cyan,
// highlightColor: Colors.blue,
child: data.used_pin == "1"
? Text("Useed")
: Text("Unused")),
),
DataCell(Text(data.pin_date)),
]))
.toList(),
),
),
);
},
),
),
],
),
);
}
}
This is my Provider part.
import 'dart:convert';
import 'package:fi_digital_earn/DashBoards/PromoCode/model/myData.dart';
import 'package:flutter/widgets.dart';
import 'package:http/http.dart' as http;
class MyHomePageProvider extends ChangeNotifier {
late MyData data;
Future getData(context) async {
var url = Uri.parse(
'https://software.oceonicitsolution.com/hrms/v3/mlm_api/v1/PromoCodeApi.php');
var response = await http.get(url);
print("res${response.body}");
// now we have response as String from local json or and API request...
var mJson = json.decode(response.body);
// print("mjson" + mJson);
this.data = MyData.fromJson(mJson);
// this.data = http.post(mJson) as MyData;
this.notifyListeners(); // for callback to view
}
}
This is my Model part
class MyData {
List<Results> results = [];
MyData.fromJson(Map<String, dynamic> json) {
// previous = json['previous'];
// next = json['next'];
if (json['results'] != null) {
results = <Results>[];
json['results'].forEach((v) {
results.add(new Results.fromJson(v));
});
}
}
}
class Results {
String pin_id = "";
String pin_name = "";
String used_pin = "";
String pin_date = "";
Results.fromJson(Map<String, dynamic> json) {
pin_id = json['pin_id'];
pin_name = json['pin_name'];
used_pin = json['use_unuse'];
pin_date = json['pin_date'];
}
}
You don't want a late variable, you want a nullable one. If you need to check if something is initialized, you should be using a nullable variable instead and your code is already set up to check for null.
Just change
late MyData data;
to
MyData? data;
You can change it to :
MyData data = MyData(); //by initializing it.
//or by making it nullable.
MyData? data;
I had this problem when i try to compare late value in if statement.
how i solved, i gave some not important value before statement. Problem has ben solved.
I faced the same issue while using the Google Maps API in flutter, the solution was to provide the correct permission in AndroidManifest.xml:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />

State does not update until button is pressed twice

I am trying to learn and work with APIs, I am using the Tiingo Stock API to get stock info. My current app is:
class _StockAppState extends State<StockApp> {
String out = "Enter Ticker and press Submit";
Map<String,String> headers = {
'Content-Type': 'application/json',
'Authorization' : <API KEY REMOVED>
};
void getPrice(String tick) async {
if(tick == ""){
out = "Enter Ticker and press Submit";
}else{
Response rep = await get('https://api.tiingo.com/tiingo/daily/$tick/prices', headers: headers);
if(rep.statusCode == 200){
List data = json.decode(rep.body);
Map dataS = data[0];
out = "Price: ${dataS['close']}";
}else{
out = "Error";
}
}
}
#override
void initState() {
super.initState();
}
TextEditingController ticker = new TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Stock App'),),
body: Column(
children: <Widget>[
TextField(
controller: ticker,
textAlign: TextAlign.left,
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'Enter Ticker',
hintStyle: TextStyle(color: Colors.grey),
),
),
FlatButton(
onPressed: () async {
FocusScope.of(context).unfocus();
setState(() {
getPrice(ticker.text);
});
},
child: Text('Submit')
),
Text(out),
],
),
);
}
}
So, basically, when you enter a ticker and press submit, the app will change the "out" string var to display the stock price. But for the app to update, I am having to press submit twice.
Could anyone help?
P.S.: I have removed my API key for security reasons.
It is because you have async method in your setState method.
The setState method will be called synchronously.
So here problem is when setState is performed and frame get refreshed your data from api has not arrived yet and it showing you the old data. When you again click the button your out variable have new data (from your first click) which will be shown on the screen and API will be called again.
To solve your problem
FlatButton(
onPressed: () async {
FocusScope.of(context).unfocus();
await getPrice(ticker.text);
setState(() {
});
},
child: Text('Submit')
),
So call the setState method after API call is completed.
To know more about async/await watch this video : https://www.youtube.com/watch?v=SmTCmDMi4BY

Flutter: Progress dialog is not hiding

I am using progress_dialog 1.2.0 package to show a progress dialog in my app, it is showing when I call pr.show() but not getting hidden when I call pr.hide():
onTap: () async {
pr.show();
print('clicked custom category');
print(categorylist[index].catName);
print(categorylist[index].catId);
// await getAllProductsInCategory(categorylist[index].catId);
setState(() {
catId = categorylist[index].catId;
myinitlist.clear();
myinitlist = List.from(productList);
pr.hide();
});
},
When I uncomment that getAllProductsInCategory() function it hides the dialog.
Try with :
onTap: () async {
pr.show();
print('clicked custom category');
print(categorylist[index].catName);
print(categorylist[index].catId);
setState(() {
catId = categorylist[index].catId;
myinitlist.clear();
myinitlist = List.from(productList);
Future.delayed(Duration(seconds: 3)).then((value) {
pr.hide().whenComplete(() {
print(pr.isShowing());
});
});
});
},
or :
onTap: () async {
pr.show();
print('clicked custom category');
print(categorylist[index].catName);
print(categorylist[index].catId);
Future.delayed(Duration(seconds: 3)).then((value) {
setState(() {
catId = categorylist[index].catId;
myinitlist.clear();
myinitlist = List.from(productList);
pr.hide().whenComplete(() {
print(pr.isShowing());
});
});
});
},
Please use await keyword when you are using async calls to start progressDialog & hide:
await progressDialog.show();
await progressDialog.hide();
Example:
Add the Package:
dependencies:
progress_dialog: ^1.2.4
import 'package:progress_dialog/progress_dialog.dart';
Create and initialize a ProgressDialog object inside the build() method passing context to it.
Initialize the ProgressDialog object:
final ProgressDialog pr = ProgressDialog(context);
By default it is a normal dialog to show some message, if you would like to use it to show percentage of progress done, specify the optional type parameter and specify if you want your dialog to dismiss when back button is pressed isDismissible parameter (Optional):
//For normal dialog
pr = ProgressDialog(context,type: ProgressDialogType.Normal, isDismissible: true/false, showLogs: true/false);
//For showing progress percentage
pr = ProgressDialog(context,type: ProgressDialogType.Download, isDismissible: true/false, showLogs: true/false);
> Note: Please initialize the ```ProgressDialog```, where you have availability of the context
Style the progress dialog (Optional)
pr.style(
message: 'Downloading file...',
borderRadius: 10.0,
backgroundColor: Colors.white,
progressWidget: CircularProgressIndicator(),
elevation: 10.0,
insetAnimCurve: Curves.easeInOut,
progress: 0.0,
textDirection: TextDirection.rtl,
maxProgress: 100.0,
progressTextStyle: TextStyle(
color: Colors.black, fontSize: 13.0, fontWeight: FontWeight.w400),
messageTextStyle: TextStyle(
color: Colors.black, fontSize: 19.0, fontWeight: FontWeight.w600)
);
Note: You don't need to use all parameters, all of them are optional.
Showing the progress dialog:
await pr.show();
Dynamically update the content shown out there
pr.update(
progress: 50.0,
message: "Please wait...",
progressWidget: Container(
padding: EdgeInsets.all(8.0), child: CircularProgressIndicator()),
maxProgress: 100.0,
progressTextStyle: TextStyle(
color: Colors.black, fontSize: 13.0, fontWeight: FontWeight.w400),
messageTextStyle: TextStyle(
color: Colors.black, fontSize: 19.0, fontWeight: FontWeight.w600),
);
Dismissing the progress dialog:
pr.hide().then((isHidden) {
print(isHidden);
});
// or
await pr.hide();
Navigating to next screens must be done after the completion of Future - hide(). See here for example.
Check if progress dialog is showing:
bool isProgressDialogShowing = pr.isShowing();
print(isProgressDialogShowing);
Use custom body
pr = ProgressDialog(
context,
type: ProgressDialogType.Normal,
isDismissible: true,
/// your body here
customBody: LinearProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Colors.blueAccent),
backgroundColor: Colors.white,
),
);
For more details: https://flutterrepos.com/repo/fayaz07-progress_dialog-