Given the official Flutter codelabs with the startup name generator, I have added a FutureBuilder
and data from a HTTP GET request.
I have a button that adds an item to a "favorite" list. Another screen has a list with all the favorites. When removing a favorite from this second screen, the state in the first screen is not updated. What am I missing?
myScreen.dart:
import 'dart:convert';
import 'package:testapp/models/User.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:testapp/screens/favoriteList.dart';
class MyScreen extends StatefulWidget {
@override
_MyScreenState createState() => _MyScreenState();
}
class _MyScreenState extends State<MyScreen> {
Future<List<User>> _listFuture;
Set<User> _saved = {};
@override
void initState() {
super.initState();
_listFuture = fetchUsers(http.Client());
}
Future<Null> refreshList() async {
setState(() {
_listFuture = fetchUsers(http.Client());
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Test'),
actions: [
IconButton(icon: Icon(Icons.list), onPressed: _pushSaved),
],
),
body: Container(
child: new FutureBuilder<List<User>>(
future: _listFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return new Center(
child: new CircularProgressIndicator(),
);
} else if (snapshot.hasError) {
return new Text("Error");
} else {
final items = snapshot.data ?? <User>[];
return new Scrollbar(
child: new RefreshIndicator(
child: ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return _buildRow(items[index]);
},
),
onRefresh: refreshList));
}
},
),
),
);
}
Widget _buildRow(User user) {
final alreadySaved = _saved.contains(user);
return Container(
child: Card(
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
ListTile(title: Text(user.firstName)),
IconButton(
icon: Icon(
alreadySaved ? Icons.favorite : Icons.favorite_border,
),
onPressed: () {
setState(() {
if (alreadySaved) {
_saved.remove(user);
} else {
_saved.add(user);
}
});
}),
]),
));
}
void _pushSaved() {
Navigator.of(context).push(MaterialPageRoute<void>(
builder: (BuildContext context) => FavoriteList(data: _saved),
));
}
Future<List<User>> fetchUsers(http.Client client) async {
var response = await http.get(Uri.https("reqres.in", "api/users"));
var body = json.decode(response.body);
List<User> users =
List<User>.from(body['data'].map((model) => User.fromJson(model)));
return users;
}
}
favoriteList.dart:
import 'package:testapp/models/User.dart';
import 'package:flutter/material.dart';
class FavoriteList extends StatefulWidget {
final Set<User> data;
FavoriteList({Key key, this.data}) : super(key: key);
@override
_FavoriteListState createState() => _FavoriteListState();
}
class _FavoriteListState extends State<FavoriteList> {
Set<User> _saved;
@override
void initState() {
_saved = widget.data;
super.initState();
}
@override
Widget build(BuildContext context) {
final Iterable<ListTile> tiles = _saved.map(
(User user) {
return ListTile(
title: Row(
children: <Widget>[
Text(
user.firstName,
),
IconButton(
icon: const Icon(Icons.delete),
onPressed: () {
setState(() {
_saved.remove(user);
});
},
)
],
),
);
},
);
final List<Widget> divided = ListTile.divideTiles(
context: context,
tiles: tiles,
).toList();
return Scaffold(
appBar: AppBar(
title: const Text('Saved users'),
),
body: ListView(children: divided),
);
}
}
User.dart:
class User {
int id;
String email;
String firstName;
User(int id, String email, String firstName) {
this.id = id;
this.email = email;
this.firstName = firstName;
}
User.fromJson(Map json)
: id = json['id'],
email = json['email'],
firstName = json['first_name'];
Map toJson() {
return {'id': id, 'email': email, 'firstName': firstName};
}
}