how can i store multiple data in sharedpreferences? - flutter

I am getting user information like the username , profile pic and name .I want to store all that info inside Sharedpreferences so that i wont have to call firebase every time I need them.
here is how i am getting the data ,how can i store this data so that later on i can get user's name and its profilepic by checking it through its username ?
storeUsersInfo()async{
print('STORE CALLED');
QuerySnapshot querySnapshot = await DatabaseMethods().getUsers();
var length = querySnapshot.docs.length ;
print(length);
int i = 0 ;
while ( i < length ) {
print(name = "${querySnapshot.docs[i]["name"]}");
print(profilePicUrl = "${querySnapshot.docs[i]["profileURL"]}");
i++;
}
}
here is the firebase call
Future<QuerySnapshot> getUsers() async {
return await FirebaseFirestore.instance
.collection("users")
.get();
}
and if anyone needs anything else please ask .

You can store all the information in SharePreference by encoding picture objects to Base64String before storing them.
How you can encode it:
Future<String> encodeImageToBase64String(String imageUrl) async {
final response = await client.get(Uri.parse(imageUrl));
final base64 = base64Encode(response.bodyBytes);
return base64;
}
After Encoding the image, you can cache it to sharedPreference using
SharedPreferences pref = await SharedPreferences.getInstance();
//Save string to SharedPreference
pref.setString('image', encodedImageString);
How to Decode and use Image Later
//Get Encoded Image String from SharedPreferences
final base64String = pref.getString('image');
///Decodes Images file encoded to Base64String to Image
Uint8List decodeImageFromBase64String(String base64String) {
return base64Decode(base64String);
}
Finally, you can use this in your Image Widget like so
...
Image(image: MemoryImage(decodeImageFromBase64String))
Assuming you want to cache name, username and image gotten from firebase
//Create a model for the firebase data
class UserModel{
final String name;
final String username;
final String encodedImage;
UserModel(this.name, this.username, this.encodedImage);
String toJson(){
Map<String, dynamic> userMap = {
'name': name,
'username': username,
'image': encodedImage,
};
return json.encode(userMap);
}
}
//Encode the image HERE
encodeImageToBase64String(imageUrl);
//Pass in the parameters to the UserModel() constructor and Call //the toJson(), then Cache the Resulting String
String stringToCache = UserModel(nameString, usernameString, encodedImageString).toJson();

SharedPreferences takes a key and the data.
use this in an async funtion.
This syntax is sharedPreferences.setString(key, value)
So in a function,
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
sharedPreferences.setString("token", jsonResponse['access_token'].toString());
sharedPreferences.setString("userId", jsonResponse['customer_id'].toString());
You can get the stored data by sharedPreferences.getString(key).Like
var token = sharedPreferences.getString("token");

You can use a cache like https://pub.dev/packages/firestore_cache which does that for you.

Related

How can I return two string values in dart flutter

I am working on my flutter project where I want to use sharedpreferences. Look at the code below:
Future<String?> getCredentials() async {
final localStorage = await SharedPreferences.getInstance();
final email = localStorage.getString('email');
final password = localStorage.getString('password');
return email, password;
}
This is my getCredentials funtion I want this function to return email and password as different parameters but dart doesn't allow me can you please help me How can I do it?
Whole SharedPreference Code:
import 'package:shared_preferences/shared_preferences.dart';
class sharedPreference {
Future<String?> saveCredentials({
required String email,
required String password,
}) async {
final localStorage = await SharedPreferences.getInstance();
await localStorage.setString('email', email);
await localStorage.setString('password', password);
}
Future<String?> getCredentials() async {
final localStorage = await SharedPreferences.getInstance();
final email = localStorage.getString('email');
final password = localStorage.getString('password');
return email, password;
}
}
Just create class. You can even add methods to Credentials later. Like secure compare to compare passwordHash with constant time.
class Credentials {
Credentials(this.email, this.passwordHash);
final String email;
final String passwordHash;
}
Future<Credentials> getCredentials() async {
final localStorage = await SharedPreferences.getInstance();
final email = localStorage.getString('email');
final passwordHash = localStorage.getString('passwordHash');
return Credentials(email, passwordHash));
}
Edit use crypto to get hash of password:
import 'dart:convert';
import 'package:crypto/crypto.dart';
String getHash(String plainPassword) {
return sha256.convert(utf8.encode(plainPassword)).toString();
}
change return type String to Map<String,dynamic>
Future<Map<String,dynamic>> getCredentials() async {
final localStorage = await SharedPreferences.getInstance();
final email = localStorage.getString('email');
final password = localStorage.getString('password');
return {
'email':email,
'password':password
};
}

