control_config 1.4.0-beta.2 copy "control_config: ^1.4.0-beta.2" to clipboard
control_config: ^1.4.0-beta.2 copied to clipboard

Wrapper around shared_preferences

control_config #

control_config is a control_core module that provides a robust and reactive layer over shared_preferences. It simplifies managing user preferences and configuration settings by offering type-safe access and automatic change notifications.

This library is ideal for:

  • Persisting user settings (e.g., dark mode, language, custom preferences).
  • Storing application configuration flags.
  • Providing reactive access to preference changes throughout your app.

Features #

  • Seamless Integration: Designed to work effortlessly with control_core's dependency injection system.
  • Type-Safe Preferences: Set and get bool, String, int, double, and even dynamic (JSON) values safely.
  • Reactive Preference Models: PrefModel allows you to observe changes to individual preference keys.
  • Simplified Access: PrefsProvider mixin for easy access to ControlPrefs from any class.
  • Modular Setup: ConfigModule for integrating preferences into your application's ControlFactory initialization.

Installation #

Add control_config to your pubspec.yaml file:

dependencies:
  control_config: ^2.0.0

Setup #

Integrate ConfigModule into your Control.initControl() call. This is typically done in your main() function.

import 'package:control_core/core.dart';
import 'package:control_config/config.dart';
import 'package:flutter/widgets.dart'; // Required for binding initialization.

void main() async {
  // Required by shared_preferences before it can be used.
  WidgetsFlutterBinding.ensureInitialized(); 

  Control.initControl(
    modules: [
      ConfigModule(), // This will automatically initialize SharedPreferences
    ],
  );
  
  // onReady ensures that all module initializations are complete.
  await Control.factory.onReady();
  print('Control System and Preferences are ready!');
  
  // Example of using PrefsProvider after setup
  final settings = UserSettings();
  settings.username = 'Alex';
  print('Username from settings: ${settings.username}');
}

Standalone Setup #

You can also initialize control_config without the full Control.initControl ceremony. This is useful for smaller apps or tests.

import 'package:control_config/config.dart';
import 'package:control_core/core.dart';
import 'package:flutter/widgets.dart';

void main() async {
  // Required by shared_preferences before it can be used.
  WidgetsFlutterBinding.ensureInitialized(); 
  
  // This initializes ControlFactory with just the ConfigModule.
  await ConfigModule.standalone();

  // onReady ensures that the module is fully initialized.
  await Control.factory.onReady();
  print('Preferences are ready for standalone use!');

  // Now you can use PrefsProvider
  final prefs = PrefsProvider.instance;
  prefs.setBool('is_first_launch', false);
  print('Is first launch: ${prefs.getBool('is_first_launch')}');
}

Usage #

1. Accessing Preferences with PrefsProvider #

Mix PrefsProvider into your classes for convenient access to ControlPrefs. This is useful for business logic classes that need to read or write multiple preference values.

import 'package:control_config/config.dart';
import 'package:control_core/core.dart';

class UserSettings with PrefsProvider {
  // Directly access preferences via the 'prefs' getter.
  String get username => prefs.get('username', defaultValue: 'Guest')!;
  set username(String value) => prefs.set('username', value);

  bool get darkMode => prefs.getBool('dark_mode', defaultValue: false);
  set darkMode(bool value) => prefs.setBool('dark_mode', value);
}

void demonstrateSettings() {
  final settings = UserSettings();

  print('Initial dark mode: ${settings.darkMode}');
  settings.darkMode = true;
  print('Updated dark mode: ${settings.darkMode}');
}

2. Reactive Preferences with PrefModel #

PrefModel creates an observable wrapper around a single preference key. It extends ChangeNotifier, so you can listen for changes, making it perfect for reactive business logic.

import 'package:control_config/config.dart';
import 'package:control_core/core.dart';

// Create PrefModel instances for specific preference keys.
final darkModePref = PrefModel.boolean('dark_mode', defaultValue: false);

final sub = darkModePref.subscribe((value) => print('Dark mode enabled: $value'));

3. Storing and Retrieving Custom Data (JSON) #

You can store and retrieve complex objects by providing get and set converter functions to PrefModel.data.

import 'package:control_config/config.dart';

class AppUser {
  final String id;
  final String name;

  AppUser({required this.id, required this.name});

  Map<String, dynamic> toJson() => {'id': id, 'name': name};

  factory AppUser.fromJson(Map<String, dynamic> json) => AppUser(
        id: json['id'] as String,
        name: json['name'] as String,
      );
}

// Create a reactive PrefModel for the AppUser object.
final currentUserPref = PrefModel.data<AppUser>(
  'current_user',
  (json) => AppUser.fromJson(json), // Getter: from JSON to AppUser
  (user) => user?.toJson(), // Setter: from AppUser to JSON
);

void manageUserSession() {
  // Save a user. This automatically converts to JSON and saves.
  final user = AppUser(id: '123', name: 'Alex');
  currentUserPref.value = user;
  
  // Retrieve the user. This automatically reads the JSON and converts it back.
  final savedUser = currentUserPref.value;
  print('Saved user: ${savedUser?.name}'); // Prints: "Saved user: Alex"
}