saveable 0.1.0 copy "saveable: ^0.1.0" to clipboard
saveable: ^0.1.0 copied to clipboard

Automatic variable-level state persistence.

example/example.dart

// ignore_for_file: avoid_print

import 'package:saveable/saveable.dart';

// =============================================================================
// Example 1: Simple In-Memory Storage (for testing/demos)
// =============================================================================

/// A simple in-memory storage implementation for demonstration.
/// In production, use SharedPreferences, Hive, or similar.
class InMemoryStorage implements Storage {
  final Map<String, dynamic> _data = {};

  @override
  dynamic read(String key) => _data[key];

  @override
  Future<void> write(String key, dynamic value) async {
    _data[key] = value;
  }

  @override
  Future<void> delete(String key) async {
    _data.remove(key);
  }

  @override
  Future<void> clear() async {
    _data.clear();
  }

  @override
  Future<void> close() async {}
}

// =============================================================================
// Example 2: Using Saveable directly
// =============================================================================

void simpleUsageExample() {
  final storage = InMemoryStorage();

  // Simple int counter
  final counter = Saveable<int>(
    key: 'counter',
    storage: storage,
    defaultValue: 0,
  );

  print('Initial counter: ${counter.value}'); // 0

  // Update the value - automatically persists
  counter.value = 42;
  print('After update: ${counter.value}'); // 42

  // Use update() for functional updates
  counter.update((current) => current + 1);
  print('After increment: ${counter.value}'); // 43

  // Clean up
  counter.dispose();
}

// =============================================================================
// Example 3: Complex types with JSON serialization
// =============================================================================

/// Example user model
class User {
  final String id;
  final String name;
  final String email;

  const User({
    required this.id,
    required this.name,
    required this.email,
  });

  factory User.empty() => const User(id: '', name: '', email: '');

  factory User.fromJson(Map<String, dynamic> json) {
    return User(
      id: json['id'] as String,
      name: json['name'] as String,
      email: json['email'] as String,
    );
  }

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

  User copyWith({String? id, String? name, String? email}) {
    return User(
      id: id ?? this.id,
      name: name ?? this.name,
      email: email ?? this.email,
    );
  }

  @override
  String toString() => 'User(id: $id, name: $name, email: $email)';
}

void complexTypeExample() {
  final storage = InMemoryStorage();

  // Complex type with serialization
  final user = Saveable<User>(
    key: 'current_user',
    storage: storage,
    defaultValue: User.empty(),
    fromJson: User.fromJson,
    toJson: (u) => u.toJson(),
  );

  print('Initial user: ${user.value}'); // User(id: , name: , email: )

  // Update with copyWith pattern
  user.update((current) => current.copyWith(
        id: '123',
        name: 'John Doe',
        email: 'john@example.com',
      ));

  print('After update: ${user.value}');
  // User(id: 123, name: John Doe, email: john@example.com)

  // Clean up
  user.dispose();
}

// =============================================================================
// Example 4: Using StateSaver mixin
// =============================================================================

/// Example settings provider using StateSaver mixin
class SettingsProvider with StateSaver {
  late final Saveable<bool> darkMode;
  late final Saveable<String> locale;
  late final Saveable<int> fontSize;
  late final Saveable<User> currentUser;

  final Storage _storage;

  @override
  Storage get storage => _storage;

  @override
  String get storagePrefix => 'settings';

  SettingsProvider(this._storage) {
    // Simple types - no serialization needed
    darkMode = saveable<bool>(
      key: 'dark_mode',
      defaultValue: false,
    );

    locale = saveable<String>(
      key: 'locale',
      defaultValue: 'en',
    );

    fontSize = saveable<int>(
      key: 'font_size',
      defaultValue: 14,
    );

    // Complex type - with serialization
    currentUser = saveable<User>(
      key: 'current_user',
      defaultValue: User.empty(),
      fromJson: User.fromJson,
      toJson: (u) => u.toJson(),
    );
  }

  void dispose() {
    disposeSaveables();
  }
}

void stateSaverExample() {
  final storage = InMemoryStorage();
  final settings = SettingsProvider(storage);

  print('Dark mode: ${settings.darkMode.value}'); // false
  print('Locale: ${settings.locale.value}'); // en

  // Update values
  settings.darkMode.value = true;
  settings.locale.value = 'fr';
  settings.fontSize.value = 16;

  print('Dark mode: ${settings.darkMode.value}'); // true
  print('Locale: ${settings.locale.value}'); // fr
  print('Font size: ${settings.fontSize.value}'); // 16

  // Update complex type
  settings.currentUser.update((user) => user.copyWith(
        id: '456',
        name: 'Jane Doe',
      ));

  print('User: ${settings.currentUser.value}');

  // Clean up all saveables at once
  settings.dispose();
}

// =============================================================================
// Example 5: Using with ValueListenableBuilder (in a widget)
// =============================================================================

/// Example showing how to use Saveable with Flutter widgets.
///
/// ```dart
/// class SettingsScreen extends StatelessWidget {
///   final SettingsProvider settings;
///
///   const SettingsScreen({super.key, required this.settings});
///
///   @override
///   Widget build(BuildContext context) {
///     return Column(
///       children: [
///         // Dark mode toggle
///         ValueListenableBuilder<bool>(
///           valueListenable: settings.darkMode,
///           builder: (context, isDark, child) {
///             return SwitchListTile(
///               title: const Text('Dark Mode'),
///               value: isDark,
///               onChanged: (value) => settings.darkMode.value = value,
///             );
///           },
///         ),
///
///         // Font size slider
///         ValueListenableBuilder<int>(
///           valueListenable: settings.fontSize,
///           builder: (context, size, child) {
///             return Slider(
///               value: size.toDouble(),
///               min: 10,
///               max: 24,
///               onChanged: (value) => settings.fontSize.value = value.toInt(),
///             );
///           },
///         ),
///       ],
///     );
///   }
/// }
/// ```

// =============================================================================
// Main
// =============================================================================

void main() {
  print('=== Simple Usage Example ===');
  simpleUsageExample();

  print('\n=== Complex Type Example ===');
  complexTypeExample();

  print('\n=== StateSaver Mixin Example ===');
  stateSaverExample();

  print('\nAll examples completed successfully!');
}
1
likes
150
points
104
downloads

Publisher

verified publisherspiercer.tech

Weekly Downloads

Automatic variable-level state persistence.

Repository (GitHub)
View/report issues

Topics

#state-management #persistence #storage #hydration

Documentation

API reference

Funding

Consider supporting this project:

github.com

License

MIT (license)

Dependencies

flutter

More

Packages that depend on saveable