asynchronous suspension after adding ChangeNotifierProxyProvider to my MutiProviders - android

I am passing the authentication token from Auth.dart file to Products.dart file to enable the app to fetch the Products in my database but the app is not able to fetch those,
I am very new to flutter any help would be appreciated
Thank you
here is my Auth.dart file
import 'dart:convert';
import 'package:flutter/widgets.dart';
import 'package:http/http.dart' as http;
import '../models/http_exceptions.dart';
class Auth with ChangeNotifier {
String _token;
DateTime _expiryDate;
String _userId;
bool get isAuth {
return token != null;
}
String get token {
if (_expiryDate != null &&
_expiryDate.isAfter(DateTime.now()) &&
_token != null) {
return _token;
}
return null;
}
Future<void> _authenticate(
String email, String password, String urlSegment) async {
final url = Uri.parse(
'https://identitytoolkit.googleapis.com/v1/accounts:$urlSegment?key=<key>',
);
try {
final response = await http.post(
url,
body: json.encode(
{
'email': email,
'password': password,
'returnSecureToken': true,
},
),
);
final responseData = json.decode(response.body);
if (responseData['error'] != null) {
throw HttpEception(responseData['error']['message']);
}
_token = responseData['idToken'];
_userId = responseData['localId'];
_expiryDate = DateTime.now().add(
Duration(
seconds: int.parse(responseData['expiresIn']),
),
);
notifyListeners();
} catch (error) {
throw error;
}
}
Future<void> signup(String email, String password) async {
return _authenticate(email, password, 'signUp');
}
Future<void> login(String email, String password) async {
return _authenticate(email, password, 'signInWithPassword');
}
}
Here is my Products.dart file, which has the Product class which is
import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'package:shop_app/models/http_exceptions.dart';
class Product with ChangeNotifier {
final String id;
final String title;
final String description;
final double price;
final String imageUrl;
bool isFavorite;
Product({
#required this.id,
#required this.title,
#required this.description,
#required this.price,
#required this.imageUrl,
this.isFavorite = false,
});
Future<void> toggleFavoriteStatus() async {
final url = Uri.https(
'<confedential>.firebaseio.com',
'/products/$id.json',
);
final oldStatus = isFavorite;
isFavorite = !isFavorite;
notifyListeners();
final response = await http.patch(
url,
body: json.encode(
{
'isFavorite': isFavorite,
},
),
);
if (response.statusCode >= 400) {
isFavorite = oldStatus;
notifyListeners();
throw HttpEception('Could Not Change To Favourite');
}
}
}
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:shop_app/models/http_exceptions.dart';
import './product.dart';
class Products with ChangeNotifier {
List<Product> _items = [];
final String authToken;
Products(this.authToken,this._items);
List<Product> get items {
return [..._items];
}
List<Product> get favoriteItems {
return _items.where((prodItem) => prodItem.isFavorite).toList();
}
Product findById(String id) {
return _items.firstWhere((prod) => prod.id == id);
}
Future<void> fetchAndSetProducts() async {
final url = Uri.https(
'<details>.firebaseio.com',
'/products.json?auth=$authToken',
);
try {
final response = await http.get(url);
// print(json.decode(response.body));
final extractedData = json.decode(response.body) as Map<String, dynamic>;
if (extractedData == null) {
return;
}
final List<Product> loadedProducts = [];
extractedData.forEach((productId, productData) {
loadedProducts.add(
Product(
id: productId,
title: productData['title'],
description: productData['description'],
price: productData['price'],
isFavorite: productData['isFavourite'],
imageUrl: productData['imageUrl'],
),
);
});
_items = loadedProducts;
notifyListeners();
} catch (error) {
throw error;
}
}
Future<void> addProduct(Product product) async {
var url = Uri.https(
'<details>.firebaseio.com',
'/products.json',
);
try {
final response = await http.post(
url,
body: json.encode(
{
'title': product.title,
'description': product.description,
'imageUrl': product.imageUrl,
'price': product.price,
'isFavourite': product.isFavorite,
},
),
);
final newProduct = Product(
title: product.title,
description: product.description,
price: product.price,
imageUrl: product.imageUrl,
id: json.decode(response.body)['name'],
);
_items.add(newProduct);
notifyListeners();
} catch (error) {
throw error;
}
}
Future<void> updateProduct(String id, Product newProduct) async {
final prodIndex = _items.indexWhere((prod) => prod.id == id);
if (prodIndex >= 0) {
final url = Uri.https(
'<details>.firebaseio.com',
'/products/$id.json',
);
http.patch(
url,
body: json.encode(
{
'title': newProduct.title,
'description': newProduct.description,
'imageUrl': newProduct.imageUrl,
'price': newProduct.price,
},
),
);
_items[prodIndex] = newProduct;
notifyListeners();
} else {
print('...');
}
}
Future<void> deleteProduct(String id) async {
final url = Uri.https(
'<details>.firebaseio.com',
'/products/$id.json',
);
final exisitingProductIndex = _items.indexWhere((prod) => prod.id == id);
var exisitingProduct = _items[exisitingProductIndex];
_items.removeAt(exisitingProductIndex);
notifyListeners();
final response = await http.delete(url);
if (response.statusCode >= 400) {
_items.insert(exisitingProductIndex, exisitingProduct);
notifyListeners();
throw HttpEception('Could Not Delete Product.');
}
exisitingProduct = null;
}
}
And finally the main.dart file which uses all this stuff
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import './providers/auth.dart';
import './screens/cart_screen.dart';
import './screens/products_overview_screen.dart';
import './screens/product_detail_screen.dart';
import './providers/products.dart';
import './providers/cart.dart';
import './providers/orders.dart';
import './screens/orders_screen.dart';
import './screens/user_products_screen.dart';
import './screens/edit_product_screen.dart';
import './screens/auth_screen.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MultiProvider(
// Defining these providers for lisening to changes in the data
providers: [
ChangeNotifierProvider.value(
value: Auth(),
),
// First parameter is the type of data that we depened on and second is the data that we arre passing
ChangeNotifierProxyProvider<Auth, Products>(
update: (ctx, auth, previousProducts) => Products(
auth.token,
previousProducts == null ? [] : previousProducts.items,
),
),
ChangeNotifierProvider.value(
value: Cart(),
),
ChangeNotifierProvider.value(
value: Orders(),
),
],
child: Consumer<Auth>(
builder: (context, auth, _) => MaterialApp(
title: 'MyShop',
theme: ThemeData(
primarySwatch: Colors.purple,
accentColor: Colors.deepOrange,
fontFamily: 'Lato',
),
// home: ProductsOverviewScreen(),
home: auth.isAuth ? ProductsOverviewScreen() : AuthScreen(),
routes: {
ProductDetailScreen.routeName: (ctx) => ProductDetailScreen(),
CartScreen.routeName: (ctx) => CartScreen(),
OrdersScreen.routeName: (ctx) => OrdersScreen(),
UserProductsScreen.routeName: (ctx) => UserProductsScreen(),
EditProductScreen.routeName: (ctx) => EditProductScreen(),
},
),
),
);
}
}

