Flutter code generator for generating easy-to-use shared_preferences.
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()),
),
],
),
),
),
);
}
}