brace brace
brace brace

Reputation: 51

Saving state of Map to Flutter app with Provider

I have a ListView that is rendered based on the below structure. The Map has about 5 'String' key values, each with 1 List of 10-15 ItemModels. The isDone is flipped by calling the individual ItemModels with toggleDone(). This saves the bool state in the app, but it resets once the app is closed. I looked into sharedprefences, but -

  1. I cant figure out how to encode this specific Map and then load the necessary values.
  2. Is this even something I should be doing on the Model class, or the individual ItemModel classes?
  3. Is there a way to encode only the bool values and then load those?

The ChangeNotifier class that holds the Map:

 ```
class Data extends ChangeNotifier {
   List<ItemModel> getData(name) => items[name];

        Map<String, List<ItemModel>> items = {
                'String': [
                  ItemModel(
                    title: 'Some text',
                    text:
                        'Some other text',
                    isDone: false,
                    duration: Duration(
                      hours: 0,
                      minutes: 0,
                      seconds: 10,
                    ),
                  ),
                ]
            };
          }

The ItemModel:

class ItemModel {
  final String title;
  final String text;
  bool isDone;
  Duration duration;

  ItemModel(
      {this.text, this.title, this.isDone = false, this.duration});

  void toggleDone() {
    isDone = !isDone;
  }
}

For each ItemModel in the List, an Item is rendered that looks like this. It takes the ItemModel value of isDone to set the isChecked property.

class Item extends StatelessWidget {
  final String title;
  final String text;
  final bool isChecked;
  final Function checkboxCallback;

  Item(
      {this.text,
      this.title,
      this.isChecked,
      this.checkboxCallback});

      @override
      Widget build(BuildContext context) {
        return Padding(
          child: ListTile(
            leading: Checkbox(
              value: isChecked,
              onChanged: checkboxCallback,
            ),
            title: Text(
              title,
            ),
            subtitle: isChecked
                ? Text('')
                : Text(
                    text,
                  ),
          ),
        );
      }
    }

I appreciate any help 😀

Upvotes: 2

Views: 1339

Answers (1)

nstosic
nstosic

Reputation: 2614

As you mentioned the SharedPreferences only support persisting primitive values. What you can do, assuming you can guarantee unique key for each instance of ItemModel in the list, is to write your own wrapper around SharedPreferences:

import 'package:shared_preferences/shared_preferences.dart';

abstract class SharedPreferencesKeys {
  static const title = 'title';
  static const text = 'text';
  static const isDone = 'isDone';
  static const duration = 'duration';
}

class SharedPreferencesImpl {
  SharedPreferences _preferences;
  Future<SharedPreferences> get preferences async => _preferences ??= await SharedPreferences.getInstance();

  Future<void> write(String key, ItemModel value) async {
    final sharedPrefs = await preferences;
    await sharedPrefs.setString('$key_${SharedPreferencesKeys.title}', value.title);
    await sharedPrefs.setString('$key_${SharedPreferencesKeys.text}', value.text);
    await sharedPrefs.setBool('$key_${SharedPreferencesKeys.isDone}', value.isDone);
    await sharedPrefs.setInt('$key_${SharedPreferencesKeys.duration}', value.duration.microseconds);
  }

  Future<ItemModel> read(String key) async {
    final sharedPrefs = await preferences;
    final title = await sharedPrefs.getString('$key_${SharedPreferencesKeys.title}');
    final text = await sharedPrefs.getString('$key_${SharedPreferencesKeys.text}');
    final isDone = await sharedPrefs.getBool('$key_${SharedPreferencesKeys.isDone}');
    final microseconds = await sharedPrefs.getInt('$key_${SharedPreferencesKeys.duration}');
    return ItemModel(
      title: title,
      text: text,
      isDone: isDone,
      duration: Duration(microseconds: microseconds),
    );
  }

  Future<void> delete(String key) async {
    final sharedPrefs = await preferences;
    await sharedPrefs.remove('$key_${SharedPreferencesKeys.title}');
    await sharedPrefs.remove('$key_${SharedPreferencesKeys.text}');
    await sharedPrefs.remove('$key_${SharedPreferencesKeys.isDone}');
    await sharedPrefs.remove('$key_${SharedPreferencesKeys.duration}');
  }
}

Upvotes: 0

Related Questions