Just added create into ChangeNotifierProxyProvider
ChangeNotifierProxyProvider<Auth, Products>(
create: (_)=>Products('',[]),
update: (ctx, auth, previousProducts) => Products(
auth.token,
previousProducts == null ? [] : previousProducts.items,
),
),
and changed the url string in Products.dart file
Uri url = Uri.parse(
'https://<some_details>.firebaseio.com/products.json?auth=$authToken');

Related

Flutter Shared Preferences

Guys how to transfer data when I login.. For example when I login the transfer data are User ID, email and password.. So if I want to add something that requires the user id how do I call it?
This is my login method
void login() async {
if(passController.text.isNotEmpty && emailController.text.isNotEmpty) {
var response = await http.post(
Uri.parse("url"),
body: ({
'email': emailController.text,
'password': passController.text,
}));
if (response.statusCode == 200) {
final body = jsonDecode(response.body);
print(body.toString());
List<dynamic> data = body["Details"];
print(data[0]['email']);
pageRoute(data[0]['name']);
} else {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text("Wrong password")));
}
} else {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text("Sila isi tempat kosong")));
}
}
void pageRoute(data) async {
//STORE VALUE IN SHARED PREFERENCES
SharedPreferences pref = await SharedPreferences.getInstance();
await pref.setString("login", data);
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(builder: (context) => nav()),
(route) => false);
This is where I want to take the user id without put it on the textfield.
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:http/http.dart' as http;
import '../Utils/lib.dart';
class CarList extends StatefulWidget {
const CarList({Key? key}) : super(key: key);
#override
State<CarList> createState() => _CarListState();
}
class _CarListState extends State<CarList> {
var userController = TextEditingController();
// late SharedPreferences logindata;
// String? Email;
final pref = Pref();
// late String name;
// late String registeration_no;
#override
void initState() {
// TODO: implement initState
super.initState();
initial();
}
void initial() async {
if (pref.isLogin()) {
final body = jsonDecode(pref.getLogin());
print(body['Details']['user_id'].toString());
}
return null;
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView(
children: <Widget>[
Container(
padding: const EdgeInsets.all(10),
child: TextField(
controller: userController,
decoration: const InputDecoration(
border: OutlineInputBorder(),
suffixIcon: Icon(Icons.email),
labelText: 'User ID',
),
),
),
Container(
margin: EdgeInsets.all(25),
child: TextButton(
child: Text('test',
style: TextStyle(fontSize: 20.0,
color: Colors.blueAccent,
backgroundColor: Colors.white),
),
onPressed: () {
list();
},
),
)
]
)
);
}
void list() async {
{
var response = await http.post(
Uri.parse("url"),
body: ({
'user_id': userController.text,
}));
if (response.statusCode == 200) {
final body = jsonDecode(response.body);
// final SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
// sharedPreferences.setString('email', emailController.text);
pref.saveLogin(true, response.body);
print(body.toString());
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text("Successfully Login")));
}
}
}
}
Im kinda new with this flutter so might thankful with your help
You can do something like this:
This is store data in pageRoute.
void login() async {
if (passController.text.isNotEmpty && emailController.text.isNotEmpty) {
var response = await http.post(
Uri.parse("http://servisjer.me-tech.com.my/api/Login"),
body: ({
'email': emailController.text,
'password': passController.text,
}));
if (response.statusCode == 200) {
final body = jsonDecode(response.body);
print(body.toString());
List<dynamic> data = body["Details"];
print(data[0]['email']);
pageRoute(Data(data[0]['email'], data[0]['user_id']));
} else {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text("Wrong password")));
}
} else {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text("Sila isi tempat kosong")));
}
}
void pageRoute(Data data) async {
MySharedPreferences().storeUser(data);
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(builder: (context) => nav()), (route) => false);
}
MySharedPreferences
class MySharedPreferences {
Future<void> storeUser(Data data) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString("email", data.email);
prefs.setInt("user_id", data.userId);
}
Future getUserId() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
var userId = prefs.getInt("user_id");
return userId;
}
}
In CarList, retrieve data using this way
#override
void initState() {
MySharedPreferences().getUserId().then((value) {
setState(() {
userController.text = value.toString();
});
});
//TODO: IMPLEMENT INITSTATE
super.initState();
}
Data
class Data {
var email;
var userId;
Data(this.email,this.userId);
}

