Routig problem with storing data from fetch on other page - flutter

So here is my problem. I have to route to the page EditReservationScrenn from the general ReservationScreen I have, which simply shows a list of all reservations in a ListView.builder. On tab on one of those elements you then get routed(with an argument which is the complete item) to a next screen. On this EditReservationScreen the data of the passed argument gets presented on the screen as ListTiles. So here's the catch... By taping on the Icon which is presented as trailing you then get transferred to yet another screen where you can change your choice.
this all works. BUT. Whenever I tried to Navigator.pop(new argument) back to the EditReservationScreen I'm not able to update the screen with the new value nor to even store it because it is always overwritten.
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:kinobuchungssystem/src/models/customer.dart';
import 'package:kinobuchungssystem/src/models/performance.dart';
import 'package:kinobuchungssystem/src/models/reservation.dart';
import 'package:kinobuchungssystem/src/models/seat.dart';
import 'package:kinobuchungssystem/src/provider/performance_provider.dart';
import 'package:kinobuchungssystem/src/provider/reservation_provider.dart';
import 'package:kinobuchungssystem/src/selections/add_performance_selection_screen.dart';
import 'package:kinobuchungssystem/src/selections/add_seat_selection_screen.dart';
import 'package:provider/provider.dart';
class EditReservationScreen extends StatefulWidget {
static const routeName = '/edit-reservation';
#override
_EditReservationScreenState createState() => _EditReservationScreenState();
}
class _EditReservationScreenState extends State<EditReservationScreen> {
List<Seat> selectedSeats = [];
List<Reservation> reservations = [];
Customer customer;
var _newPerformance = Performance(
id: null,
movie: null,
dateTime: null,
theater: null,
);
var _newReservation = Reservation(
id: null,
seat: null,
customer: null,
performance: null,
);
/* Future<void> _getPerformance() async {
final pId = await Navigator.of(context)
.pushNamed(AddPerformanceSelectionScreen.routeName);
Provider.of<PerformanceProvider>(context, listen: false)
.fetchAndSetPerformances();
var performance =
Provider.of<PerformanceProvider>(context, listen: false).findById(pId);
setState(() {
_newPerformance = Performance(
id: pId,
dateTime: performance.dateTime,
movie: performance.movie,
theater: performance.theater,
);
_newReservation = Reservation(
id: _newReservation.id,
seat: null,
customer: _newReservation.customer,
performance: performance,
);
});
} */
Future<void> _getReservation() async {
final reservation = /* final reservationId = */
ModalRoute.of(context).settings.arguments as Reservation;
Performance performance = reservation.performance;
_newReservation = Reservation(
customer: reservation.customer,
id: reservation.id,
performance: reservation.performance,
seat: reservation.seat,
);
customer = reservation.customer;
_newPerformance = Performance(
id: performance.id,
dateTime: performance.dateTime,
movie: performance.movie,
theater: performance.theater,
);
}
Future<void> _updateSeat(String id) async {
Map result = (await Navigator.of(context).pushNamed(
AddSeatSelectionScreen.routeName,
arguments: {'id': id, 'customer': _newReservation.customer}) as Map);
selectedSeats = List<Seat>.from((result['seats'] as List));
Performance p = result['performance'];
setState(() {
_newPerformance = Performance(
id: p.id,
dateTime: p.dateTime,
movie: p.movie,
theater: p.theater,
);
_newReservation = Reservation(
id: _newReservation.id,
seat: selectedSeats,
customer: _newReservation.customer,
performance: _newReservation.performance,
);
});
}
void _updateReservation() {
setState(() {
_newReservation = Reservation(
id: _newReservation.id,
seat: _newReservation.seat,
customer: _newReservation.customer,
performance: _newReservation.performance,
);
});
reservations.add(_newReservation);
_newPerformance = Performance(
id: _newPerformance.id,
dateTime: _newPerformance.dateTime,
movie: _newPerformance.movie,
theater: _newPerformance.theater,
);
Provider.of<ReservationProvider>(context, listen: false)
.addReservation(_newReservation);
Provider.of<PerformanceProvider>(context, listen: false)
.updatePerformance(_newPerformance.id, _newPerformance);
Navigator.pop(context);
}
String setSeatNumbers() {
List<int> seatNumbers = [];
List<Seat> seats = List<Seat>.from(_newReservation.seat);
String seatNumbersToString = '';
seats.forEach((seat) {
seatNumbers.add(seat.seatNumber);
});
seatNumbers.forEach((s) {
seatNumbersToString = '$seatNumbersToString, $s';
});
seatNumbersToString = seatNumbersToString.substring(1);
return seatNumbersToString;
}
#override
Widget build(BuildContext context) {
final reservation =
ModalRoute.of(context).settings.arguments as Reservation;
return Scaffold(
appBar: AppBar(
title: Text('Reservation bearbeiten'),
actions: <Widget>[
IconButton(icon: Icon(Icons.save), onPressed: _updateReservation),
],
),
body: FutureBuilder(
future: _getReservation(),
builder: (context, snapshot) => buildList(/* reservation */),
));
}
Widget buildList(/* Reservation reservation */) {
return Padding(
padding: EdgeInsets.all(10),
child: ListView(
children: <Widget>[
SizedBox(
height: 10,
),
ListTile(
leading: CircleAvatar(
backgroundColor: Colors.amber,
child: Icon(Icons.person),
),
title: Text(
'${_newReservation.customer.firstName} ${_newReservation.customer.lastName}'),
subtitle: Text('${_newReservation.customer.phoneNumber}'),
),
SizedBox(
height: 10,
),
Divider(),
SizedBox(
height: 10,
),
ListTile(
leading: CircleAvatar(
backgroundColor: Colors.amber,
child: Icon(Icons.movie),
),
title: Text(
'${_newReservation.performance.movie.title}',
),
subtitle: Text(
'${DateFormat.d().add_MMMM().add_y().format(_newReservation.performance.dateTime)} um ${DateFormat().add_Hm().format(_newReservation.performance.dateTime)}'),
trailing: IconButton(
icon: Icon(Icons.edit),
onPressed: () async {
final pId = await Navigator.of(context)
.pushNamed(AddPerformanceSelectionScreen.routeName);
print(pId);
Provider.of<PerformanceProvider>(context, listen: false)
.fetchAndSetPerformances();
var performance =
Provider.of<PerformanceProvider>(context, listen: false)
.findById(pId);
setState(() {
_newPerformance = Performance(
id: pId,
dateTime: performance.dateTime,
movie: performance.movie,
theater: performance.theater,
);
_newReservation = Reservation(
id: _newReservation.id,
seat: null,
customer: _newReservation.customer,
performance: performance,
);
});
}),
),
SizedBox(
height: 10,
),
Divider(),
SizedBox(
height: 10,
),
ListTile(
leading: CircleAvatar(
backgroundColor: Colors.amber,
child: IconButton(
icon: Icon(
Icons.event_seat,
),
onPressed: () {},
),
),
title: _newReservation.seat == null
? Text('Sitze wählen')
: Text('Sitze: ${setSeatNumbers()}'),
trailing: IconButton(
icon: Icon(Icons.edit),
onPressed: () => _updateSeat(_newReservation.performance.id),
),
),
],
),
);
}
}
import 'package:flutter/material.dart';
import 'package:kinobuchungssystem/src/provider/reservation_provider.dart';
import 'package:kinobuchungssystem/src/screens/reservation_screens/add_reservation_screen.dart';
import 'package:kinobuchungssystem/src/screens/reservation_screens/search_reservation_screen.dart';
import 'package:kinobuchungssystem/src/widgets/reservation_item.dart';
import 'package:provider/provider.dart';
class ReservationScreen extends StatelessWidget {
static const routeName = '/reservation';
Future<void> _refreshReservations(BuildContext context) async {
await Provider.of<ReservationProvider>(context, listen: false)
.fetchAndSetReservations();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Reservationen'),
actions: <Widget>[
IconButton(
icon: Icon(Icons.add),
onPressed: () =>
Navigator.of(context).pushNamed(AddReservationScreen.routeName),
),
],
),
floatingActionButton: FloatingActionButton.extended(
label: Text('Reservation suchen'),
onPressed: () => Navigator.of(context).pushNamed(SearchReservationScreen.routeName),
icon: Icon(Icons.search),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
body: FutureBuilder(
future: _refreshReservations(context),
builder: (context, snapshot) => snapshot.connectionState ==
ConnectionState.waiting
? Center(
child: CircularProgressIndicator(),
)
: RefreshIndicator(
onRefresh: () => _refreshReservations(context),
child: Consumer<ReservationProvider>(
builder: (context, reservation, _) => Padding(
padding: EdgeInsets.all(10),
child: ListView.builder(
itemBuilder: (context, index) => Column(
children: <Widget>[
ReservationItem(
id: reservation.reservation[index].id,
customer: reservation.reservation[index].customer,
dateTime: reservation
.reservation[index].performance.dateTime,
movieName: reservation
.reservation[index].performance.movie.title,
),
SizedBox(
height: 10,
)
],
),
itemCount: reservation.reservation.length,
),
),
),
),
),
);
}
}
import 'package:flutter/material.dart';
import 'package:kinobuchungssystem/src/provider/movie_provider.dart';
import 'package:kinobuchungssystem/src/provider/performance_provider.dart';
import 'package:kinobuchungssystem/src/widgets/select_performance.dart';
import 'package:provider/provider.dart';
class AddPerformanceSelectionScreen extends StatelessWidget {
static const routeName = '/select-performance';
Future<void> _setPerformace(BuildContext context) async {
await Provider.of<PerformanceProvider>(context, listen: false)
.fetchAndSetPerformances();
await Provider.of<MovieProvider>(context, listen: false)
.fetchAndSetMovies();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Vorstellung auswählen'),
),
body: FutureBuilder(
future: _setPerformace(context),
builder: (context, snapshot) =>
snapshot.connectionState == ConnectionState.waiting
? Center(
child: CircularProgressIndicator(),
)
: RefreshIndicator(
onRefresh: () => _setPerformace(context),
child: Consumer2<PerformanceProvider, MovieProvider>(
builder: (context, performance, movie, _) => Padding(
padding: EdgeInsets.all(10),
child: ListView.builder(
itemCount: performance.performance.length,
itemBuilder: (context, index) {
final loadedMovie = movie.findById(performance.performance[index].movie.id);
return Column(
children: <Widget>[
SelectPerformance(
id: performance.performance[index].id,
movieName: loadedMovie.title,
dateTime: performance.performance[index].dateTime),
Divider(),
],
);
}),
),
),
),
),
);
}
}
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
class SelectPerformance extends StatelessWidget {
final String id;
final String movieName;
final DateTime dateTime;
SelectPerformance({
#required this.id,
#required this.movieName,
#required this.dateTime,
});
#override
Widget build(BuildContext context) {
final time = DateFormat.Hm().format(dateTime);
final date = DateFormat.d().add_MMMM().add_y().format(dateTime);
return Card(
child: ListTile(
onTap: () => Navigator.pop(context, id),
leading: IconButton(
icon: Icon(Icons.add),
onPressed: () {
print(id);
Navigator.pop(context, id);
},
color: Colors.amberAccent,
),
title: Text('$movieName'),
subtitle: Text(date),
trailing: CircleAvatar(
child: Text(time),
radius: 30,
),
),
);
}
}
I suppose it reloads because of the ModalRout.of. Or of the FutureBuilder... But I found no way to fix it.