Save ImagePicker Image in Shared Preferences - Flutter

I'm trying to save image picked from ImagePicker and store it in shared preferences and then retrieve it from there but no luck so far
To make my question more specific, how to save an image as a string in shared preference and then later retrieve it
Here is my code
File? profileImage;
void saveData(String key, String value) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString(key, value);
}
void getData(String key) async {
final prefs = await SharedPreferences.getInstance();
final image = await prefs.getString(key);
setState(() {
profileImage = image; //this would result into error because profileImage expect file type value
});
}
Future pickProfile() async {
final profileImagePicker = await ImagePicker().pickImage(source: ImageSource.gallery);
final File profile = File(profileImagePicker!.path);
final directoryPath = await getApplicationDocumentsDirectory();
final path = directoryPath.path;
final imageFile = await File(profileImagePicker.path).copy('$path/image1.png'); // What am I supposed to do after this step
saveData('profile', path); what value needs to be stored here, it expects a string
setState(() {
profileImage = profile;
});
}
To convert image into String you can use below code
final bytes = imageFile.readAsBytesSync();
String imageString = base64Encode(bytes);
To convert String to Image
Uint8List bytes = BASE64.decode(base64ImageString);
You can use the Image widget to diplay the Image
Image.memory(bytes);

save map locally and use it elsewhere

I'm converting a map to a string in order to save it to the device memory
_read() async {
try {
final directory = await getApplicationDocumentsDirectory();
final file = File('${directory.path}/answers.txt');
String text = await file.readAsString();
print(text);
} catch (e) {
print("Couldn't read file");
}
}
_save() async {
final directory = await getApplicationDocumentsDirectory();
final file = File('${directory.path}/answers.txt');
await file.writeAsString(answers.toString());
print('saved');
}
now I want to use it as a map to access the data on the map. is there a way to do it?
my map looks like this {Everyone should read...: Harry Potter, Two truths and a lie...: something, I can quote every line from...: the alchemist}
What you want is a JSON file.
JSON is a special syntax that can be used to store maps and lists in a file.
There is a catch though: You may only store maps and lists of primitive values like string, int or bool, a custom class, for example, cannot be stored in a JSON file. You would have to convert it into a map first.
In order to turn a JSON string into a map, you can use the jsonDecode function. Similarly, the jsonEncode function will return a string from a map.
Here goes the code:
Future<Map<String, dynamic>> _read() async {
final file = File(filePath);
final jsonStr = await file.readAsString()
return jsonDecode(jsonStr) as Map<String, dynamic>>;
}
Future<void> _write(Map<String, dynamic> map) async {
final jsonStr = jsonEncode(map);
final file = File(filePath);
await file.writeAsString(jsonStr);
}
In my code I skipped the try-catch block and the Directory thing, that's just to make the example simpler.

is there way to get a particular data which have been saved using shared preference?