how to pass array of data from API into graph in flutter?

I have an issue while integrating an array of data from API into my graph, I have tried all other methods but I don't find any solution. How to Use model class to get API data and integrate it into a graph.
import 'dart:convert';
import 'package:chartapp/network/network_helper.dart';
import 'package:chartapp/src/Bar_Chart/bar_model.dart';
import 'package:flutter/material.dart';
import 'package:charts_flutter/flutter.dart' as charts;
import 'package:http/http.dart' as http;
import 'gender_model.dart';
class NetworkHelper {
Future<http.Response> post(String endpoint) async {
var url = Uri.parse(endpoint);
var response = await http.post(url, headers: {
'Authorization':
'token',
'Cookie': ''
});
return response;
}
}
class BarChartAPI extends StatefulWidget {
const BarChartAPI({Key? key}) : super(key: key);
#override
State<BarChartAPI> createState() => _BarChartAPIState();
}
class _BarChartAPIState extends State<BarChartAPI> {
List<Graphmodel> graph = [];
bool loading = true;
NetworkHelper _networkHelper = NetworkHelper();
#override
void initState() {
super.initState();
getData();
}
void getData() async {
var response = await _networkHelper.post(
"*********************************");
final tempdata = json.decode(response.body)['result']["meter"]
["performance"]["growth"]["graph-data"];
List data = tempdata
.map((e) => Graphmodel(name: e['name'], value: e['value']))
.toList();
print(tempdata);
print(data);
setState(() {
graph = data as List<Graphmodel>;
loading = false;
});
}
List<charts.Series<Graphmodel, String>> _createSampleData() {
return [
charts.Series<Graphmodel, String>(
data: graph ,
id: 'graph_data',
colorFn: (_, __) => charts.MaterialPalette.teal.shadeDefault,
domainFn: (Graphmodel graphmodel, _) => graphmodel.name,
measureFn: (Graphmodel graphmodel, _) => graphmodel.value,
)
];
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Graph"),
),
body: Center(
child: loading
? CircularProgressIndicator()
: Container(
height: 300,
child: charts.BarChart(
_createSampleData(),
animate: true,
),
),
),
);
}
}
This is my console response
[1]: https://i.stack.imgur.com/Hkomh.png
The following is my class model
import 'dart:convert';
List<Graphmodel> graphmodelFromJson(String str) =>
List<Graphmodel>.from(json.decode(str).map((x) => Graphmodel.fromJson(x)));
String graphmodelToJson(List<Graphmodel> data) =>
json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class Graphmodel {
Graphmodel({
required this.name,
required this.value,
});
String name;
int value;
factory Graphmodel.fromJson(Map<String, dynamic> json) => Graphmodel(
name: json["name"],
value: json["value"],
);
Map<String, dynamic> toJson() => {
"name": name,
"value": value,
};
}

