flutter_clean_storage

A type-safe, clean architecture storage solution for Flutter applications that supports both secure and non-secure storage with built-in parsers for common types.


License
MIT

Documentation

flutter_clean_storage

A robust, type-safe storage solution for Flutter applications built with clean architecture principles. This package provides a seamless way to handle both secure and non-secure storage needs with built-in support for various data types, JSON serialization, and list storage.

pub package likes popularity Flutter Tests

Features

  • 🔒 Secure and non-secure storage support
  • 🎯 Type-safe storage operations
  • 🧩 Built-in parsers for common types
  • 📦 JSON serialization support
  • 📝 List storage support
  • 🏗️ Clean architecture approach
  • 🔄 Easy-to-use extensions
  • 📱 Cross-platform support

Installation

Add this to your package's pubspec.yaml file:

dependencies:
  flutter_clean_storage: ^0.0.1

Usage

Basic Usage

// Initialize the storage service
await CleanStorageService.instance.initialize();

// Create storage items
final counterStorage = 'counter'.asIntStorage();
final nameStorage = 'username'.asStorage();
final isDarkMode = 'darkMode'.asBoolStorage();

// Store values
await counterStorage.set(42);
await nameStorage.set('John Doe');
await isDarkMode.set(true);

// Retrieve values
final count = await counterStorage.get();
final name = await nameStorage.get();
final darkMode = await isDarkMode.get();

// Delete values
await counterStorage.delete();

Secure Storage

// Create secure storage items
final tokenStorage = 'auth_token'.asStorage(isSecure: true);
final pinCodeStorage = 'pin_code'.asStorage(isSecure: true);

// Store sensitive data securely
await tokenStorage.set('your-secret-token');
await pinCodeStorage.set('1234');

Custom Types

class User {
  final String name;
  final int age;

  User({required this.name, required this.age});

  factory User.fromJson(Map<String, dynamic> json) => User(
        name: json['name'] as String,
        age: json['age'] as int,
      );

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

// Create a storage item for User
final userStorage = StorageItem<User>(
  key: 'current_user',
  defaultValue: User(name: '', age: 0),
  parser: StorageParsers.json(
    fromJson: User.fromJson,
    toJson: (user) => user.toJson(),
  ),
);

// Store user
await userStorage.set(User(name: 'John', age: 30));

// Retrieve user
final user = await userStorage.get();

List Storage

// Store list of strings
final favoriteColors = StorageItem<List<String>>(
  key: 'favorite_colors',
  defaultValue: const [],
  parser: StorageParsers.list(StorageParsers.string),
);

await favoriteColors.set(['red', 'blue', 'green']);

Extensions

// Create storage items using extensions
final counter = 'counter'.asIntStorage(defaultValue: 0);
final username = 'username'.asStorage(defaultValue: '');
final lastUpdate = 'lastUpdate'.asDateTimeStorage();

// Make any storage item secure
final secureToken = 'token'.asStorage().secure();

Advanced Usage

Update with Callback

final counterStorage = 'counter'.asIntStorage();

// Increment counter
await counterStorage.update((current) => current + 1);

Clearing Storage

// Clear non-secure storage
await CleanStorageService.instance.clearAll();

// Clear secure storage
await CleanStorageService.instance.clearAllSecure();

// Clear everything
await CleanStorageService.instance.clearEverything();

Static Storage Pattern

You can create a centralized storage management class using static members:

/// Application-wide storage management
class AppStorage {
  // Authentication & User Data
  static final authToken = StorageItem<String>(
    key: 'auth_token',
    defaultValue: '',
    parser: StorageParsers.string,
    isSecure: true,
  );

  static final currentUser = StorageItem<User?>(
    key: 'current_user',
    defaultValue: null,
    parser: StorageParsers.json<User?>(
      fromJson: (json) => json.isEmpty ? null : User.fromJson(json),
      toJson: (user) => user?.toJson() ?? {},
    ),
  );

  // App Settings
  static final themeMode = StorageItem<String>(
    key: 'theme_mode',
    defaultValue: 'system',
    parser: StorageParsers.string,
  );

  static final language = StorageItem<String>(
    key: 'language',
    defaultValue: 'en',
    parser: StorageParsers.string,
  );

  // Helper Methods
  static Future<void> initialize() async {
    await CleanStorageService.instance.initialize();
  }

  static Future<bool> isAuthenticated() async {
    final token = await authToken.get();
    final user = await currentUser.get();
    return token.isNotEmpty && user != null;
  }

  static Future<void> saveSession({
    required String token,
    required User user,
  }) async {
    await Future.wait([
      authToken.set(token),
      currentUser.set(user),
    ]);
  }

  static Future<void> clearSession() async {
    await Future.wait([
      authToken.delete(),
      currentUser.delete(),
    ]);
  }
}

Usage example:

// Initialize storage
await AppStorage.initialize();

// Check authentication
final isAuthenticated = await AppStorage.isAuthenticated();

// Save user session
await AppStorage.saveSession(
  token: 'your-auth-token',
  user: User(name: 'John', age: 30),
);

// Access individual storage items
final theme = await AppStorage.themeMode.get();
final language = await AppStorage.language.get();

// Clear session
await AppStorage.clearSession();

This pattern provides a clean and organized way to manage application-wide storage with proper separation of concerns.

Platform Support

Android iOS MacOS Web Linux Windows

Maintainers

Contributing

Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.

  1. Fork the Project
  2. Create your Feature Branch (git checkout -b feature/AmazingFeature)
  3. Commit your Changes (git commit -m 'Add some AmazingFeature')
  4. Push to the Branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

Please make sure to update tests as appropriate.

License

This project is licensed under the MIT License - see the LICENSE file for details.