#i Saved all my user data using shared preference to perform autologin and it works well data is saved
token = responseData['token'];
userEmail = responseData['user_email'];
userNicename = responseData['user_nicename'];
userDisplayName = responseData['user_display_name'];
userAddress = responseData['user_address'];
userContact = responseData['user_contact'];
userId = responseData['user_id'];
userDisplayUrl = responseData['user_display_url'];
notifyListeners();
SharedPreferences prefs = await SharedPreferences.getInstance();
final userData = jsonEncode({'token':token,'user_email':userEmail,'user_nicename':userNicename,'user_display_name':userDisplayName,'user_address':userAddress,'user_contact':userContact,'user_id':userId,'user_display_url':userDisplayUrl});
prefs.setString('userData',userData);
#Data is saved in this manner
{"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczpcL1wvc3dlZXQtYXJkaW5naGVsbGkuMy0xMDgtMTM4LTIwNi5wbGVzay5wYWdlIiwiaWF0IjoxNjQyMzMwNzQyLCJuYmYiOjE2NDIzMzA3NDIsImV4cCI6MTY0MjkzNTU0MiwiZGF0YSI6eyJ1c2VyIjp7ImlkIjoiMjgifX19.2jZEu-QNL3UxRiFSgVE728bF_cl_CZd0VJLT1f5HfCc","user_email":"sauravadhikari404#gmail.com","user_nicename":"sauravadhikari404","user_display_name":"SauravAdhikari404","user_address":null,"user_contact":null,"user_id":"28","user_display_url":""}
#now i wanna access single single data like i wanna get that user_id only or user_email only but i dont know how to do it i tried like this
String? userData;
#override
void initState(){
// TODO: implement initState
getUserId();
super.initState();
}
void getUserId()async{
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
userData = prefs.getString("userData");
print(userData);
});
}
#as i mentioned above all my data is comming in userData but now i wanna fetch my user_id only or user_email but i am unable to
Use jsonDecode to convert it to a Map:
Like so:
setState(() {
var userId = jsonDecode(prefs.getString("userData"))["user_id"];
print(userId);
});
To handle the null case:
String? userDataString = prefs.getString("userData");
if(userDataString != null){
var userId = jsonDecode(userDataString)["user_id"];
var email = jsonDecode(userDataString)["user_email"];
}

Flutter cannot get download url firebase-storage

While trying to upload byteArray to the bucket in firebase storage, the file uploads to the storage but I cannot get the downloadUrl back from the file. I am getting the reference of bucket like this:
Future<Reference> get storageRef async {
final _bucketUrl = await bucketUrl;
return FirebaseStorage.instanceFor(bucket: _bucketUrl).ref();
}
And Uploading image like this:
Future<String> uploadImageByteArray({
#required Uint8List byteArray,
String fileName,
}) async {
final name = fileName ?? DateTime.now().toIso8601String();
final _ref = await storageRef;
final _refUrl = _ref.child("images/$name.png");
print(_refUrl.fullPath);
final uploadTask = _refUrl.putData(byteArray);
final snapshot = await uploadTask;
return snapshot.ref.getDownloadURL();
}
From above code I am getting this error:
Unhandled Exception: type 'NoSuchMethodError' is not a subtype of type 'Exception'.
It works if I get reference for the FirebaseStorage only and not the bucket like this:
Future<Reference> get storageRef{
return FirebaseStorage.instance.ref();
}
I cannot implement without using bucket reference because there can be different bucket urls depending on the tenants. What am I doing wrong?
Edit => Recent Developments:
I found out that it works if I get the downloadurl from the _refUrl itself. i.e:
String downloadUrl = _refUrl.getDownloadUrl();
It works but I can't help but wonder if it is correct implementation.
Your edit makes perfect sense since you have the reference to the uploaded file with _refUrl, fetching its long-lived download URL works as expected (That's how I have done it before btw). I don't have access to a project with FirebaseStorage to test this, but You can try printing snapshot.ref.fullPath and compare it with the fullPath of _refUrl.
try this
Future<String> uploadImageByteArray({
#required Uint8List byteArray,
String fileName,
}) async {
final name = fileName ?? DateTime.now().toIso8601String();
final _ref = await storageRef;
final _refUrl = _ref.child("images/$name.png");
print(_refUrl.fullPath);
final uploadTask = _refUrl.putData(byteArray);
final snapshot = (await uploadTask);
String url = await snapshot.ref.getDownloadURL(); // await
return url;
}