Flutter Save Object on SharedPreferences - flutter

I have a working json parsing from my commerce API. all are working fine except for storing the add cart product to the shared preferences. How can I achieve this? I got an error of type
'ProductsModel' is not a subtype of type 'Map<String, dynamic>';
Here's my ProductsModel
class ProductsList{
final List<ProductsModel> products;
ProductsList({this.products});
factory ProductsList.fromJSON(List<dynamic> parsedJson){
List <ProductsModel> productsList = new List<ProductsModel>();
productsList = parsedJson.map((i) => ProductsModel.fromJSON(i)).toList();
return new ProductsList(
products: productsList
);
}
}
class ProductsModel {
final int id;
final String name;
final String catalog_visibility;
final String description;
final String short_description;
final String price;
final String regular_price;
final String sale_price;
final String date_created;
final List<CategoriesModel> categories;
final List<ImagesModel> images;
ProductsModel(
{this.id,
this.name,
this.catalog_visibility,
this.description,
this.short_description,
this.price,
this.regular_price,
this.sale_price,
this.date_created,
this.categories,
this.images
});
factory ProductsModel.fromJSON(Map<String, dynamic> parsedJson) {
var categoriesList = parsedJson['categories'] as List;
var imagesList = parsedJson['images'] as List;
List<ImagesModel> dataImages = imagesList.map((i) => ImagesModel.fromJSON(i)).toList();
List<CategoriesModel> dataCategories =
categoriesList.map((i) => CategoriesModel.fromJSON(i)).toList();
return ProductsModel(
id: parsedJson['id'],
name: parsedJson['name'],
catalog_visibility: parsedJson['catalog_visibility'],
description: parsedJson['description'],
short_description: parsedJson['short_description'],
regular_price: parsedJson['regular_price'],
sale_price: parsedJson['sale_price'],
date_created: parsedJson['date_created'],
categories: dataCategories,
images: dataImages
);
}
}
class CategoriesModel {
final int id;
final String name;
CategoriesModel({this.id, this.name});
factory CategoriesModel.fromJSON(Map<String, dynamic> parsedJson) {
return CategoriesModel(id: parsedJson['id'], name: parsedJson['name']);
}
}
class ImagesModel{
final int id;
final String src;
final String name;
ImagesModel({this.id,this.src,this.name});
factory ImagesModel.fromJSON(Map<String,dynamic> parsedJson){
return ImagesModel(
id: parsedJson['id'],
src: parsedJson['src'],
name: parsedJson['name']
);
}
}
and I am testing to stored the ProductsModel only by using this function only
Here's my function
storedCart(products){
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setString('cart', products);
}

STEP 1 : Add a toMap() method in your class
Map<String,dynamic> toMap() {
var map = new Map<String, dynamic>();
map["id"] = id;
map["name"] = name;
map["description"] = description;
// Add all other fields
return map;
}
STEP 2 : While storing this in SharedPreferences call the toMap() method on the object
This will return a Map<String,dynamic> representation of your current object.
Map<String,dynamic> productsMap = products.toMap();
STEP 3 : Convert the object to String by using json.encode() and store it !
storedCart(productsMap){
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setString('cart', json.encode(productsMap));
}
Note :
Dont forget to import dart:convert
While retrieving the object don't forget to use json.decode()
If you are having trouble understanding why we used json.encode(), try printing the object before and after using the function, you'll notice that when we convert our object to JSON it becomes a big String, Therefore it is possible for us to store it in SharedPreferences using the "putString()" method.

Related

Riverpod Model from List<Model> to Map<String>

I am new to flutter and I am a bit confused about Riverpod and have wasted a few days on this issue which is probably really easy. I have a Model, Provider and Service created with Riverpod which I will share below. I have a widget that takes a Map and an API that is structured
{
"job": [
{"feild1": "data",..},
{"feild2": "data",..},
{"feild3": "data",..}
]
}
It is being mapped as List how can I change that to Map for a child widget I have created.
This is my Provider:
final jobsDataProvider = FutureProvider<List<JobsModel>>((ref) async {
return ref.watch(jobsProvider).getJobs();
});
This is my model:
class JobsModel {
final String jobid;
final String from_state;
final String from_suburb;
final String to_state;
final String to_suburb;
final String travel_time;
final String date;
final String distance;
final String status;
final String map;
JobsModel({
required this.jobid,
required this.from_state,
required this.from_suburb,
required this.to_state,
required this.to_suburb,
required this.travel_time,
required this.date,
required this.distance,
required this.status,
required this.map,
});
factory JobsModel.fromJson(Map<String, dynamic> json) {
return JobsModel(
jobid: json['jobid'],
from_state: json['from']['state'],
from_suburb: json['from']['suburb'],
to_state: json['to']['state'],
to_suburb: json['to']['suburb'],
travel_time: json['travel_time'],
date: json['date'],
distance: json['distance'],
status: json['status'],
map: json['map'],
);
}
}
This is my service:
class ApiServices {
String endpoint = 'https://localhost:3000/jobs';
Future<List<JobsModel>> getJobs() async {
Response response = await get(Uri.parse(endpoint));
if (response.statusCode == 200) {
final List result = jsonDecode(response.body)['jobs'];
return result.map(((e) => JobsModel.fromJson(e))).toList();
} else {
throw Exception(response.reasonPhrase);
}
}
}
final jobsProvider = Provider<ApiServices>((ref) => ApiServices());
My child widget takes a Map<String, dynamic> how can I make this work so I can map multiple widgets from the returned api call into a row.
Thanks heaps all.