Error: Could not find the correct Provider<AuthState> above this AuthPage Widget

ERROR:
══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
The following ProviderNotFoundException was thrown building AuthPage(dirty, state:
_AuthPageState#7ac1c):
Error: Could not find the correct Provider above this AuthPage Widget
This happens because you used a BuildContext that does not include the provider
of your choice. There are a few common scenarios:
You added a new provider in your main.dart and performed a hot-reload.
To fix, perform a hot-restart.
The provider you are trying to read is in a different route.
Providers are "scoped". So if you insert of provider inside a route, then
other routes will not be able to access that provider.
You used a BuildContext that is an ancestor of the provider you are trying to read.
Make sure that AuthPage is under your MultiProvider/Provider.
This usually happens when you are creating a provider and trying to read it immediately.
For example, instead of:
Widget build(BuildContext context) {
return Provider<Example>(
create: (_) => Example(),
// Will throw a ProviderNotFoundError, because `context` is associated
// to the widget that is the parent of `Provider<Example>`
child: Text(context.watch<Example>()),
),
}
consider using builder like so:
Widget build(BuildContext context) {
return Provider<Example>(
create: (_) => Example(),
// we use `builder` to obtain a new `BuildContext` that has access to the provider
builder: (context) {
// No longer throws
return Text(context.watch<Example>()),
}
),
}
My Code:
AuthPage.dart:-
import 'package:first_app/pages/auth/bloc/auth_state.dart';
import 'package:first_app/pages/auth/widgets/auth_button.dart';
import 'package:first_app/pages/auth/widgets/otp_page.dart';
import 'package:first_app/pages/auth/widgets/phone_page.dart';
import 'package:first_app/pages/auth/widgets/set_up_account.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:provider/provider.dart';
class AuthPage extends StatefulWidget {
final int page;
final String? uid;
const AuthPage({
Key? key,
this.page = 0,
this.uid,
}) : super(key: key);
#override
_AuthPageState createState() => _AuthPageState();
}
class _AuthPageState extends State<AuthPage> {
#override
Widget build(BuildContext context) {
final state = Provider.of<AuthState>(context);
final screenSize = MediaQuery.of(context).size;
return
Builder(builder: (context) {
return Stack(
children: [
Container(
height: screenSize.height,
width: screenSize.width,
color: Colors.white,
child: PageView(
controller: state.controller,
onPageChanged: state.onPageChanged,
physics: NeverScrollableScrollPhysics(),
children: [
PhonePage(),
OtpPage(),
SetUpAccount(),
],
),
),
AuthButton(),
],
);
});
}
}
class AuthPageWidget extends StatelessWidget {
final int page;
final String? uid;
const AuthPageWidget({
Key? key,
required this.page,
this.uid,
}) : super(key: key);
#override
Widget build(BuildContext context) {
final state = AuthState(page, uid ?? '');
return ChangeNotifierProvider(
create: (_) => state,
child: ChangeNotifierProvider.value(
value: state,
child: AuthPage(page: page, uid: uid),
),
);
}
}
AuthState.dart
import 'dart:async';
import 'package:first_app/models/user.dart';
import 'package:first_app/repositories/user_repository.dart';
import 'package:first_app/services/auth.dart';
import 'package:first_app/services/map_services.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
enum PhoneAuthState { initial, success, loading, codeSent, error }
/*part of 'auth_bloc.dart';
abstract class AuthState extends Equatable {
const AuthState();
#override
List<Object> get props => [];
}*/
class AuthState extends ChangeNotifier {
final authService = AuthService.instance;
final userRepo = UserRepository.instance;
PhoneAuthState _phoneAuthState = PhoneAuthState.initial;
String verificationId = '';
TextEditingController phoneController = TextEditingController();
TextEditingController otpController = TextEditingController();
TextEditingController firstNameController = TextEditingController();
TextEditingController lastNameController = TextEditingController();
TextEditingController emailController = TextEditingController();
TextEditingController licensePlateController = TextEditingController();
TextEditingController vehicleColorController = TextEditingController();
TextEditingController vehicleTypeController = TextEditingController();
TextEditingController vehicleManufacturersController = TextEditingController();
Roles role = Roles.passenger;
PageController? controller;
int pageIndex = 0;
String uid = '';
int timeOut = 30;
bool get isRoleDriver => role == Roles.driver;
AuthState(int page, String uid) {
this.uid = uid;
controller = PageController(initialPage: page);
pageIndex = page;
notifyListeners();
siginCurrentUser();
}
PhoneAuthState get phoneAuthState => _phoneAuthState;
set changeRoleState(int value) {
role = Roles.values[value];
notifyListeners();
}
set phoneAuthStateChange(PhoneAuthState phoneAuthState) {
_phoneAuthState = phoneAuthState;
notifyListeners();
}
void animateToNextPage(int page) {
controller!.animateToPage(page, duration: Duration(milliseconds: 400), curve: Curves.easeIn);
pageIndex = page;
notifyListeners();
}
void onPageChanged(int value) {
pageIndex = value;
notifyListeners();
}
Future<void> signUp() async {
phoneAuthStateChange = PhoneAuthState.loading;
final address = await MapService.instance?.getCurrentPosition();
try {
final user = User(
uid: uid,
isActive: true,
firstname: firstNameController.text,
lastname: lastNameController.text,
email: emailController.text,
createdAt: DateTime.now(),
isVerified: true,
licensePlate: licensePlateController.text,
phone: "234${phoneController.text}",
vehicleType: vehicleTypeController.text,
vehicleColor: vehicleColorController.text,
vehicleManufacturer: vehicleManufacturersController.text,
role: role,
latlng: address?.latLng,
);
await userRepo.setUpAccount(user);
phoneAuthStateChange = PhoneAuthState.success;
} on FirebaseException catch (e) {
print(e.message);
phoneAuthStateChange = PhoneAuthState.error;
}
}
Future<void> phoneNumberVerification(String phone) async {
await AuthService.instance!.verifyPhoneSendOtp(phone, completed: (credential) async {
if (credential.smsCode != null && credential.verificationId != null) {
verificationId = credential.verificationId ?? '';
notifyListeners();
await verifyAndLogin(credential.verificationId!, credential.smsCode!, phoneController.text);
}
}, failed: (error) {
phoneAuthStateChange = PhoneAuthState.error;
}, codeSent: (String id, int? token) {
verificationId = id;
notifyListeners();
phoneAuthStateChange = PhoneAuthState.codeSent;
codeSentEvent();
print('code sent $id');
}, codeAutoRetrievalTimeout: (id) {
verificationId = id;
notifyListeners();
phoneAuthStateChange = PhoneAuthState.codeSent;
animateToNextPage(1);
print('timeout $id');
});
animateToNextPage(1);
notifyListeners();
}
Future<void> verifyAndLogin(String verificationId, String smsCode, String phone) async {
phoneAuthStateChange = PhoneAuthState.loading;
final uid = await authService?.verifyAndLogin(verificationId, smsCode, phone);
await userRepo.getUser(uid);
this.uid = uid ?? '';
animateToNextPage(2);
notifyListeners();
phoneAuthStateChange = PhoneAuthState.success;
print('completed');
}
Future<void> siginCurrentUser() async {
await userRepo.signInCurrentUser();
}
Future<void> codeSentEvent() async {
animateToNextPage(1);
_startCountDown();
}
void _startCountDown() {
Timer.periodic(Duration(seconds: 1), (timer) {
if (timer.tick > 30) {
timer.cancel();
} else {
--timeOut;
}
notifyListeners();
});
}
}
main.dart
import 'package:first_app/pages/home/home.dart';
import 'package:first_app/repositories/user_repository.dart';
import 'package:first_app/ui/theme.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
void initState() {
UserRepository.instance.signInCurrentUser();
super.initState();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'BrilliantDrive',
theme: CityTheme.theme,
home: HomePage(),
);
}
}
Initialize your provider 1st. Refer this https://stackoverflow.com/a/68418866/16467763.
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider<AuthState>(
create: (context) => AuthState(),
),
],
child: MyApp(),
),
);
}
class AuthPageWidget extends StatelessWidget {
final int page;
final String? uid;
const AuthPageWidget({
Key? key,
required this.page,
this.uid,
}) : super(key: key);
#override
Widget build(BuildContext context) {
final state = AuthState(page, uid ?? '');
return ChangeNotifierProvider(
create: (_) => state,
child: ChangeNotifierProvider.value(
value: state,
child: AuthPage(page: page, uid: uid),
),
);
}
}
You should move the ChangeNotifierProvider to your main.dart like this
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
final state = AuthState(page, uid ?? '');
runApp(
MaterialApp(
debugShowCheckedModeBanner: false,
home: ChangeNotifierProvider(
create: (_) => state,
child: AuthPage(page: page, uid: uid),
),
),
);
}
OR
class SomeWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: ChangeNotifierProvider(
create: (_) => state,
child: ChangeNotifierProvider.value(
value: state,
child: AuthPage(page: page, uid: uid),
),
)
),
);
}
}