every setState in the class EditReservationScreen() also the FuturBuilder is calling _getReservation()
and the _newPerformance is updating again with old values
call _getReservation only one time in the initstate, without any futureBuilder
#override
void initState() {
super.initState();
_getReservation();
}
Or you save your updates in the Provider before you call setstate in _updateSeat()

Related

How to prevent duplicate card widget on same product if i click more than one time in Flutter

I use provider library state management for doing add to cart and basically i am a bit beginner in provider. So the issue i am facing is for example there are three products laptop , iphone x & keyboard. Now if i put laptop two times in the cart then in cart page it displays two laptop card widgets, instead i want to display only one card widget in that laptop qty: 2. And second issue is that i have implemented + and - button in each card widget in cart page and if i click on + or - button then it should reflect on qty and also on total price. Really appreciate if you help me in this problem.
main.dart
void main() {
runApp(ChangeNotifierProvider(
create: (context) => Cart(),
child: MyApp(),
));
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage(),
debugShowCheckedModeBanner: false,
);
}
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
final List<Item> items = [
Item(title: 'laptop ', price: 500.0),
Item(title: 'iphone x ', price: 400.0),
Item(title: 'keyboard ', price: 40.0),
];
#override
Widget build(BuildContext context) {
return Consumer<Cart>(builder: (context, cart, child) {
return Scaffold(
appBar: AppBar(
title: Text('Shopping cart'),
actions: <Widget>[
Padding(
padding: EdgeInsets.all(8.0),
child: Row(
children: <Widget>[
IconButton(
icon: Icon(
Icons.shopping_cart,
color: Colors.white,
),
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => CheckoutPage()));
},
),
Text(cart.count.toString())
],
),
)
],
centerTitle: true,
),
body: ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(items[index].title),
subtitle: Text(items[index].price.toString()),
trailing: Icon(Icons.add),
onTap: () {
cart.add(items[index]);
},
);
},
),
);
});
}
}
CheckoutPage.dart
class CheckoutPage extends StatefulWidget {
#override
_CheckoutPageState createState() => _CheckoutPageState();
}
class _CheckoutPageState extends State<CheckoutPage> {
#override
Widget build(BuildContext context) {
return Consumer<Cart>(
builder: (context, cart, child) {
return Scaffold(
appBar: AppBar(
title: Text('Checkout Page [\$ ${cart.totalPrice}]'),
actions: [
TextButton(
onPressed: () {
print(cart.totalPrice);
},
child: Text('Check'))
],
),
body: cart.basketItems.length == 0
? Text('no items in your cart')
: ListView.builder(
itemCount: cart.basketItems.length,
itemBuilder: (context, index) {
return Card(
child: ListTile(
title: Text(cart.basketItems[index].title),
subtitle: Row(
children: [
TextButton(onPressed: () {}, child: Text('+')),
Text(cart.basketItems[index].qty.toString()),
TextButton(onPressed: () {}, child: Text('-')),
],
),
trailing: IconButton(
icon: Icon(Icons.delete),
onPressed: () {
cart.remove(cart.basketItems[index]);
},
),
),
);
},
));
},
);
}
}
Item.dart
class Item {
String title;
double price;
Item({this.title, this.price});
}
Cart.dart
class Cart extends ChangeNotifier {
List<Item> _items = [];
double _totalPrice = 0.0;
void add(Item item) {
_items.add(item);
_totalPrice += item.price;
notifyListeners();
}
void remove(Item item) {
_totalPrice -= item.price;
_items.remove(item);
notifyListeners();
}
int get count {
return _items.length;
}
double get totalPrice {
return _totalPrice;
}
List<Item> get basketItems {
return _items;
}
}
Hmm try before adding item add a certain function that will look up for the duplicate item like this
e.g. inside on add
Add qty on you class on item.dart so that in every add item you should have default qty to one then goes this below.
class Item {
String title;
double price;
int qty;
Item({this.title, this.price,this.qty});
}
void add(Item item) {
final itemIsExist = _items.where((e)=> e.title == item.title);
if(itemIsExist.isNotEmpty){
// if item exist and you want to add +1 on qty
final addQty = _items.firstWhere((e)=> e.title == item.title);
addQty.qty= addQty.qty+1;
// do your thing here to calculate again the total
}else{
_items.add(item);
_totalPrice += item.price;
notifyListeners();
}
}
I suggest creating another variable on base class and extend it for model, But now let's follow your way.
We can create a map to iterate items on _CheckoutPageState and create a Set, but we need to count the item quantity,
We can take the help of map in this case and place it just under Consumer builder before returning Scaffold
Map<String, int> itemsMap = {};
for (final item in cart._items) {
if (!itemsMap.containsKey(item.title)) {
itemsMap.putIfAbsent(item.title, () => 1);
} else {
itemsMap.update(item.title, (value) => itemsMap[item.title]! + 1);
}
}
And uses will be like
itemBuilder: (context, index) {
final keys = itemsMap.keys.toList();
final count = itemsMap.values.toList();
return Card(
child: ListTile(
title: Text(keys[index].toString()),
subtitle: Row(
children: [
TextButton(onPressed: () {}, child: Text('+')),
Text(count[index].toString()),
TextButton(onPressed: () {}, child: Text('-')),
],
),
State class
class _CheckoutPageState extends State<CheckoutPage> {
#override
Widget build(BuildContext context) {
return Consumer<Cart>(
builder: (context, cart, child) {
Map<String, int> itemsMap = {};
for (final item in cart.basketItems) {
if (!itemsMap.containsKey(item.title)) {
itemsMap.putIfAbsent(item.title, () => 1);
} else {
itemsMap.update(item.title, (value) => itemsMap[item.title]! + 1);
}
}
return Scaffold(
appBar: AppBar(
title: Text('Checkout Page [\$ ${cart.totalPrice}]'),
actions: [
TextButton(
onPressed: () {
print(cart.totalPrice);
},
child: Text('Check'))
],
),
body: cart.basketItems.length == 0
? Text('no items in your cart')
: ListView.builder(
itemCount: itemsMap.length,
itemBuilder: (context, index) {
final keys = itemsMap.keys.toList();
final count = itemsMap.values.toList();
return Card(
child: ListTile(
title: Text(keys[index].toString()),
subtitle: Row(
children: [
TextButton(
onPressed: () {
cart.add(
Item(
title: keys[index].toString(),
price: keys[index].trim() == "laptop"
? 500
: keys[index].trim() == "iphone x"
? 400
: 40,
),
);
},
child: Text('+')),
Text(count[index].toString()),
TextButton(
onPressed: () {
cart.remove(Item(
title: keys[index].toString(),
price: keys[index].trim() == "laptop"
? 500
: keys[index].trim() == "iphone x"
? 400
: 40,
));
},
child: Text('-')),
],
),
trailing: IconButton(
icon: Icon(Icons.delete),
onPressed: () {
cart.remove(cart.basketItems[
index]); // remove match all on remove method
},
),
),
);
},
));
},
);
}
}

What is the correct Provider<AuthBlock> for my DrawerNavigation Widget?

I am working on a simple mobile app with Google sign in capabilities.
So far, the app has been working, but with the latest step (the actual signing in) I am receiving the following error
════════ Exception caught by widgets library ═══════════════════════════════════
Error: Could not find the correct Provider<AuthBlock> above this DrawerNavigation Widget
I have tried the usual suspects; ensuring that the right packages are being imported, that it is due to me running on a virtual mobile device, and that a hot reboot might have been needed.
The issue persists however.
I had expected it to prompt the user to sign in with Google, but that is obviously not happening.
My code is as follows, and I believe the error is originating from line 54 which reads final authBlock = Provider.of(context);.
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:to_do_list/blocks/auth_block.dart';
import 'package:to_do_list/screens/home_screen.dart';
import 'package:to_do_list/screens/categories_screen.dart';
import 'package:to_do_list/screens/todos_by_category.dart';
import 'package:to_do_list/service/category_service.dart';
import 'package:flutter_signin_button/flutter_signin_button.dart';
class DrawerNavigation extends StatefulWidget {
#override
_DrawerNavigationState createState() => _DrawerNavigationState();
}
class _DrawerNavigationState extends State<DrawerNavigation> {
//List<Widget> _categoryList = List<Widget>(); //Has been depricated
List<Widget> _categoryList = List<Widget>.generate(0, (index) {
//Widget obj = Widget();
//obj.id = index;
return;
});
CategoryService _categoryService = CategoryService();
#override
initState() {
super.initState();
getAllCategories();
}
getAllCategories() async {
var categories = await _categoryService.readCategories();
categories.forEach((category) {
setState(() {
_categoryList.add(InkWell(
onTap: () => Navigator.push(
context,
new MaterialPageRoute(
builder: (context) => new TodosByCategory(
category: category['name'],
))),
child: ListTile(
title: Text(category['name']),
),
));
});
});
}
#override
Widget build(BuildContext context) {
final authBlock = Provider.of<AuthBlock>(context);
return Container(
child: Drawer(
child: ListView(
children: <Widget>[
// UserAccountsDrawerHeader(
// currentAccountPicture: CircleAvatar(
// backgroundImage: NetworkImage(
// 'https://cdn.shopify.com/s/files/1/1733/6579/products/product-image-602960373_1024x1024#2x.jpg')),
// accountName: Text('Meena Bobeena'),
// accountEmail: Text('meena#happycat.com'),
// decoration: BoxDecoration(color: Colors.blue),
// ),
Column(
children: [
SignInButton(
Buttons.Google,
onPressed: () => authBlock.loginWithGoogle(),
),
],
),
ListTile(
leading: Icon(Icons.home),
title: Text('Home'),
onTap: () => Navigator.of(context).push(
MaterialPageRoute(builder: (context) => (HomeScreen()))),
),
ListTile(
leading: Icon(Icons.view_list),
title: Text('Categories'),
onTap: () => Navigator.of(context).push(MaterialPageRoute(
builder: (context) => (CategoriesScreen()))),
),
Divider(),
Column(
children: _categoryList,
)
],
),
),
);
}
}
As requested, the following is how the DrawerNavigation is called.
import 'package:flutter/material.dart';
import 'package:to_do_list/helpers/drawer_navigation.dart';
import 'package:to_do_list/screens/todo_screen.dart';
import 'package:to_do_list/service/todo_service.dart';
import 'package:to_do_list/models/todo.dart';
class HomeScreen extends StatefulWidget {
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
TodoService _todoService;
//List<Todo> _todoList = List<Todo>(); // Has been deprecated
List<Todo> _todoList = List<Todo>.generate(0, (index) {
Todo obj = Todo();
obj.id = index;
return obj;
});
#override
initState() {
super.initState();
getAllTodos();
}
getAllTodos() async {
_todoService = TodoService();
//_todoList = List<Todo>(); //Has been depricated
_todoList = List<Todo>.generate(0, (index) {
Todo obj = Todo();
obj.id = index;
return obj;
});
var todos = await _todoService.readTodos();
todos.forEach((todo) {
setState(() {
var model = Todo();
model.id = todo['id'];
model.title = todo['title'];
model.description = todo['description'];
model.category = todo['category'];
model.todoDate = todo['todoDate'];
model.isFinished = todo['isFinished'];
_todoList.add(model);
});
});
}
_deleteFormDialog(BuildContext context, categoryId) {
return showDialog(
context: context,
barrierDismissible: true,
builder: (param) {
return AlertDialog(
actions: <Widget>[
TextButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.red),
foregroundColor: MaterialStateProperty.all(Colors.white)),
onPressed: () async {
Navigator.pop(context);
},
child: Text('Cancel'),
),
TextButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.green),
foregroundColor: MaterialStateProperty.all(Colors.white)),
// This doesn't delete :'(
onPressed: () async {
var result = await _todoService.deleteTodos(categoryId);
//print(result);
if (result > 0) {
print(result);
Navigator.pop(context);
getAllTodos();
_showSuccessSnackBar(Text('Deleted'));
}
},
child: Text('Delete'),
),
],
title: Text('Are you sure you wish to delete this To Do item ?'),
);
});
}
_showSuccessSnackBar(message) {
var _snackBar = SnackBar(content: message);
ScaffoldMessenger.of(context).showSnackBar(_snackBar);
//_globalKey.currentState.showSnackBar(_snackBar); === Depreciated
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Meenas To Do List')),
drawer: DrawerNavigation(),
body: ListView.builder(
itemCount: _todoList.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.only(top: 8, left: 8, right: 8),
child: Card(
elevation: 8,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
child: ListTile(
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(_todoList[index].title ?? 'No Title'),
IconButton(
icon: Icon(Icons.delete, color: Colors.red),
onPressed: () {
_deleteFormDialog(context, _todoList[index].id);
},
)
],
),
subtitle: Text(_todoList[index].category ?? 'No Category'),
trailing: Text(_todoList[index].todoDate ?? 'No Date'),
),
),
);
}),
floatingActionButton: FloatingActionButton(
onPressed: () => Navigator.of(context)
.push(MaterialPageRoute(builder: (context) => TodoScreen())),
child: Icon(Icons.add)),
);
}
}
This is the code where I instantiate the provider
import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:to_do_list/service/auth_service.dart';
class AuthBlock {
final authService = AuthService();
final googleSignIn = GoogleSignIn(scopes: ['email']);
Stream<User> get currentUser => authService.currentUser;
loginWithGoogle() async {
try {
final GoogleSignInAccount googleUser = await googleSignIn.signIn();
final GoogleSignInAuthentication googleAuth =
await googleUser.authentication;
final AuthCredential credential = GoogleAuthProvider.credential(
idToken: googleAuth.idToken,
accessToken: googleAuth.accessToken,
);
//Firebase Sign In
final result = await authService.signInWithCredential(credential);
print('${result.user.displayName}');
} catch (error) {
print(error);
}
}
logout() {
authService.logout();
}
}
The main.dart
import 'package:flutter/material.dart';
import 'package:to_do_list/src/app.dart';
void main() => runApp(App());
Did you wrap your app with the provider? E.g. like you see here
runApp(
/// Providers are above [MyApp] instead of inside it, so that tests
/// can use [MyApp] while mocking the providers
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => Counter()),
],
child: const MyApp(),
),
);