How to access token saved as a variable in different dart page in a secured storage

I have saved a token as a variable in flutter secure storage in a file called login_response_model.dart and I am trying to access it in the home screen, but I keep getting error as undefined name:
Here is the login_response_model.dart:
class LoginResponse {
dynamic? key;
List<dynamic>? non_field_errors;
LoginResponse({this.key, this.non_field_errors});
factory LoginResponse.fromJson(mapOfBody) {
return LoginResponse(
key: mapOfBody['key'],
non_field_errors: mapOfBody['non_field_errors'],
);
}
}
LoginResponseModel loginResponseJson(String str) =>
LoginResponseModel.fromJson(json.decode(str));
class LoginResponseModel {
dynamic? key;
List<dynamic>? non_field_errors;
LoginResponseModel({this.key, this.non_field_errors});
LoginResponseModel.fromJson(mapOfBody) {
key:
mapOfBody['key'];
non_field_errors:
mapOfBody['non_field_errors'];
print(mapOfBody['key']);
// Create storage
final storage = new FlutterSecureStorage();
// Write value
storage.write(key: 'Token', value: mapOfBody['key']);
}
Map<String, dynamic> toJson() {
final _data = <String, dynamic>{};
_data['key'] = key;
_data['non_field_errors'] = non_field_errors;
return _data;
}
}
class Data {
Data({
required this.username,
required this.email,
required this.date,
required this.id,
required this.key,
});
late final String username;
late final String email;
late final String date;
late final String id;
late final String key;
Data.fromJson(Map<String, dynamic> json) {
username = json['username'];
email = json['email'];
date = json['date'];
id = json['id'];
key = json['key'];
}
Map<String, dynamic> toJson() {
final _data = <String, dynamic>{};
_data['username'] = username;
_data['email'] = email;
_data['date'] = date;
_data['id'] = id;
_data['key'] = key;
return _data;
}
}
Here is the homescreen:
Future<User> fetchUser() async {
var url = Uri.parse(Config.apiURL + Config.userProfileAPI);
var value = storage.read(key: 'Token');
My question:
How can I access the token saved in a secured storage into the home screen?
Is there an easier and more secure way to access the token saved other than the way I have arranged it?
Use can you SharedPreference & save token here. Each time you want to use, you just need to:
SharedPreferences prefs = await SharedPreferences.getInstance();
String token = prefs.getString("key_token") ?? "";
However, each time you want to use it, you again need to use async function & wait until it give you saved token. Although it doesn't take so much time & space but we need to notice this. You can init a global variable to save token whenever open app or login success. Learn more about Singleton.
Example in my app: data_instance.dart
class DataInstance {
static DataInstance _instance = new DataInstance.internal();
DataInstance.internal();
factory DataInstance() => _instance;
late String accessToken;
initPreference() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
DataInstance().accessToken = prefs.getString("key_token_haha")?? '';
}
}
In main.dart:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await DataInstance().initPreference();
runApp(const MyApp());
}

Flutter SQFlite Class to Json()