how to get data from api(Map type) for dropdown option

I have a problem when i want to get data from api and show them in dropdown option, I can print data when i run my code but in dropdown option i have below error :
type '(dynamic) => DropdownMenuItem' is not a subtype of type '(String, dynamic) => MapEntry' of 'transform'
import 'package:flutter/material.dart';
import 'package:dropdownfield/dropdownfield.dart';
import 'package:http/http.dart' as http;
import 'dart:async';`enter code here`
import 'dart:convert';
class InBoundRate extends StatefulWidget {
#override
_InBoundRateState createState() => _InBoundRateState();
}
class _InBoundRateState extends State<InBoundRate> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: new Center(
child: new FutureBuilder(
future: GetInbound(),
builder: (BuildContext context, AsyncSnapshot<Map> snapshot) {
if (snapshot.hasData) {
Map content = snapshot.data ;
var sampleData = json.encode(content);
var json2 = JsonDecoder().convert(sampleData);
// print(json2['data']['countries']);
return DropdownButton(
items: json2.map(
(item) => DropdownMenuItem(
value: item['data']['countries'],
child: Text(item['data']['countries'])),
// onChanged: (Users value) {
// setState(() {
// _currentUser = value;
// });
// }
),
isExpanded: false,
//value: _currentUser,
hint: Text('Select User'),
);
} else {
return new Container();
}
}),
),
);
}
}
Future<Map> GetInbound() async {
String apiUrl = 'http://homaexpressco.ir/api/getRatesInformation2';
http.Response response = await http.get(apiUrl);
var res = json.decode(response.body);
return res;
}

