Search code examples
jsonflutterdartflutter-listview

Flutter: using shared preferences plugin to store saved favorite list


The following is my JSON file which include the data:

[
    {
        "city": "City1",
        "attractions": [
            "attraction1",
            "attraction2"
        ],
    },
    {
        "city": "city2",
        "attractions": [
            "attraction1",
            "attraction2",
        ],
    },
]

My implementation code is a listview builder that gets data from the JSON file. the code also have an option option to save cities as favorite that can be shown in another page as a list of saved favorites:

class Index extends StatefulWidget {
  @override
  _IndexState createState() => _IndexState();
}
List data;
List<Cities> citylist = List();
List<Cities> citysavedlist = List();
int index;
class _IndexState extends State<Index> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: listView(),
    );
  }
  Future<String> fetchData() async {
    String data =
        await DefaultAssetBundle.of(context).loadString("assets/data.json");
    final jsonResult = json.decode(data);
    this.setState(() {
      jsonResult
          .forEach((element) => citylist.add(new Cities.fromJson(element)));
    });
    return "Success!";
  }

  @override
  void initState() {
    super.initState();
    fetchData();
  }

  listView() {
    return ListView.builder(
      itemCount: citylist == null ? 0 : citylist.length,
      itemBuilder: (context, index) {
        return Column(
          children: <Widget>[_buildRow(index, citylist)],
        );
      },
    );
  }

  Widget _buildRow(index, citylist) {
    final bool alreadySaved = citysavedlist.contains(citylist[index]);
    return Padding(
      padding: const EdgeInsets.only(top: 5.0, left: 5.0, right: 5.0),
      child: Card(
        child: ListTile(
            title:
                Text(citylist[index].title, style: TextStyle(fontSize: 22.0)),
            trailing: IconButton(
              icon: Icon(
                alreadySaved ? Icons.star : Icons.star_border,
                color: alreadySaved ? Colors.blue : Colors.blue,
              ),
              onPressed: () {
                setState(() {
                  if (alreadySaved) {
                    citysavedlist.remove(citylist[index]);
                  } else {
                    citysavedlist.add(citylist[index]);
                  }
                });
              },
            ), //subtitle: Text(subtitle),
            onTap: () {
              Navigator.push(
                  context,
                  MaterialPageRoute(
                      builder: (context) => Detail(citylist[index])));
            }),
      ),
    );
  }


void _pushSaved() {
    Navigator.of(context).push(
      MaterialPageRoute<void>(
        builder: (BuildContext context) {
          final Iterable<ListTile> tiles = citysavedlist.map(
            (Cities pair) {
              return ListTile(
                  title: Text(
                    pair.city,
                  ),
                  onTap: () {
                    Navigator.push(context,
                        MaterialPageRoute(builder: (context) => Detail(pair)));
                  });
            },
          );

          final List<Widget> divided = ListTile.divideTiles(
            context: context,
            tiles: tiles,
          ).toList();
          return Scaffold(
            appBar: AppBar(
              title: const Text('Saved Suggestions'),
            ),
            body: ListView(children: divided),
          );
        },
      ),
    );
  }
}

This is model class :

List<Cities> citiesFromJson(String str) =>
    List<Cities>.from(json.decode(str).map((x) => Cities.fromJson(x)));
String citiesToJson(List<Cities> data) =>
    json.encode(List<dynamic>.from(data.map((x) => x.toJson())));

class Cities {
  Cities({
    this.city,
    this.attractions,
  });

  String city;
  List<String> attractions;

  factory Cities.fromJson(Map<String, dynamic> json) => Cities(
        city: json["city"],
        attractions: List<String>.from(json["attractions"].map((x) => x)),
      );

  Map<String, dynamic> toJson() => {
        "city": city,
        "attractions": List<dynamic>.from(attractions.map((x) => x)),
      };
}

Now I am facing an issue which is the saved favorite cities is not stored, so when the app is closed and reopened again, the favorite list will disappear as it is not stored.

I know that there is a plugin called Shared preferences that will do this functionality of storing saved data, but I am not able to integrate this plugin into my code. Can someone help to do that.


Solution

  • First what you have to do is get the package in the pubspec then

    import 'package:shared_preferences/shared_preferences.dart';
    
    SharedPreferences prefs = await SharedPreferences.getInstance();
    

    Now to save the json data you have to do is

    prefs.setString('mydata', json.encode(yourjsondata));
    

    to retrieve this data you must use the exact name you assigned , in my case 'mydata'

    json.decode(preferences.getString('mydata'))
    

    Remember If you want to save so many data items sqflite or hive is recommended or If you still want to use shared_preferences you might save a counter as

    To save

    var counter = (prefs.getInt('Counter')??0)+1;
    prefs.setString('Counter:$counter', json.encode(yourdata));
    

    To get back in the order

    var listCount = preferences.getInt('Counter');
    

    loop through using listCount and then use

    json.decode(preferences.getString('Counter:$variable'))