I am currently working on an app where the user is able to store data on their device locally. Therefor I am using the sqflite package but I am running into some errors converting my Class data into Json.
This is the error message I get:
A value of type 'Set' can't be returned from the method
'toJson' because it has a return type of 'Map<String, Widget>'.
due to this line:
Map<String, Widget> toJson() => {
EntryFields.id = id,
EntryFields.name = name,
EntryFields.navigation = navigation,
};
This is my class:
import 'package:flutter/material.dart';
const String tableFavs = 'favorites';
class EntryFields {
static late String id = '_id';
static late String name = '_name';
static late String navigation = '_navigation';
}
class Entries {
final int id;
final String name;
final Widget navigation;
Entries({
required this.id,
required this.name,
required this.navigation,
});
Map<String, Widget> toJson() => {
EntryFields.id = id,
EntryFields.name = name,
EntryFields.navigation = navigation,
};
}
and this is a snipped from my database:
Future<Entries> create(Entries entries) async {
final db = await instance.database;
final id = await db.insert(tableFavs, entries.toJson());
}
you can't store a widget in the database it should be Map<String, String>
try to store the parameters of the widget as a String, not the whole widget
you can store these types double, string, int, bool..
try using the below code
class EntryFields {
static late String id = '_id';
static late String name = '_name';
static late String navigation = '_navigation';
}
class Entries {
const Entries({
this.id,
this.name,
this.navigation,
});
final String? id;
final String? name;
final String? navigation;
Map<String, dynamic> toJson() => {
"_id": id,
"_name": name,
"_navigation": navigation,
};
}
Future<void> create(Entries entries) async {
final db = await instance.database;
final id = await db.insert(tableFavs, entries.toJson());
}
void main(){
final entriesFromField = Entries(
id: EntryFields.id,
name: EntryFields.name,
navigation: EntryFields.navigation
);
create(entriesFromField);
}
or better you can use this json generator

Flutter & Shared Preferences : How do I save a list (of object) to local memory?

I want to save a list of objects into my local memory using the shared_preferences package.
Let's assume that this is my class:
class Person{
String name;
String age;
String gender;
}
How do I do that with shared_preferences?
I am looking forward to hearing from all of you. Thank you.
You can save a List<String> with shared_preferences.
Therefore, we need to convert the Person class, and its list, into a String by encoding them as JSON:
class Person {
String name;
String age;
String gender;
Person({this.name, this.age, this.gender});
factory Person.fromJson(Map<String, dynamic> parsedJson) {
return new Person(
name: parsedJson['name'] ?? "",
age: parsedJson['age'] ?? "",
gender: parsedJson['gender'] ?? "");
}
Map<String, dynamic> toJson() {
return {
"name": this.name,
"age": this.age,
"gender": this.gender,
};
}
}
void _savePersons(List<Person> persons) async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
List<String> personsEncoded = persons.map((person) => jsonEncode(person.toJson())).toList();
await sharedPreferences.setStringList('accounts', accounts);
}
In the same fashion, we can get the saved List<Person> as a JSON object and de-serialize it:
List<Person> _getPersons(List<Person> persons) async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
await sharedPreferences.setStringList('accounts', accounts);
return persons.map((person) => Person.fromJson(person)).toList();
}

Flutter how to cast the model object to another model to save it to HIVE