A Flutter List populated from an Async Call Throws an In-App Error but doesn't Crash

I have a list of items being populated from an async call in a Stateful Widget. It grabs the first item of the list (which should really be just one item) and displays content from it in a card.
When I navigate to the screen, it says there is no element meets[0] with a big bright red screen, but the screen almost immediately goes away (in ~.5 seconds). I'm assuming that this means that the call is finishing and the error disappears. This however makes for a very poor user experience when they see an error randomly.
I've tried putting the async call in the init method before build - however, the error is still happening.
RESPONSE PAGE:
import 'dart:convert';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
import 'package:location/location.dart';
import 'package:marketapp/Areas/Meet/MeetDetailsPage.dart';
class ResponsePage extends StatefulWidget {
static const int = 5;
static const routeName = '/responsepage';
final ResponsePageArguments rpa;
ResponsePage({Key key, #required this.rpa}) : super(key: key);
// Create initial state of the Meet Page
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return ResponsePageState();
}
}
class ResponsePageState extends State<ResponsePage> {
Location location = Location();
LocationData currentLocation;
var isLoading = false;
var id;
var meets = new List<MeetModel>();
#override
Widget build(BuildContext context) {
// TODO: implement build
final _formKey = GlobalKey<FormState>();
return Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Card(
child: ListTile(
title: Text(meets[0].host + " wants to meet you!"),
subtitle: Text("Requested at " + meets[0].requestTime),
)),
Padding(
padding: const EdgeInsets.symmetric(
vertical: 10.0, horizontal: 5.0),
child: Row(children: <Widget>[
RaisedButton(
onPressed: () {
declineRequest(id);
},
child: Text('Decline')),
RaisedButton(
onPressed: () {
// Validate returns true if the form is valid, false otherwise
acceptRequest(id);
},
child: Text('Accept'),
),
]))
]));
}
#override
initState() {
getMeet(widget.rpa.id);
id = widget.rpa.id;
super.initState();
location.onLocationChanged().listen((value) {
if (this.mounted) {
setState(() {
currentLocation = value;
});
}
});
}
acceptRequest(id) async {
setState(() {
isLoading = true;
});
final url = 'https://.azurewebsites.net/Meets/MeetResponse/$id';
var userToken = await getToken();
print("Token printed " + userToken.toString());
var body = jsonEncode({'latitude': currentLocation.latitude.toString(),
'longitude' : currentLocation.longitude.toString()});
print("Current Latitude: " + currentLocation.latitude.toString());
print("Current Longitude: " + currentLocation.longitude.toString());
/*final responseBody = (await http.get(
'https://.azurewebsites.net/Auths/RegisterDevice?deviceToken=$deviceToken&userToken=$userToken'))
.body;*/
/*return */
http.post(
url,
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer $userToken"
},
body: body
).then((http.Response response) {
print("Accept Response Status: ${response.statusCode}");
print("Accept Response Body: ${response.body}");
setState(() {
isLoading = false;
});
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) =>
MeetDetailsPage(mdpa: MeetDetailsPageArguments(id))));
});
}
declineRequest(id) async {
setState(() {
isLoading = true;
});
final url = 'https://.net/Meets/MeetResponse/$id';
var userToken = await getToken();
print("Token printed " + userToken.toString());
var body = jsonEncode({'userToken': '$userToken'});
/*final responseBody = (await http.get(
'https://.net/Auths/RegisterDevice?deviceToken=$deviceToken&userToken=$userToken'))
.body;*/
/*return */
http.post(
url,
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer $userToken"
},
/*body: body*/
).then((http.Response response) {
print("Decline Response Status: ${response.statusCode}");
print("Decline Response Body: ${response.body}");
setState(() {
isLoading = false;
});
var responseBody = response.body;
});
}
getMeet(id) async {
setState(() {
isLoading = true;
});
final url = 'https://``````````````.net/Meets/Get/$id';
var userToken = await getToken();
print("Token printed " + userToken.toString());
var body = jsonEncode({'userToken': '$userToken'});
/*final responseBody = (await http.get(
'https://``````````.net/Auths/RegisterDevice?deviceToken=$deviceToken&userToken=$userToken'))
.body;*/
/*return */
http.get(
url,
headers: {"Authorization": "Bearer $userToken"},
/*body: body*/
).then((http.Response response) async {
print("Get Response Status: ${response.statusCode}");
print("Get Response Body: ${response.body}");
setState(() {
isLoading = false;
});
var responseBody = response.body;
meets = MeetModel.fromJsonList(json.decode(responseBody));
});
}
}
Future<String> getToken() async {
final storage = new FlutterSecureStorage();
return await storage.read(key: 'token');
}
class ResponsePageArguments {
String id;
ResponsePageArguments(this.id);
}
// Code below is useless
class MeetModel {
String meetId;
String host;
String hostId;
String address;
String city;
String zip;
String category;
String latitude;
String longitude;
String product;
String productId;
String reference;
String hostPlaceId;
String venueAddress;
String venuePlaceId;
String venueLatitude;
String venueLongitude;
String recipient;
String recipientAddress;
String recipientZip;
String recipientCity;
String recipientPlaceID;
String recipientLatitude;
String recipientLongitude;
String requestTime;
String responseTime;
String recipientId;
String isArchived;
String meetType;
MeetModel.fromJson(obj) {
this.meetId = obj['MeetId'].toString();
this.host = obj['Host'].toString();
this.address = obj['Address'].toString();
this.city = obj['City'].toString();
this.zip = obj['Zip'].toString();
this.category = obj['Category'].toString();
this.latitude = obj['Latitude'].toString();
this.longitude = obj['Longitude'].toString();
this.product = obj['Product'].toString();
this.productId = obj['ProductId'].toString();
this.reference = obj['Reference'].toString();
this.hostPlaceId = obj['HostPlaceId'].toString();
this.venueAddress = obj['VenueAddress'].toString();
this.venuePlaceId = obj['VenuePlaceId'].toString();
this.venueLatitude = obj['VenueLatitude'].toString();
this.venueLongitude = obj['VengueLongitude'].toString();
this.recipient = obj['Recipient'].toString();
this.recipientAddress = obj['RecipientAddress'].toString();
this.recipientZip = obj['RecipientZip'].toString();
this.recipientPlaceID = obj['RecipientPlaceID'].toString();
this.recipientLatitude = obj['RecipientLatitude'].toString();
this.recipientLongitude = obj['RecipientLongitude'].toString();
this.requestTime = obj['RequestTime'].toString();
this.responseTime = obj['ResponseTime'].toString();
this.hostId = obj['HostId'].toString();
this.recipientId = obj['RecipientId'].toString();
this.isArchived = obj['IsArchived'].toString();
this.meetType = obj['MeetType'].toString();
}
static List<MeetModel> fromJsonList(jsonList) {
return jsonList.map<MeetModel>((obj) => MeetModel.fromJson(obj)).toList();
}
}
MEETS PAGE:
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:marketapp/Areas/Meet/ResponsePage.dart';
import 'MeetDetailsPage.dart';
class MeetsPage extends StatefulWidget {
#override
State createState() => new MeetsPageState();
}
class MeetsPageState extends State<MeetsPage> {
var meets = new List<MeetModel>();
var isLoading = false;
_fetchData() async {
setState(() {
isLoading = true;
});
final url = 'https://.azurewebsites.net/Meets/GetAll';
var userToken = await getToken();
print("Token printed " + userToken.toString());
var body = jsonEncode({'userToken': '$userToken'});
/*final responseBody = (await http.get(
'https://.azurewebsites.net/Auths/RegisterDevice?deviceToken=$deviceToken&userToken=$userToken'))
.body;*/
/*return */
http.post(
url,
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer $userToken"
},
/*body: body*/
).then((http.Response response) {
print("GetAll Response Status: ${response.statusCode}");
print("GetAll Response Body: ${response.body}");
setState(() {
isLoading = false;
});
var responseBody = response.body;
meets = MeetModel.fromJsonList(json.decode(responseBody));
});
}
#override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
/*appBar: AppBar(
title: Text("Meet List"),
backgroundColor: Colors.indigo,
),*/
body: isLoading
? Center(
child: CircularProgressIndicator(),
)
: ListView.builder(
itemCount: meets.length,
itemBuilder: (context, index) {
if (meets[index].host == "xxxxxx#gmail.com") { // Do not hard code email.
return ListTile(
onTap: () {
if (meets[index].venueAddress != "null") {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MeetDetailsPage(
mdpa: MeetDetailsPageArguments(
meets[index].meetId))));
} else if (meets[index].venueAddress == "null") {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ResponsePage(
rpa: ResponsePageArguments(
meets[index].meetId))));
}
},
title: Text(
meets[index].recipient,
style: TextStyle(fontWeight: FontWeight.w500)),
trailing: Icon(
Icons.map,
color: Colors.blue[500],
),
subtitle: Text(meets[index].requestTime),
);
} else {
return ListTile(
onTap: () {
if (meets[index].venueAddress != "null") {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MeetDetailsPage(
mdpa: MeetDetailsPageArguments(
meets[index].meetId))));
} else if (meets[index].venueAddress == "null") {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ResponsePage(
rpa: ResponsePageArguments(
meets[index].meetId))));
}
},
title: Text(
meets[index].host,
style: TextStyle(fontWeight: FontWeight.w500)),
trailing: Icon(
Icons.map,
color: Colors.blue[500],
),
subtitle: Text(meets[index].requestTime),
);
}
},
));
}
#override
void initState() {
_fetchData();
super.initState();
}
}
class MeetModel {
String meetId;
String host;
String hostId;
String address;
String city;
String zip;
String category;
String latitude;
String longitude;
String product;
String productId;
String reference;
String hostPlaceId;
String venueAddress;
String venuePlaceId;
String venueLatitude;
String venueLongitude;
String recipient;
String recipientAddress;
String recipientZip;
String recipientCity;
String recipientPlaceID;
String recipientLatitude;
String recipientLongitude;
String requestTime;
String responseTime;
String recipientId;
String isArchived;
String meetType;
MeetModel.fromJson(obj) {
this.meetId = obj['MeetId'].toString();
this.host = obj['Host'].toString();
this.address = obj['Address'].toString();
this.city = obj['City'].toString();
this.zip = obj['Zip'].toString();
this.category = obj['Category'].toString();
this.latitude = obj['Latitude'].toString();
this.longitude = obj['Longitude'].toString();
this.product = obj['Product'].toString();
this.productId = obj['ProductId'].toString();
this.reference = obj['Reference'].toString();
this.hostPlaceId = obj['HostPlaceId'].toString();
this.venueAddress = obj['VenueAddress'].toString();
this.venuePlaceId = obj['VenuePlaceId'].toString();
this.venueLatitude = obj['VenueLatitude'].toString();
this.venueLongitude = obj['VengueLongitude'].toString();
this.recipient = obj['Recipient'].toString();
this.recipientAddress = obj['RecipientAddress'].toString();
this.recipientZip = obj['RecipientZip'].toString();
this.recipientPlaceID = obj['RecipientPlaceID'].toString();
this.recipientLatitude = obj['RecipientLatitude'].toString();
this.recipientLongitude = obj['RecipientLongitude'].toString();
this.requestTime = obj['RequestTime'].toString();
this.responseTime = obj['ResponseTime'].toString();
this.hostId = obj['HostId'].toString();
this.recipientId = obj['RecipientId'].toString();
this.isArchived = obj['IsArchived'].toString();
this.meetType = obj['MeetType'].toString();
}
static List<MeetModel> fromJsonList(jsonList) {
return jsonList.map<MeetModel>((obj) => MeetModel.fromJson(obj)).toList();
}
}
Future<String> getToken() async {
final storage = new FlutterSecureStorage();
return await storage.read(key: 'token');
}
class Backend {
static Future<List<MeetModel>> GetAll(userToken) async {
final url = 'https://.net/Auths/RegisterDevice';
var body = jsonEncode({'userToken': '$userToken'});
/*final responseBody = (await http.get(
'https://.azurewebsites.net/Auths/RegisterDevice?deviceToken=$deviceToken&userToken=$userToken'))
.body;*/
return http
.post(url,
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer $userToken"
},
body: body)
.then((http.Response response) {
print("GetAll Response Status: ${response.statusCode}");
print("GetAll Response Body: ${response.body}");
var responseBody = response.body;
return MeetModel.fromJsonList(json.decode(responseBody));
});
}
}
The error still appears, but goes away when the async call finishes. Note - this error happens when you select an item from the list of meets - it navigates to ResponsePage, and for a brief second, there is a flash of red indicating that there is not enough items in the list. This error disappears when the call finishes with the correct form.
Is there a way to stop building the card until the data in the list of meets finishes getting populated?

Categories

Resources