How do I use sharedPreferences with booleans? - flutter

I am currently learning sharedPreferences and trying to set and get values to check if a button has been clicked or not.
This is my class for sharedPreferences
class UserSimplePrefences {
static SharedPreferences? _preferences;
static const _keyButton = 'buttonStatus';
static Future init() async {
_preferences = await SharedPreferences.getInstance();
}
static Future setButtonStatus(bool btnStatus) async {
await _preferences?.setBool(_keyButton, btnStatus);
}
static bool? getButtonStatus() {
return _preferences?.getBool(_keyButton);
}
}
here in my main.dart
I have a button.
bool? onLineStatus;
//
void initState() {
super.initState();
WidgetsBinding.instance?.addObserver(this);
onLineStatus = UserSimplePrefences.getButtonStatus() !;
displayToastMessage(onLineStatus.toString(), context);
}
//
#override
Widget build(BuildContext context) {
//
RaisedButton(
onPressed: () async {
if (UserOnline! =true) {
UserOnline = true;
await UserSimplePrefences.setButtonStatus(true);
displayToastMessage("You are Online now", context);
} else {
UserOnline =false;
await UserSimplePrefences.setButtonStatus(false);
displayToastMessage("You are Offline now", context);
}}
),
}
UserOnline is to toggle the button, works fine without SharedPreferences.
In more simple language, when I hit the button i.e Online and close the app and reopen the app sometime later I want the init statement to be called with the toast message as true and similarly when I click offline I want the init statement to call the toast false.
Issue: My toast message is always true.
`

add setState to your onPressed
onPressed: () async {
if (UserOnline! =true) {
UserOnline = true;
await UserSimplePrefences.setButtonStatus(true);
displayToastMessage("You are Online now", context);
setState(() {});
} else {
UserOnline =false;
await UserSimplePrefences.setButtonStatus(false);
displayToastMessage("You are Offline now", context);
setState(() {});
}}

Related

How to pass the changed value of a variable from a method to a condition in Flutter/Dart?

I check Internet access like this:
My code on the main page:
class _MainWidgetState extends State<MainWidget> {
CheckUserConnection _checkUserConnection = CheckUserConnection();
InternetDialogHandler _internetDialogHandler = InternetDialogHandler();
bool? _internetAvailable;
...
void checkNet() async{
_internetAvailable = await
_checkUserConnection.checkInternetAvailability();
setState((){});
}
My code on a different page because it is used on multiple screens.
class CheckUserConnection {
Future checkInternetAvailability() async {
try {
final result = await InternetAddress.lookup('example.com');
if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
return true;
}
} on SocketException catch (_) {
return false;
}
}
}
This works well, but there is a problem when checkNet() checks for Internet availability before a condition that has _internetAvailable.
In particular:
GradientButton(label: 'Continue Game', onTap: () {
checkNet();
_loadData();
return _internetAvailable == true ?
{Navigator.push(
context,
MaterialPageRoute(builder: (context) => Game(
listCount: _listCount, assetPath: assetPath ///What I want to pass
)),
)}
:
_internetDialogHandler.showInternetDialog(context);
}),
The situation is the following. First, there is Internet access. Respectively,
_internetAvailable=true.
Then I specifically turn off Internet access and press the button.
checkNet() will check _internetAvailable and leave this variable set to true. Accordingly, the condition is met. And this is wrong.
But when I click on the button next time, _internetAvailable takes the correct value, i.e. false.
My question is the following. Where am I making a mistake? I want checkNet() to change the value of _internetAvailable the first time correctly.
And yes, the problem is not in the Internet access. As an experiment, I used other variables. For example, _isFirstLoad = true. The situation is the same. The first time the button is pressed, the value of the variable does not change.
Use checkInternetAvailability() like this
class CheckUserConnection {
Future<bool> checkInternetAvailability() async {
try {
final result = await InternetAddress.lookup('example.com');
if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
return true;
}
} on SocketException catch (_) {
return false;
}
}
}

How to navigate to another page after using a provider function in flutter?

I have created a function in my Login provider to verify OTP for my app like below.
Future<bool> verifyOtp(String otp) async {
final _loginData = await SharedPreferences.getInstance();
_isLoading = true;
notifyListeners();
_status = await AuthApi.verifyOtp(otp);
_isLoading = false;
_name = _loginData.getString('name');
notifyListeners();
return _status;
}
Now whenever I am trying to use this on my code like below,
final bool status = await Provider.of<LoginProvider>(context, listen: false).verifyOtp(verificationCode);
// ignore: avoid_print
print("STATUS ==== " + status.toString());
if (status) {
Navigator.of(context).pushReplacementNamed('/discover');
} else {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("Incorrect OTP!!!")));
}
It's giving me an exception like below -
Exception has occurred.
FlutterError (This widget has been unmounted, so the State no longer has a context (and should be considered defunct).
Consider canceling any active work during "dispose" or using the "mounted" getter to determine if the State is still active.)
Anyone please guide me, what is the actual way to navigate from a provider. I am very new in Provider. Thank you so much :)
----- Full Provider Code is Below -----
class LoginProvider with ChangeNotifier {
bool _status = false;
bool _isLoading = false;
bool _isOtpScreen = false;
String? _name;
bool get isLoading => _isLoading;
bool get isOtpScreen => _isOtpScreen;
String? get name => _name;
void sendOtp(String phone) async {
_isLoading = true;
notifyListeners();
_status = await AuthApi.sendOtp(phone);
_isLoading = false;
_isOtpScreen = true;
notifyListeners();
}
Future<bool> verifyOtp(String otp) async {
final _loginData = await SharedPreferences.getInstance();
_isLoading = true;
notifyListeners();
_status = await AuthApi.verifyOtp(otp);
_isLoading = false;
_name = _loginData.getString('name');
notifyListeners();
return _status;
}
}
Use a GlobalKey you can access from anywhere to navigate
Create the key
final GlobalKey<NavigatorState> navigatorKey = new GlobalKey<NavigatorState>();
void main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(MyApp());
}
Pass it to your App:
new MaterialApp(
title: 'MyApp',
onGenerateRoute: generateRoute,
navigatorKey: navigatorKey,
);
Use in your route:
print("STATUS ==== " + status.toString());
if (status) {
Navigator.of(navigatorKey.currentContext).pushReplacementNamed('/discover');
} else {
ScaffoldMessenger.of(navigatorKey.currentContext).showSnackBar(const SnackBar(content:
Text("Incorrect OTP!!!")));
}
final bool status = await Provider.of<LoginProvider>(context, listen: false).verifyOtp(verificationCode);
// ignore: avoid_print
print("STATUS ==== " + status.toString());
if (status) {
Navigator.of(context).pushReplacementNamed('/discover');
} else {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("Incorrect OTP!!!")));
}
change this code to the next one and i think it will work
but you must add this code in build function if it's stateless widget
final provider = Provider.of<LoginProvider>(context);
final status = await provider.verifyOtp(verificationCode);
// ignore: avoid_print
print("STATUS ==== " + status.toString());
if (status) {
Navigator.of(context).pushReplacementNamed('/discover');
} else {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("Incorrect OTP!!!")));
}
this will work fine with you i hope it help you

Display Loading spinner waitint for request to complete while using provider package

I am using a provider package. I want to display a loading spinner while waiting for a request to complete. The pattern below is too verbose. Please help me make it less verbose. Here is my code
class APIService with ChangeNotifier {
// Check for working API backend
bool isWorking = false;
bool isLoading = false;
set _isLoading(bool value) {
isLoading = value; <--
notifyListeners();
}
Future<bool> selectAPI(String input) async {
_isLoading = true; <-- 1
final uri = Uri.tryParse('https://$input$url')!;
final response = await http.get(uri);
if (response.statusCode == 200) {
final body = jsonDecode(response.body) as Map<String, dynamic>;
bool isTrue = body['info']['title'] == 'SamFetch';
_isLoading = false; <-- 2
notifyListeners();
return isWorking = isTrue;
}
_isLoading = false; <-- 3
throw response;
}
}
Here is my UI code
IconButton(
icon: apiService.isLoading
? CircularProgressIndicator()
: Icon(Icons.done),
onPressed: () async {
await addAPI(apiService, cache);
}),
}
Below is addAPI() method
Future<void> addAPI(APIService apiService, Cache cache) async {
if (api != null) {
try {
await apiService.selectAPI(api!);
if (apiService.isWorking) {
await cache.saveAppName(api!);
}
} on SocketException catch (e) {
print(e);
} catch (e) {
await cache.clearCache();
}
}
}
Is setState the final solution?
You can use Future Builder and set your Future Function in future attribute. You can control the visible widget based on the status of your function. So you dont have to use isloading variable.

Flutter how to handle time based events?

I am having a widget in the flutter which can be dismissed by watching a rewarded video. But I don't want the widget to be completely dismissed. Say for 3 days.
So if the user clicks on the specific widget then the ads will be disabled for 3 days. Is it possible to do? Could someone help me with references or ideas to get this done?
Please help
First, Get shared preferences Package to make local storage to track the Date shared_preferences: ^2.0.5
Make A Local Storage like this -
import 'package:shared_preferences/shared_preferences.dart';
class SetUserLocalStorage {
Future<SharedPreferences> _prefs = SharedPreferences.getInstance();
void date(String valueOfDate) async {
final SharedPreferences prefs = await _prefs;
prefs.setString(UserStorageKey().valueOfDate, valueOfDate);
}
void clear() async { // For Your Further Operation, If needed
final SharedPreferences prefs = await _prefs;
prefs.clear();
}
}
class GetUserLocalStorage {
Future<SharedPreferences> _prefs = SharedPreferences.getInstance();
Future<String> date() async {
final SharedPreferences prefs = await _prefs;
return prefs.getString(UserStorageKey().valueOfDate);
}
}
class UserStorageKey {
String get valueOfDate => "valueOfDate";
}
Now, in your page / Screen, Define Variable -
bool _showTheAd = false;
DateTime _now = DateTime.now();
DateTime _date = DateTime.now();
and In InitState, Start Checking the Condition on the base of Time,I am making it in three part for better understanding
#override
void initState() {
super.initState();
_initialPoint();
}
in _initialPoint() -
void _initialPoint() async {
await GetUserLocalStorage().date().then((value) {
setState(() {
_date = DateTime.parse(value);
});
}).then((value) {
_conditionCheck();
});
}
In _conditionCheck -
void _conditionCheck() {
if (_date == null) {
setState(() {
_showTheAd = true;
});
} else {
setState(() {
_now = DateTime.now();
});
if (_now.isAfter(_date)) {
setState(() {
_showTheAd = true;
});
}
}
}
I know that,these are like "dirty code", but I think that will help you understand the scenario.
in body, show the add based on the _showTheAd condition, and use some interceptor / listener of kind to sense when the video is end,I am using an inkwell, and execute the code in onTap(), full scenario -
Container(
child: Column(
children: [
if (_showTheAd)
InkWell(
onTap: () {
setState(
() {
_date = _now.add(
Duration(seconds: 5),
); // to add Date _now.add(Duration(days:3));
},
);
SetUserLocalStorage().date(_date.toIso8601String());
},
child: Center(
child: Container(
height: 120,
width: 120,
color: Colors.red,
child: Text("the ad"),
),
),
)
],
),
),

How to save event with sharedpreference in flutter

Hello I try to use this timeline package.
https://github.com/softmarshmallow/flutter-timeline
It's work fine to create timeline after press button but I don't success to save events with sharedpreference. I would like to restore history of the timeline at the initState.
TimelineEventDisplay get plainEventDisplay {
return TimelineEventDisplay(
child: TimelineEventCard(
title: Text("just now"),
content: Text("someone commented on your timeline ${DateTime.now()}"),
),
indicator: TimelineDots.of(context).circleIcon);
}
List<TimelineEventDisplay> events;
Widget _buildTimeline() {
return TimelineTheme(
data: TimelineThemeData(lineColor: Colors.blueAccent),
child: Timeline(
indicatorSize: 56,
events: events,
));
}
void _addEvent() {
setState(() {
events.add(plainEventDisplay);
});
}
#override
void initState() {
events = [
plainEventDisplay,
];
}
Create a SharedPref class so that it would be easy for you to manage things.
import 'package:shared_preferences/shared_preferences.dart';
import 'dart:convert';
class SharedPref {
read(String key) async {
final prefs = await SharedPreferences.getInstance();
if(prefs.getString(key) == null){
return null;
}
final map = jsonDecode(prefs.getString(key));
return map;
}
save(String key, value) async {
final prefs = await SharedPreferences.getInstance();
prefs.setString(key, jsonEncode(value));
}
remove(String key) async {
final prefs = await SharedPreferences.getInstance();
prefs.remove(key);
}
}
In your Flutter widget, create initState as follows:
SharedPref _prefs = SharedPref();
final events;
#override
void initState() async {
super.initState();
events = await _prefs.read('events');
}
void _addEvent() async {
setState(() {
events.add(plainEventDisplay);
});
await _prefs.save('events', events);
}