Flutter code generator for generating easy-to-use shared_preferences.

Pub Package

Setup

Add easy_prefs and shared_preferences to dependencies, easy_prefs_gen and build_runner to dev_dependencies. Note: Add provider as well if you're going to use PrefsAnnotation with providerExtensionMethods set to true.

dependencies:
 easy_prefs: [version]
 shared_preferences: ^2.0.11

dev_dependencies:
 build_runner: [version]
 easy_prefs_gen: [version]

in your main.dart file

// IMPORT THESE TWO PACKAGES
import 'package:easy_prefs/easy_prefs.dart';
import 'package:shared_preferences/shared_preferences.dart';

Future<void> main() async {
  // ADD THESE TWO LINES
  WidgetsFlutterBinding.ensureInitialized(); 
  await EasyPrefs.initialize(await SharedPreferences.getInstance());

  // ..

  runApp(const MyApp());
}

Running the code generator

Once you have added the annotations to your code you then need to run the code generator to generate the missing .g.dart generated dart files.

	dart run build_runner build
	
	// or watch
	dart run build_runner watch

Example

Given a dart file example.dart with an Settings class annotated with `PrefsAnnotation`:


import 'package:easy_prefs/easy_prefs.dart';
import 'package:flutter/material.dart'; // or cupertiono, this is required if [changeProvider] is set to true
import 'package:provider/provider.dart'; // this is required if [providerExtensionMethods] is set to true

part 'example.g.dart';

@PrefsAnnotation(
 {  
	 "username": "",
	 "notification": true,
	 "notificationSound": true,
	 "exchangeRate": 1.1,
	 "language": LanguageCodes.kmr,
	 "likeCount": 0,
	 "favs": PrefsStringList(["asf", "afsaf"]),
	 "favs2": ["asf", "afsaf"],
 },
 changeNotifier: true,
 onlyModifier: true,
 providerExtensionMethods: true,
 toggleMethodForBoolValues: true,
)
class Settings extends _$Settings {}

Building creates the corresponding part example.g.dart:

// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'example.dart';

// **************************************************************************
// PrefsGenerator
// **************************************************************************

class _PrefKeysForSettings {
  const _PrefKeysForSettings();
  final String username = 'username';
  final String notification = 'notification';
  final String notificationSound = 'notificationSound';
  final String exchangeRate = 'exchangeRate';
  final String language = 'language';
  final String likeCount = 'likeCount';
  final String favs = 'favs';
  final String favs2 = 'favs2';
}

class _$Settings extends IEasyPrefs with ChangeNotifier {
  final _helper = SharedPreferencesHelper();
  final _keys = const _PrefKeysForSettings();

  /// if [silent] is true, value changes won't be notified.
  _$Settings({bool silent = false}) {
    if (silent) return;
    _helper.onNotify = onValueChanged;
  }

  @override
  void onValueChanged(String key) {
    notifyListeners();
  }

  String? _$username;
  String get username => _$username ?? _helper.getString(_keys.username, '');
  set username(String val) => _helper.setString(_keys.username, val, (_) => _$username = val);

  bool? _$notification;
  bool get notification => _$notification ?? _helper.getBool(_keys.notification, true);
  set notification(bool val) => _helper.setBool(_keys.notification, val, (_) => _$notification = val);
  bool toggleNotification() => _helper.toggleBool(_keys.notification, true, (val) => _$notification = val);

  bool? _$notificationSound;
  bool get notificationSound => _$notificationSound ?? _helper.getBool(_keys.notificationSound, true);
  set notificationSound(bool val) => _helper.setBool(_keys.notificationSound, val, (_) => _$notificationSound = val);
  bool toggleNotificationSound() => _helper.toggleBool(_keys.notificationSound, true, (val) => _$notificationSound = val);

  double? _$exchangeRate;
  double get exchangeRate => _$exchangeRate ?? _helper.getDouble(_keys.exchangeRate, 1.1);
  set exchangeRate(double val) => _helper.setDouble(_keys.exchangeRate, val, (_) => _$exchangeRate = val);

  LanguageCodes? _$language;
  LanguageCodes get language => _$language ?? _helper.getEnum(_keys.language, LanguageCodes.values, LanguageCodes.kmr);
  set language(LanguageCodes val) => _helper.setInt(_keys.language, val.index, (_) => _$language = val);

  int? _$likeCount;
  int get likeCount => _$likeCount ?? _helper.getInt(_keys.likeCount, 0);
  set likeCount(int val) => _helper.setInt(_keys.likeCount, val, (_) => _$likeCount = val);

  NotifiableStringList? _$favs;
  NotifiableStringList get favs => _$favs ?? _helper.getStringList(_keys.favs, ['asf', 'afsaf']);
  set favs(NotifiableStringList val) => _helper.setStringList(_keys.favs, val, (_) => _$favs = val);

