Flutter save shared preferences of multiple users - flutter

I have two types of settings which I want to save on the users apps device. First is filter settings, second is if user is opening the app the very first time.
For filter I have multiple bools to save, for the first open app value I just need a single bool. Now my problem is if I log into the app with another account, the values of the first account are choosen. I need to make a set for each account, but I dont know how, since im changing single values all the time.
these are my functions for getting and setting a filter:
void putShared(String key, bool val) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setBool(key, val);
}
Future getShared(String key) async {
final prefs = await SharedPreferences.getInstance();
bool val = prefs.getBool(key) == null ? false : (prefs.getBool(key));
return val;
}
So how to change the code to make it work for multiple accounts?

You can add a unique user id as a prefix to all the keys. Like..
void putShared(String key, bool val) async {
String userSpecificKey = userID + key;
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setBool(userSpecificKey, val);
}
Future getShared(String key) async {
String userSpecificKey = userID + key;
final prefs = await SharedPreferences.getInstance();
bool val = prefs.getBool(userSpecificKey) == null ? false : (prefs.getBool(userSpecificKey));
return val;
}

What I suggest is while saving the values in the sharedprefrences you rather use a map where the key must be unique like id and value of what you need. Then just encode the map which will convert it to string and then you can save it as string in sharedPrefrences and then when you retrive you just decode the map and just check if the loggedin user id matches the id which you have logged in if not do not fetch the values else fetch them.

Related

SetState and Shared Preferences returning null