How to implement a process that uses flutter_secure_storage package to read and write the data [with Provider package]

I'm new to Flutter and Dart. I made a simple Todos app with Provider package and Consumer. I'm trying to implement a process that uses flutter_secure_storage package to read and write the list data on the device.
But I don't know how to implement it.
Checkbox widget requires a bool, while secure_storage requires the type of String. Therefore, it is necessary to convert both types. This also confuses me a little.
The code is below.
I would be happy if you could give me some advice.
main.dart
// Todos app example
import 'package:consumer_samp/list_model.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: ChangeNotifierProvider<ListModel>(
create: (context) => ListModel(),
child: MyHomePage('Todos app example'),
),
);
}
}
class MyHomePage extends StatelessWidget {
MyHomePage(this.title);
final String title;
final TextEditingController eCtrl = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: SingleChildScrollView(
child: Column(
children: <Widget>[
Container(
padding: EdgeInsets.all(10),
child: Row(
children: <Widget>[
Expanded(
child: TextField(
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'Enter your ToDo item',
),
controller: eCtrl,
),
),
Consumer<ListModel>(
builder: (_, listModel, __) => FlatButton(
child: Text('Add'),
onPressed: () {
if (eCtrl.text != '') {
Map<String, dynamic> item = {
'value': false,
'text': eCtrl.text
};
listModel.addItem(item);
eCtrl.clear();
}
},
),
),
],
),
),
Center(
child: Consumer<ListModel>(builder: (_, listModel, __) {
var items = listModel.getItems;
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
height: 300,
child: ListView.builder(
itemCount: items.length,
itemBuilder: (BuildContext context, int idx) =>
Container(
padding: const EdgeInsets.all(5),
color: Colors.green,
child: Row(
children: <Widget>[
Checkbox(
value: items[idx]['value'],
onChanged: (val) {
listModel.toggleValue(idx, val);
}),
Text(
items[idx]['text'],
style: TextStyle(
fontSize: 21, color: Colors.white),
),
],
),
),
),
),
],
);
}),
),
],
),
),
);
}
}
list_model.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
class ListModel with ChangeNotifier {
List<Map<String, dynamic>> _items = [];
List<Map<String, dynamic>> get getItems => _items;
void addItem(Map<String, dynamic> item) {
_items.add(item);
notifyListeners();
}
void toggleValue(int idx, bool val) {
_items[idx]['value'] = val;
notifyListeners();
}
}
You can copy paste run full code below
You can use class TodoItem and save/load with JSON String
Provider logic for secure storage is in full code, too long to describe detail
code snippet
List<TodoItem> todoItemFromJson(String str) =>
List<TodoItem>.from(json.decode(str).map((x) => TodoItem.fromJson(x)));
String todoItemToJson(List<TodoItem> data) =>
json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class TodoItem {
TodoItem({
this.item,
this.checked,
});
String item;
bool checked;
factory TodoItem.fromJson(Map<String, dynamic> json) => TodoItem(
item: json["item"],
checked: json["checked"],
);
Map<String, dynamic> toJson() => {
"item": item,
"checked": checked,
};
}
working demo
full code
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'dart:convert';
List<TodoItem> todoItemFromJson(String str) =>
List<TodoItem>.from(json.decode(str).map((x) => TodoItem.fromJson(x)));
String todoItemToJson(List<TodoItem> data) =>
json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class TodoItem {
TodoItem({
this.item,
this.checked,
});
String item;
bool checked;
factory TodoItem.fromJson(Map<String, dynamic> json) => TodoItem(
item: json["item"],
checked: json["checked"],
);
Map<String, dynamic> toJson() => {
"item": item,
"checked": checked,
};
}
class ListModel with ChangeNotifier {
FlutterSecureStorage _storage;
List<TodoItem> _items = [];
List<TodoItem> get getItems => _items;
initilaize() async {
print("initialize");
String jsonString = await _storage.read(key: "todo");
if (jsonString != null) {
_items = todoItemFromJson(jsonString);
notifyListeners();
}
}
ListModel.init(FlutterSecureStorage storage) {
print("init");
_storage = storage;
initilaize();
}
void update(FlutterSecureStorage storage) {
print("update");
_storage = storage;
}
void addItem(TodoItem item) {
_items.add(item);
notifyListeners();
}
void toggleValue(int idx, bool val) {
_items[idx].checked = val;
notifyListeners();
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: MultiProvider(
providers: [
Provider<FlutterSecureStorage>(create: (_) => FlutterSecureStorage()),
ChangeNotifierProxyProvider<FlutterSecureStorage, ListModel>(
create: (_) {
return ListModel.init(
Provider.of<FlutterSecureStorage>(_, listen: false));
},
update: (_, storage, listModel) => listModel..update(storage),
),
],
child: MyHomePage('Todos app example'),
),
);
}
}
class MyHomePage extends StatelessWidget {
MyHomePage(this.title);
final String title;
final TextEditingController eCtrl = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
actions: <Widget>[
Consumer2<ListModel, FlutterSecureStorage>(
builder: (_, listModel, storage, __) => IconButton(
icon: Icon(Icons.save),
onPressed: () async {
await storage.write(
key: "todo", value: todoItemToJson(listModel._items));
print("save done");
},
))
],
),
body: SingleChildScrollView(
child: Column(
children: <Widget>[
Container(
padding: EdgeInsets.all(10),
child: Row(
children: <Widget>[
Expanded(
child: TextField(
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'Enter your ToDo item',
),
controller: eCtrl,
),
),
Consumer<ListModel>(
builder: (_, listModel, __) => FlatButton(
child: Text('Add'),
onPressed: () {
if (eCtrl.text != '') {
Map<String, dynamic> item = {
'value': false,
'text': eCtrl.text
};
listModel.addItem(
TodoItem(item: eCtrl.text, checked: false));
eCtrl.clear();
}
},
),
),
],
),
),
Center(
child: Consumer<ListModel>(builder: (_, listModel, __) {
var items = listModel.getItems;
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
height: 300,
child: ListView.builder(
itemCount: items.length,
itemBuilder: (BuildContext context, int idx) =>
Container(
padding: const EdgeInsets.all(5),
color: Colors.green,
child: Row(
children: <Widget>[
Checkbox(
value: items[idx].checked,
onChanged: (val) {
listModel.toggleValue(idx, val);
}),
Text(
items[idx].item,
style: TextStyle(
fontSize: 21, color: Colors.white),
),
],
),
),
),
),
],
);
}),
),
],
),
),
);
}
}
As mentioned in the readme files by the following link
https://pub.dev/packages/flutter_secure_storage
The following code instantiate the storage, and the following code's must be in a async method as this returns a future.
final storage = new FlutterSecureStorage();
And you can pass the _items list as a value and you can set some key name
await storage.write(key: key, value: _items);
And then you could get that value by using the key name (which is set while storing)
List<Map<String, dynamic>> _value = await storage.read(key: key);
And then you could map the _value you get from storage and you can store it in _items. And then you could do various operations and queries inside your app now with all data you have.
Make a note! I haven't tried this approach in my code base. Just I said what I thought. Please try this in your code and comment me please.
The following code executes correctly use this in model, for storing data:
Future<void> _storingData() async {
final storage = new FlutterSecureStorage();
for (int i = 0; i < _items.length; i++) {
await storage
.write(key: _items[i]['text'], value: "${_items[i]['value']}")
.then((value) => print("success"));
}
}
For retrieving data:
Future<void> retrivingData() async {
final storage = new FlutterSecureStorage();
Map<String, String> allValues = await storage.readAll();
print(allValues);
allValues.forEach((key, value) {
bool val = bool.fromEnvironment(value, defaultValue: false);
Map<String, dynamic> item = {'value': val, 'text': key};
addItem(item);
});
}
and finally I stored all values again to a list.
You should do some changes in your code in main.dart according to the above methods based on your usage.