I have an API response and parsed it using ProductsModel and I am trying to save it to my local storage using Hive and I have different model called LocalProductsModel. How can I cast the response ProductsModel to LocalProductsModel? I used product.cast<LocalProductsModel>();
Here's my Products Model:
class ProductsList{
final List<ProductsModel> products;
ProductsList({this.products});
factory ProductsList.fromJSON(List<dynamic> parsedJson){
List <ProductsModel> productsList = new List<ProductsModel>();
productsList = parsedJson.map((i) => ProductsModel.fromJSON(i)).toList();
return new ProductsList(
products: productsList
);
}
}
class ProductsModel {
final int id;
final String name;
final String catalog_visibility;
final String description;
final String short_description;
final String price;
final String regular_price;
final String sale_price;
final String date_created;
final List<CategoriesModel> categories;
final List<ImagesModel> images;
ProductsModel(
{this.id,
this.name,
this.catalog_visibility,
this.description,
this.short_description,
this.price,
this.regular_price,
this.sale_price,
this.date_created,
this.categories,
this.images
});
factory ProductsModel.fromJSON(Map<String, dynamic> parsedJson) {
var categoriesList = parsedJson['categories'] as List;
var imagesList = parsedJson['images'] as List;
List<ImagesModel> dataImages = imagesList.map((i) => ImagesModel.fromJSON(i)).toList();
List<CategoriesModel> dataCategories =
categoriesList.map((i) => CategoriesModel.fromJSON(i)).toList();
return ProductsModel(
id: parsedJson['id'],
name: parsedJson['name'],
catalog_visibility: parsedJson['catalog_visibility'],
description: parsedJson['description'],
short_description: parsedJson['short_description'],
regular_price: parsedJson['regular_price'],
sale_price: parsedJson['sale_price'],
date_created: parsedJson['date_created'],
categories: dataCategories,
images: dataImages
);
}
Map<String, dynamic> toMap() {
var map = new Map<String, dynamic>();
ImagesModel img = ImagesModel();
map["id"] = id;
map["name"] = name;
map["description"] = description;
map["catalog_visibility"] = catalog_visibility;
map["short_description"] = short_description;
map["regular_price"] = regular_price;
map["sale_price"] = sale_price;
map["date_created"] = date_created;
map['images'] = this.images.map((v) => v.toMap()).toList();
return map;
}
}
class CategoriesModel {
final int id;
final String name;
CategoriesModel({this.id, this.name});
factory CategoriesModel.fromJSON(Map<String, dynamic> parsedJson) {
return CategoriesModel(id: parsedJson['id'], name: parsedJson['name']);
}
Map<String, dynamic> toMap() {
var map = new Map<String, dynamic>();
map["id"] = id;
map["name"] = name;
return map;
}
}
class ImagesModel{
final int id;
final String src;
final String name;
ImagesModel({this.id, this.src, this.name});
factory ImagesModel.fromJSON(Map<String, dynamic> parsedJson){
return ImagesModel(
id: parsedJson['id'],
src: parsedJson['src'],
name: parsedJson['name']
);
}
Map<String, dynamic> toMap() => {
"id": id,
"src": src,
"name" :name,
};
}
My LocalProductModel for my hive local storage:
import 'package:hive/hive.dart';
part 'localProducts.g.dart';
#HiveType(typeId: 0)
class LocalProductsModel {
#HiveField(0)
final int id;
#HiveField(1)
final String name;
#HiveField(2)
final String catalog_visibility;
#HiveField(3)
final String description;
#HiveField(4)
final String short_description;
#HiveField(5)
final String price;
#HiveField(6)
final String regular_price;
#HiveField(7)
final String sale_price;
#HiveField(8)
final String date_created;
#HiveField(9)
final List<LocalCategoriesModel> categories;
#HiveField(10)
final List<LocalImagesModel> images;
LocalProductsModel(
{this.id,
this.name,
this.catalog_visibility,
this.description,
this.short_description,
this.price,
this.regular_price,
this.sale_price,
this.date_created,
this.categories,
this.images
});
factory LocalProductsModel.fromJSON(Map<String, dynamic> parsedJson) {
var categoriesList = parsedJson['categories'] as List;
var imagesList = parsedJson['images'] as List;
List<LocalImagesModel> dataImages = imagesList.map((i) => LocalImagesModel.fromJSON(i)).toList();
List<LocalCategoriesModel> dataCategories =
categoriesList.map((i) => LocalCategoriesModel.fromJSON(i)).toList();
return LocalProductsModel(
id: parsedJson['id'],
name: parsedJson['name'],
catalog_visibility: parsedJson['catalog_visibility'],
description: parsedJson['description'],
short_description: parsedJson['short_description'],
regular_price: parsedJson['regular_price'],
sale_price: parsedJson['sale_price'],
date_created: parsedJson['date_created'],
categories: dataCategories,
images: dataImages
);
}
Map<String,dynamic> toMap() {
var map = new Map<String, dynamic>();
LocalImagesModel img = LocalImagesModel();
Map<String,dynamic> images = img.toMap();
map["id"] = id;
map["name"] = name;
map["description"] = description;
map["catalog_visibility"] = catalog_visibility;
map["short_description"] = short_description;
map["regular_price"] = regular_price;
map["sale_price"] = sale_price;
map["date_created"] = date_created;
map['images'] = this.images.map((v) => v.toMap()).toList();
return map;
}
}
class LocalCategoriesModel {
final int id;
final String name;
LocalCategoriesModel({this.id, this.name});
factory LocalCategoriesModel.fromJSON(Map<String, dynamic> parsedJson) {
return LocalCategoriesModel(id: parsedJson['id'], name: parsedJson['name']);
}
Map<String,dynamic> toMap() {
var map = new Map<String, dynamic>();
map["id"] = id;
map["name"] = name;
return map;
}
}
class LocalImagesModel{
final int id;
final String src;
final String name;
LocalImagesModel({this.id,this.src,this.name});
factory LocalImagesModel.fromJSON(Map<String,dynamic> parsedJson){
return LocalImagesModel(
id: parsedJson['id'],
src: parsedJson['src'],
name: parsedJson['name']
);
}
Map<String, dynamic> toMap() => {
"id": id,
"src": src,
"name" :name,
};
}
I have a working add function on hive but I know this is wrong cause I didn't cast it to my LocalProductsModel:
postCartLocal(ProductsModel products){
Map<String, dynamic> productsMap = products.toMap();
Hive.box('cart').add(productsMap);
}
When I am getting the value I got an error type
'_InternalLinkedHashMap<String, dynamic>' is not a subtype of type
'LocalProductsModel' in type cast
My Code on getting the value on local storage:
Widget _buildListView(){
return ValueListenableBuilder(
valueListenable: Hive.box('cart').listenable(),
builder: (context, snapshot, widget){
return ListView.builder(
itemCount: snapshot.length,
itemBuilder: (context, index) {
final cart = snapshot.getAt(index) as LocalProductsModel;
print('lenght ${cart.name}');
});
}
);
}
This should work:
final cart = snapshot.getAt(index).cast<LocalProductsModel>();