  NotifiableStringList? _$favs2;
  NotifiableStringList get favs2 => _$favs2 ?? _helper.getStringList(_keys.favs2, ['asf', 'afsaf']);
  set favs2(NotifiableStringList val) => _helper.setStringList(_keys.favs2, val, (_) => _$favs2 = val);

  @override
  void initializeAll() {
    final tmp = _helper.onNotify;
    _helper.onNotify = null;

    username = username;
    notification = notification;
    notificationSound = notificationSound;
    exchangeRate = exchangeRate;
    language = language;
    likeCount = likeCount;
    favs = favs;
    favs2 = favs2;

    _helper.onNotify = tmp;
    _helper.onNotify?.call("");
  }

  @override
  bool isTouched() {
    return _helper.hasKey(_keys.username) ||
        _helper.hasKey(_keys.notification) ||
        _helper.hasKey(_keys.notificationSound) ||
        _helper.hasKey(_keys.exchangeRate) ||
        _helper.hasKey(_keys.language) ||
        _helper.hasKey(_keys.likeCount) ||
        _helper.hasKey(_keys.favs) ||
        _helper.hasKey(_keys.favs2);
  }

  @override
  String toString() {
    return '''
{
  "username" : "$username",
  "notification" : $notification,
  "notificationSound" : $notificationSound,
  "exchangeRate" : $exchangeRate,
  "language" : $language,
  "likeCount" : $likeCount,
  "favs" : [
      ${favs.map((e) => '"$e"').join(",\n      ")}
    ],
  "favs2" : [
      ${favs2.map((e) => '"$e"').join(",\n      ")}
    ]
}
''';
  }
}

extension SettingsProviderExtensionMethodsOnBuildContext on BuildContext {
  Settings readSettings() => read<Settings>();
  Settings watchSettings() => watch<Settings>();
  R selectSettings<R>(R Function(Settings s) selector) => select(selector);
}

Consuming the class main.dart (Hier I used provider for state management)

import 'package:easy_prefs/easy_prefs.dart';
import 'package:easy_prefs_example/settings.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();  // IMPORTANT
  await EasyPrefs.initialize(await SharedPreferences.getInstance());  // IMPORTANT
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'EasyPrefs Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: ChangeNotifierProvider(
        create: (_) => Settings(),
        builder: (_, __) {
          return const MyHomePage();
        },
      ),
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final settings = context.watchSettings();
    final lastValInFavList = int.parse(settings.favs.isNotEmpty ? settings.favs.last : "0");
    return Scaffold(
      appBar: AppBar(
        title: const Text("EasyPrefs Demo"),
      ),
      body: Padding(
        padding: const EdgeInsets.all(8.0),
        child: SingleChildScrollView(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: <Widget>[
              CheckboxListTile(
                value: settings.notification,
                title: const Text("Enable notification"),
                onChanged: (t) => settings.notification = t!,
              ),
              CheckboxListTile(
                value: settings.notificationSound,
                title: const Text("Enable notification sound"),
                onChanged: (t) => settings.notificationSound = t!,
              ),
              const Divider(height: 1),
              ListTile(
                title: const Text("Language"),
                trailing: DropdownButton(
                  value: settings.language,
                  items: LanguageCodes.values
                      .map((e) => DropdownMenuItem(
                            child: Text(e.name, textScaler: TextScaler.linear(1.2)),
                            value: e,
                          ))
                      .toList(),
                  onChanged: (LanguageCodes? lang) {
                    if (lang != null) {
                      settings.language = lang;
                    }
                  },
                ),
              ),
              const Divider(height: 1),
              Row(
                children: [
                  const Padding(
                    padding: EdgeInsets.all(16.0),
                    child: Text("View Count: ", textScaler: TextScaler.linear(1.2)),
                  ),
                  const Spacer(),
                  IconButton(onPressed: () => settings.likeCount--, icon: const Icon(Icons.remove)),
                  Text(settings.likeCount.toString(), textScaler: TextScaler.linear(1.2)),
                  IconButton(onPressed: () => settings.likeCount++, icon: const Icon(Icons.add)),
                ],
              ),
              const Divider(height: 1),
              Row(
                children: [
                  const Padding(
                    padding: EdgeInsets.all(16.0),
                    child: Text("Fav Items: ", textScaler: TextScaler.linear(1.2)),
                  ),
                  const Spacer(),
                  ElevatedButton(onPressed: () => settings.favs.removeLast(), child: const Icon(Icons.remove)),
                  const SizedBox(width: 5),
                  ElevatedButton(onPressed: () => settings.favs.add("${lastValInFavList + 1}"), child: const Icon(Icons.add)),
                ],
              ),
              const Divider(height: 20),
              const Padding(
                padding: EdgeInsets.fromLTRB(20, 10, 20, 0),
                child: Text("settings.toString() :", textScaler: TextScaler.linear(1.1)),
              ),
              Padding(
                padding: const EdgeInsets.fromLTRB(20, 5, 20, 10),
                child: Text(settings.toString()),
              ),
            ],
          ),
        ),
      ),
    );
  }
}


PrefsAnnotation

Parameters

PrefsStringList