How change the visual of List of Radio button?

I have a bet game it is a list of game and user need to choose between 3 choices (only one choice) (1,N,2) so i use radio in flutter for do it.
1 - Here is the result i have now :
2 - Here is the result i want to have :
I need have the same radio 1 N 2 without using any images, i think it is possible to do it using clipoval perhaps with rounded borders. Here the selected radio is in RED in background so when i click on another radio it needs change the color of radio (red background and white color font if selected and white background and red color font if not selected)
And now here is my entire code for the grid :
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'dart:async';
import 'package:flutter_app/menu_member.dart';
import 'package:flutter_app/globals.dart' as globals;
import 'package:flutter_app/grille_lotosport.dart';
// Create
a Form widget.
class Affiche_grille extends StatefulWidget {
#override
String id;
Affiche_grille({Key key, #required this.id}) : super(key: key);
_Affiche_grille_State createState() {
return _Affiche_grille_State();
}
}
// Create a corresponding State class.
// This class holds data related to the form.
class _Affiche_grille_State extends State<Affiche_grille> {
#override
final _formKey = GlobalKey<FormState>();
List<String> radioValues = [];
Future<List<Match>> grid;
Future <List<Match>> Grille_display() async {
// SERVER LOGIN API URL
var url = 'https://www.easytrafic.fr/game_app/display_grid.php';
// Store all data with Param Name.
var data = {'id_grille': widget.id};
// Starting Web API Call.
var response = await http.post(url, body: json.encode(data),headers: {'content-type': 'application/json','accept': 'application/json','authorization': globals.token});
// Getting Server response into variable.
var jsondata = json.decode(response.body);
List<Match> Matchs = [];
for (var u in jsondata) {
Match match = Match(u["equipe1"],u["equipe2"],u["type_prono"]);
Matchs.add(match);
radioValues.add("N");
}
return Matchs;
}
void initState() {
grid = Grille_display();
super.initState();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('GRILLE LOTOSPORT'),
),
drawer: new DrawerOnly(),
body:
Container(
child:
FutureBuilder(
future: grid,
builder: (BuildContext context, AsyncSnapshot snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return new Center(
child: new CircularProgressIndicator(),);
default:
if (snapshot.hasError) {
return new Center(
child: new Text('Error: ${snapshot.error}'),);
}
else {
List<Match> values = snapshot.data;
return Form(
key: _formKey,
child: ListView(
children: <Widget>[
DataTable(
columnSpacing: 20,
columns: [
DataColumn(
label: Text("Libelle Match"),
numeric: false,
tooltip: "",
),
DataColumn(
label: Text("1"),
numeric: false,
tooltip: "",
),
DataColumn(
label: Text("N"),
numeric: false,
tooltip: "",
),
DataColumn(
label: Text("2"),
numeric: false,
tooltip: "",
),
],
rows:
List.generate(values.length, (index) {
return DataRow(
cells: [
DataCell(
Text(values[index].equipe1.toString() +
" - " +
values[index].equipe2.toString()),
),
DataCell(
Radio(
value: "1",
groupValue: radioValues[index],
onChanged: (val) {
setState(() {
radioValues[index] = val;
});
},
),
),
DataCell(
Radio(
value: "N",
groupValue: radioValues[index],
onChanged: (val) {
setState(() {
radioValues[index] = val;
});
},
),
),
DataCell(
Radio(
value: "2",
groupValue: radioValues[index],
onChanged: (val) {
setState(() {
radioValues[index] = val;
});
},
),
),
]
);
}).toList(),
),
Center(
child: RaisedButton(
color: Colors.green,
textColor: Colors.white,
padding: EdgeInsets.fromLTRB(9, 9, 9, 9),
child: Text('VALIDER VOTRE GRILLE'),
onPressed: () {
Valide_grille();
},
),
),
],
)
);
};
};
},
),
),
),
);
}
Future Valide_grille() async{
// For CircularProgressIndicator.
bool visible = false ;
// Showing CircularProgressIndicator.
setState(() {
visible = true ;
});
// SERVER LOGIN API URL
var url = 'https://www.easytrafic.fr/game_app/valide_grid.php';
var concatenate='';
radioValues.forEach((item){
concatenate=concatenate+item;
});
var id_grille=widget.id;
// Store all data with Param Name.
var data = {'id_membre':globals.id_membre, 'id_grille':id_grille,'result':concatenate};
var grille_encode=jsonEncode(data);
// Starting Web API Call.
var response = await http.post(url, body: grille_encode,headers: {'content-type': 'application/json','accept': 'application/json','authorization': globals.token});
print(response.body);
// Getting Server response into variable.
Map <String,dynamic> map2 = json.decode(response.body);
// If the Response Message is Matched.
if(map2["status"] == 1)
{
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: new Text(map2["message"]),
actions: <Widget>[
FlatButton(
child: new Text("OK"),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Affiche_Liste_grille()),
);
},
),
],
);
},
);
// Hiding the CircularProgressIndicator.
setState(() {
visible = false;
});
}else{
// Hiding the CircularProgressIndicator.
setState(() {
visible = false;
});
// Showing Alert Dialog with Response JSON Message.
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: new Text(map2["message"]),
actions: <Widget>[
FlatButton(
child: new Text("OK"),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
}
}
class Match {
final String equipe1;
final String equipe2;
final String typeprono;
const Match(this.equipe1, this.equipe2, this.typeprono);
}
I have found the solution, i Don't understand why it works but it works now with allmy corrections. I Don't understand why when i put a setstate all elements are updated correctly, i put no code in the setstate but all is now updated, it is very strange

FutureBuilder and async function in flutter

I have a problem with FutureBuilder, it refresh and execute code again when there is a change like when i change value of radio button, i click on radio and it reloads all futurebuilder it seems.
EDIT : i have corrected the problem and here is my solution, i am not sure it works all time
My full code is :
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'dart:async';
// Create a Form widget.
class Affiche_grille extends StatefulWidget {
#override
_Affiche_grille_State createState() {
return _Affiche_grille_State();
}
}
// Create a corresponding State class.
// This class holds data related to the form.
class _Affiche_grille_State extends State<Affiche_grille> {
#override
final _formKey = GlobalKey<FormState>();
List<String> radioValues = [];
Future<List<Match>> grid;
Future <List<Match>> Grille_display() async {
// SERVER LOGIN API URL
var url = 'http://www.axis-medias.fr/game_app/display_grid.php';
// Store all data with Param Name.
var data = {'id_grille': 1};
// Starting Web API Call.
var response = await http.post(url, body: json.encode(data));
// Getting Server response into variable.
var jsondata = json.decode(response.body);
List<Match> Matchs = [];
for (var u in jsondata) {
Match match = Match(u["equipe1"],u["equipe2"],u["type_prono"]);
Matchs.add(match);
radioValues.add("N");
}
return Matchs;
}
void initState() {
grid = Grille_display();
super.initState();
}
#override
Widget build(BuildContext context) {
final appTitle = 'MONEYFREE';
return MaterialApp(
title: appTitle,
home: Scaffold(
appBar: AppBar(
title: Text(appTitle),
),
body: Container(
child:
FutureBuilder(
future: grid,
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.data == null) {
return Container (
child: Center(
child: Text("Chargement en cours...")
)
);
}
else {
List<Match> values = snapshot.data;
return Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
DataTable(
columnSpacing: 20,
columns: [
DataColumn(
label: Text("Libelle Match"),
numeric: false,
tooltip: "",
),
DataColumn(
label: Text("1"),
numeric: false,
tooltip: "",
),
DataColumn(
label: Text("N"),
numeric: false,
tooltip: "",
),
DataColumn(
label: Text("2"),
numeric: false,
tooltip: "",
),
],
rows:
List.generate(values.length, (index) {
return DataRow(
cells: [
DataCell(
Text(values[index].equipe1.toString() + " - " + values[index].equipe2.toString()),
),
DataCell(
Radio(
value: "1",
groupValue: radioValues[index],
onChanged: (val) {
setState(() {
radioValues[index] = val;
print('Change 1');
print(radioValues);
});
},
),
),
DataCell(
Radio(
value: "N",
groupValue: radioValues[index],
onChanged: (val) {
setState(() {
radioValues[index] = val;
print('Change N');
print(radioValues);
});
},
),
),
DataCell(
Radio(
value: "2",
groupValue: radioValues[index],
onChanged: (val) {
setState(() {
radioValues[index] = val;
print('Change 2');
print(radioValues);
});
},
),
),
]
);
}).toList(),
),
Center(
child: RaisedButton(
color: Colors.green,
textColor: Colors.white,
padding: EdgeInsets.fromLTRB(9, 9, 9, 9),
child: Text('VALIDER VOTRE GRILLE'),
onPressed: () {
Valide_grille();
},
),
),
],
)
);
};
},
),
),
),
);
}
Future Valide_grille() async{
// For CircularProgressIndicator.
bool visible = false ;
// Showing CircularProgressIndicator.
setState(() {
visible = true ;
});
// SERVER LOGIN API URL
var url = 'http://www.axis-medias.fr/game_app/valide_grid.php';
var concatenate='';
radioValues.forEach((item){
concatenate=concatenate+item;
});
// Store all data with Param Name.
var data = {'id_membre':1, 'id_grille':1,'result':concatenate};
print (data);
var grille_encode=jsonEncode(data);
print(grille_encode);
// Starting Web API Call.
var response = await http.post(url, body: grille_encode);
print(response.body);
// Getting Server response into variable.
var message = json.decode(response.body);
// If the Response Message is Matched.
if(message == 'OK')
{
print('VALIDATION DE LA GRILLE OK');
// Hiding the CircularProgressIndicator.
setState(() {
visible = false;
});
}else{
// If Email or Password did not Matched.
// Hiding the CircularProgressIndicator.
setState(() {
visible = false;
});
// Showing Alert Dialog with Response JSON Message.
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: new Text(message),
actions: <Widget>[
FlatButton(
child: new Text("OK"),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
}
}
class Match {
final String equipe1;
final String equipe2;
final String typeprono;
const Match(this.equipe1, this.equipe2, this.typeprono);
}
You can copy paste run full code below
Reason
didUpdateWidget of the FutureBuilder state is being called every time a rebuild is issued. This function checks if the old future object is different from the new one, and if so, refires the FutureBuilder.
https://github.com/flutter/flutter/issues/11426#issuecomment-414047398
Solution
Future _future;
#override
void initState() {
// TODO: implement initState
_future = Grille_display();
}
...
child: FutureBuilder(
future: _future,
working demo
full code
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'dart:async';
// Create a Form widget.
class Affiche_grille extends StatefulWidget {
#override
_Affiche_grille_State createState() {
return _Affiche_grille_State();
}
}
// Create a corresponding State class.
// This class holds data related to the form.
class _Affiche_grille_State extends State<Affiche_grille> {
#override
final _formKey = GlobalKey<FormState>();
List<String> radioValues = [];
Future<List<Match>> Grille_display() async {
// SERVER LOGIN API URL
var url = 'http://www.axis-medias.fr/game_app/display_grid.php';
// Store all data with Param Name.
var data = {'id_grille': 1};
// Starting Web API Call.
var response = await http.post(url, body: json.encode(data));
// Getting Server response into variable.
var jsondata = json.decode(response.body);
List<Match> Matchs = [];
for (var u in jsondata) {
Match match = Match(u["equipe1"], u["equipe2"], u["type_prono"]);
Matchs.add(match);
}
return Matchs;
}
Future _future;
#override
void initState() {
// TODO: implement initState
_future = Grille_display();
}
#override
Widget build(BuildContext context) {
final appTitle = 'MONEYFREE';
return MaterialApp(
title: appTitle,
home: Scaffold(
appBar: AppBar(
title: Text(appTitle),
),
body: Container(
child: FutureBuilder(
future: _future,
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.data == null) {
return Container(
child: Center(child: Text("Chargement en cours...")));
} else {
List<Match> values = snapshot.data;
values.forEach((m) {
radioValues.add("N");
//like N or something
});
print('valeur radio après initialisation');
print(radioValues);
return Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
DataTable(
columnSpacing: 20,
columns: [
DataColumn(
label: Text("Libelle Match"),
numeric: false,
tooltip: "",
),
DataColumn(
label: Text("1"),
numeric: false,
tooltip: "",
),
DataColumn(
label: Text("N"),
numeric: false,
tooltip: "",
),
DataColumn(
label: Text("2"),
numeric: false,
tooltip: "",
),
],
rows: List.generate(values.length, (index) {
return DataRow(cells: [
DataCell(
Text(values[index].equipe1.toString() +
" - " +
values[index].equipe2.toString()),
),
DataCell(
Radio(
value: "1",
groupValue: radioValues[index],
onChanged: (val) {
setState(() {
radioValues[index] = val;
print('Change 1');
print(radioValues);
});
},
),
),
DataCell(
Radio(
value: "N",
groupValue: radioValues[index],
onChanged: (val) {
setState(() {
radioValues[index] = val;
print(radioValues);
});
},
),
),
DataCell(
Radio(
value: "2",
groupValue: radioValues[index],
onChanged: (val) {
setState(() {
radioValues[index] = val;
print(radioValues);
});
},
),
),
]);
}).toList(),
),
Center(
child: RaisedButton(
color: Colors.green,
textColor: Colors.white,
padding: EdgeInsets.fromLTRB(9, 9, 9, 9),
child: Text('VALIDER VOTRE GRILLE'),
onPressed: () {
Valide_grille();
},
),
),
],
));
}
;
},
),
),
),
);
}
Future Valide_grille() async {
// For CircularProgressIndicator.
bool visible = false;
// Showing CircularProgressIndicator.
setState(() {
visible = true;
});
// SERVER LOGIN API URL
var url = 'http://www.axis-medias.fr/game_app/valide_grid.php';
// Store all data with Param Name.
var data = jsonEncode(radioValues);
print(radioValues);
// Starting Web API Call.
var response = await http.post(url, body: json.encode(data));
// Getting Server response into variable.
var message = json.decode(response.body);
// If the Response Message is Matched.
if (message == 'OK') {
print('VALIDATION DE LA GRILLE OK');
// Hiding the CircularProgressIndicator.
setState(() {
visible = false;
});
} else {
// If Email or Password did not Matched.
// Hiding the CircularProgressIndicator.
setState(() {
visible = false;
});
// Showing Alert Dialog with Response JSON Message.
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: new Text(message),
actions: <Widget>[
FlatButton(
child: new Text("OK"),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
}
}
class Match {
final String equipe1;
final String equipe2;
final String typeprono;
const Match(this.equipe1, this.equipe2, this.typeprono);
}
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Affiche_grille(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}