I am having trouble identifying as to why setState() is returning null on my shared preferences getString method.
I am calling an async function outside of the initState and the constantly printing null when i check the return string of getString on page load.
I have checked that setString is saving the correct string to the key.
Here is my code:
void initState() {
super.initState();
retrieve();
}
retrieve() async {
final prefs = await SharedPreferences.getInstance();
setState(() {
name = prefs.getString("displayName");
print(name);
});
}
Here is where I setString(in the register user page):
try {
UserCredential result =
await FirebaseAuth.instance.createUserWithEmailAndPassword(
email: _emailController.text,
password: _passwordController.text,
);
final user = FirebaseAuth.instance.currentUser;
final name = _usernameController.text;
// if (user != null) {
await user?.updateDisplayName(name);
Navigator.pushNamed(context, homeRoute);
print(name);
You should set ,username via shared preference before accessing it.
final prefs = await SharedPreferences.getInstance();
In register page.(where you want to set name via SharedPreference before accessing it)
await prefs.setString('displayName', 'name');
After setting it in registeration you can access like above
name = prefs.getString("displayName");
When SharedPreferences return null value it means you have not set value with your key yet. So firstly set something like this:
final prefs = await SharedPreferences.getInstance().reload();
await prefs.setString('displayName', 'Mark');
then try to call it.
Thanks to all who have spent the time to respond to help. I hope this answer might help some one else down the track.
I found that Shared Preferences was not saving the data - my code was fine after all. I simply just closed the app and restarted the X code build from scratch and it is now working.....

Store data in dart/flutter

I am coding a to-do list app in flutter but every time I close the app, all my to-do's are gone, and none of them are stored. How do I stop them from disappearing every time I close the app?
Use sqlite or files. Please refer documentation on cookbooks for either approach.
https://docs.flutter.dev/cookbook/persistence
Your other option is to use an external database over the internet
To persist your data (todo list) you can either
store data on the users device
You can do this by using a local databases like sqflite, sqfentity, shared_preferences etc
or store the data on the server
Using this option you can either spin up your own server or use some quick serverless solutions like supabase or cloud firestore from firebase.
I recommend hive it’s very easy to use and it’s lightweigh.
In addition with all the other propositions, you can try Isar, which is a NoSQL local database that can be used for all platforms:
https://isar.dev/tutorials/quickstart.html
https://pub.dev/packages/isar
Apps generally store data in temporary storage which destroyed every time yo close the app. in order to save data permanently, you could use sqflite database or shared_preferences database
if you want use shared_preferences, you can do this:
first make class that call StorageManager:
import 'package:shared_preferences/shared_preferences.dart';
class StorageManager {
static Future<bool> saveData(String key, dynamic value) async {
final prefs = await SharedPreferences.getInstance();
await prefs.reload();
if (value is int) {
prefs.setInt(key, value);
return true;
} else if (value is String) {
prefs.setString(key, value);
return true;
} else if (value is bool) {
prefs.setBool(key, value);
return true;
} else {
return false;
}
}
static Future<dynamic> readData(String key) async {
final prefs = await SharedPreferences.getInstance();
await prefs.reload();
dynamic obj = prefs.get(key);
return obj;
}
static Future<bool> deleteData(String key) async {
final prefs = await SharedPreferences.getInstance();
return prefs.remove(key);
}
static Future<void> reloadSharedPreferences() async {
final prefs = await SharedPreferences.getInstance();
await prefs.reload();
}
}
then use it like this:
when you want save some thing in storage call this:
await StorageManager.saveData('some unique key', your int or string or bool value);
when you want read from storage:
var result = await StorageManager.readData('some unique key');
if (result != null) {
// use your value
} else {
// this means there is no result
}

How to save prefs to different scopes in Flutter?

I am trying to use shared prefs to store App Data and User Data differently, like this :
{
"APP_DATA": {
"banners": "{\"success\":true,\"data\":{}}",
"gameList": "{\"success\":true,\"data\":{}}"
},
"USER_DATA":
{
"emailVerified": "N",
"userName": "97144554455",
"playerToken": "W_8zUx3UCmFPeECjhhjhHhnnsajknHxAM0",
"idVerified": "UPLOADED",
"playerId": "412904",
"bankList": "{\"84\":\"African Bank\",\"5\":\"FNB : First National Bank\"}",
"unreadMsgCount": "0"
}
}
But whenever I update any value in "APP_DATA" or "USER_DATA", it deletes the previous value and updates new value. Example : After adding "banners" and "gamesList" to my APP_DATA, I only see "gamesList" because it is overriding the "banners" value.
MySharedPreferences.instance.setAppStringValue(
"banners", jsonEncode(bannersModel),
);
MySharedPreferences.instance.setAppStringValue(
"gamesList", jsonEncode(gamesListModel),
);
This is the function I'm using
setAppStringValue(String key, String value) async {
SharedPreferences myPrefs = await SharedPreferences.getInstance();
myPrefs.setString("APP_DATA", jsonEncode({key: value}));
}
How to solve this issue?
What is happening is that you are overriding the APP_DATA key with a whole new value (encoded String) which results in the previous data to be lost.
If you want to keep the same structure, this is, having a key for APP_DATA and other for USER_DATA, both having their own data, you'll need to fetch the previous stored data and append the new one into it so you make sure you don't lose it.
setAppStringValue(String key, String value) async {
SharedPreferences myPrefs = await SharedPreferences.getInstance();
final String storedData = myPrefs.get('APP_DATA');
final Map newData = {key: value};
try {
// Has previous data, decode it and append into the new one
if (storedData != null) {
newData.addAll(jsonDecode(storedData));
}
} catch (ex) {
print('Couldn\'t parse the stored data: $ex');
}
myPrefs.setString('APP_DATA', jsonEncode(newData));
}
When using shared preferences, it uses the unique key to recognise the value of the corresponding data. When you are writing data to the key 'APP_DATA' it will overwrite the entire string value. To change one value without overwriting the rest, you should save it in different keys. Like so,
setAppStringValue(String key, String value) async {
SharedPreferences myPrefs = await SharedPreferences.getInstance();
myPrefs.setString("banner", jsonEncode({key: value}));
}
setAppStringValue(String key, String value) async {
SharedPreferences myPrefs = await SharedPreferences.getInstance();
myPrefs.setString("gamesList", jsonEncode({key: value}));
}

What will be the name of SharedPreference created in flutter app?

I just new in flutter and coming from android,
In android we declare sharedPreference name like
SharedPreferences sp = Activity.this.getSharedPreferences("USER", MODE_PRIVATE);
by this in android USER.xml file was created,
So, what will be the name of sharedPreference in created by flutter app in this example?
how i store collection of data in sharedPreference,like
USER,
HOBBIES
TYPES,
etc
addIntToSF() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setInt('intValue', 123);
}
read data
getIntValuesSF() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
//Return int
int intValue = prefs.getInt('intValue');
return intValue;
}
You can take a look at the source code of the shared_preferences package:
// Line 37
private static final String SHARED_PREFERENCES_NAME = "FlutterSharedPreferences";
// ...
// Line 54
preferences = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
So the name is simply "FlutterSharedPreferences".
If you want to group entries by a model (e.g. User, HobbieType), you can add a prefix to each key:
addIntToSF() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
// Entries related to users
prefs.setInt('User_intValue', 123);
prefs.setString('User_strValue', "123");
prefs.setBool('User_boolValue', true);
// Entries related to hobbie types
prefs.setInt('HobbieType_intValue', 456);
prefs.setString('HobbieType_strValue', "456");
prefs.setBool('HobbieType_boolValue', false);
}

returning a String when getting error: type 'Future<dynamic>' is not a subtype of type 'String'

I can't work out how to return a string from a function in Dart (a Flutter app).
I am using SharedPreferences to capture input from the user. I have two functions, one to save preferences:
save(key, value) async {
final prefs = await SharedPreferences.getInstance();
prefs.setString(key, value);
print('saved $value');
}
and one to read preferences:
read(key) async {
final prefs = await SharedPreferences.getInstance();
final value = prefs.getString(key) ?? 0;
print('$value');
}
This is working, but when I try to replace the print line with a return:
read(key) async {
final prefs = await SharedPreferences.getInstance();
final value = prefs.getString(key) ?? 0;
return('$value');
}
to return a string for the value, it throws an error:
type 'Future' is not a subtype of type 'String'
I have tried calling it many MANY different ways, but can't figure out what I assume is an incredibly basic problem. I noticed in some posts that this is a suggested solution, which works to print out the value, but I don't want to print it, i want it as a String variable:
read(mykey).then((value) => '$value');
I need to combine the value with other some other string values and make some minor manipulations (so printing it isn't helpful)
UPDATE
I have defined the function as #Stijn2210 suggested, but am still having problems getting the output i need.
Future<String> read(key) async {
final prefs = await SharedPreferences.getInstance();
final value = await prefs.getString(key) ?? '';
return value;
}
When I call this function from my app (this is a simplified snippet):
void onDragEnd(DraggableDetails details, User user) {
final minimumDrag = 100;
Future<String> myvalue;
if (details.offset.dx > minimumDrag) {
user.isSwipedOff = true;
save(user.imgUrl, 'Dog');
}
myvalue = read(user.imgUrl);
print(myvalue);
It's printing :
Instance of 'Future'
Whereas I want myvalue to be 'Dog'... Appreciate any insights!!
Really appreciate your answer #Stijn2202
Solution was to edit the method definition:
Future<void> onDragEnd(DraggableDetails details, User user) async
and then call the read function from the method with this:
final String myvalue = await read(user.imgUrl);
getString is a Future, which you can handle by using await or as you are doing, using then
However, in my opinion using await is your better option. This would look like this:
Future<String> getMyString() async {
final prefs = await SharedPreferences.getInstance();
final value = await prefs.getString(key) ?? '';
// Don't use 0, since it isnt an int what you want to return
return value;
}
EDIT:
based on your code snippet, this is how you should call your read method:
Future<void> onDragEnd(DraggableDetails details, User user) async {
final minimumDrag = 100;
if (details.offset.dx > minimumDrag) {
user.isSwipedOff = true;
save(user.imgUrl, 'Dog');
}
final String myvalue = await read(user.imgUrl);
print(myvalue);
}
Now I'm not sure if onDragEnd is actually allowed to be Future<void>, but let me know if it isn't
Just await for the value. It will return Dog and not instance of Future.
String someName=await myvalue;
As the value is Future, await keyword will wait until the task finishes and return the value