Skip to content

Commit aa635b2

Browse files
committed
Release v1.0.0 with docs, error handling, and workflow
Adds comprehensive documentation comments for all public APIs, improves error handling with UnsupportedError for unsupported types, and introduces an automatic publishing workflow to pub.dev via GitHub Actions. Fixes bugs where write(null) incorrectly called clear() instead of remove() in SharedPreferences and EncryptedSharedPreferences. Enhances code organization, type safety, and test coverage for unsupported types and double values.
1 parent 40ef056 commit aa635b2

File tree

12 files changed

+249
-32
lines changed

12 files changed

+249
-32
lines changed

.github/workflows/publish.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
name: Publish to pub.dev
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v[0-9]+.[0-9]+.[0-9]+*'
7+
8+
jobs:
9+
publish:
10+
permissions:
11+
id-token: write # Required for authentication using OIDC
12+
uses: dart-lang/setup-dart/.github/workflows/publish.yml@v1
13+
# with:
14+
# working-directory: path/to/package/within/repository

CHANGELOG.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
---
99

10+
## [1.0.0] - 2025-10-07
11+
12+
### Added
13+
- Automatic publishing workflow to pub.dev via GitHub Actions
14+
- Comprehensive documentation comments for all public APIs
15+
- Better error messages with `UnsupportedError` instead of generic `Exception`
16+
17+
### Changed
18+
- Fixed bug where `write(null)` was calling `clear()` instead of `remove()` in SharedPreferences
19+
- Fixed bug where `write(null)` was calling `clear()` instead of `remove()` in EncryptedSharedPreferences
20+
- Improved code organization and readability
21+
- Enhanced documentation with detailed examples and use cases
22+
- Made storage operations more explicit with better type safety
23+
- Updated all class and method documentation following Dart documentation conventions
24+
25+
### Fixed
26+
- SharedPreferences now properly uses `remove()` for deleting specific keys instead of `clear()`
27+
- EncryptedSharedPreferences now properly uses `remove()` for deleting specific keys instead of `clear()`
28+
29+
---
30+
1031
## [0.1.1] - Documentation update
1132

1233
### Added

lib/mayr_storage.dart

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,43 @@
1+
/// A simple and unified storage solution for Flutter applications.
2+
///
3+
/// This library provides a clean, consistent API for managing different types
4+
/// of persistent storage in Flutter apps:
5+
///
6+
/// - **SharedPreferences** - For simple, non-sensitive data
7+
/// - **EncryptedSharedPreferences** - For sensitive, encrypted data
8+
/// - **GetStorage** - For fast, synchronous key-value storage
9+
///
10+
/// ## Quick Start
11+
///
12+
/// Initialize storage at app startup:
13+
/// ```dart
14+
/// void main() async {
15+
/// WidgetsFlutterBinding.ensureInitialized();
16+
/// await MayrStorage.init();
17+
/// runApp(MyApp());
18+
/// }
19+
/// ```
20+
///
21+
/// Define storage keys:
22+
/// ```dart
23+
/// class Storage {
24+
/// static final userToken = 'USER_TOKEN'.storage<String>();
25+
/// static final authToken = 'AUTH_TOKEN'.secureStorage<String>();
26+
/// static final cache = 'CACHE_DATA'.boxStorage<String>();
27+
/// }
28+
/// ```
29+
///
30+
/// Use storage operations:
31+
/// ```dart
32+
/// // Write
33+
/// await Storage.userToken.write('token123');
34+
///
35+
/// // Read
36+
/// final token = await Storage.userToken.read();
37+
///
38+
/// // Delete
39+
/// await Storage.userToken.delete();
40+
/// ```
41+
library mayr_storage;
42+
143
export './src/mayr_storage.dart';
Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,22 @@
11
part of '../../mayr_storage.dart';
22

3+
/// Abstract interface for preference-based storage implementations.
4+
///
5+
/// Defines the contract for storage backends that persist data asynchronously,
6+
/// such as SharedPreferences and EncryptedSharedPreferences.
37
abstract interface class PreferencesStorage<ValueT> {
4-
/// Delete stored record
8+
/// Deletes the stored value by writing null.
9+
///
10+
/// This is equivalent to calling write(null).
511
Future<void> delete() async => write(null);
612

7-
/// Read stored record
13+
/// Reads the stored value.
14+
///
15+
/// Returns the stored value of type [ValueT], or null if no value exists.
816
Future<ValueT?> read();
917

10-
/// Write record to storage
18+
/// Writes a value to storage.
19+
///
20+
/// If [value] is null, the stored value will be deleted.
1121
Future<void> write(ValueT? value);
1222
}
Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,25 @@
11
part of './../mayr_storage.dart';
22

3+
/// Storage implementation using EncryptedSharedPreferences.
4+
///
5+
/// Provides encrypted, asynchronous storage for sensitive data.
6+
/// Data is encrypted at rest using AES encryption, making it suitable
7+
/// for storing tokens, passwords, and other confidential information.
8+
///
9+
/// Supported types: [String], [int], [double], [bool]
310
class EncryptSharedPreferencesStorage<ValueT>
411
extends PreferencesStorage<ValueT> {
512
final String _preferenceKey;
613

14+
/// Creates an encrypted storage handler for the given key.
715
EncryptSharedPreferencesStorage(this._preferenceKey);
816

917
@override
1018
Future<ValueT?> read() async {
11-
EncryptedSharedPreferences securePref =
19+
final EncryptedSharedPreferences securePref =
1220
EncryptedSharedPreferences.getInstance();
1321

22+
// Type-safe retrieval based on generic type
1423
if (ValueT == bool) {
1524
return securePref.getBool(_preferenceKey) as ValueT?;
1625
} else if (ValueT == String) {
@@ -20,27 +29,32 @@ class EncryptSharedPreferencesStorage<ValueT>
2029
} else if (ValueT == double) {
2130
return securePref.getDouble(_preferenceKey) as ValueT?;
2231
} else {
23-
throw Exception("Unsupported type");
32+
throw UnsupportedError(
33+
'Type $ValueT is not supported. Only String, int, double, and bool are supported.',
34+
);
2435
}
2536
}
2637

2738
@override
2839
Future<void> write(ValueT? value) async {
29-
EncryptedSharedPreferences securePref =
40+
final EncryptedSharedPreferences securePref =
3041
EncryptedSharedPreferences.getInstance();
3142

43+
// Delete the key if value is null
3244
if (value == null) {
33-
securePref.clear();
45+
await securePref.remove(_preferenceKey);
3446
} else if (ValueT == bool) {
35-
securePref.setBool(_preferenceKey, value as bool);
47+
await securePref.setBool(_preferenceKey, value as bool);
3648
} else if (ValueT == String) {
37-
securePref.setString(_preferenceKey, value as String);
49+
await securePref.setString(_preferenceKey, value as String);
3850
} else if (ValueT == int) {
39-
securePref.setInt(_preferenceKey, value as int);
51+
await securePref.setInt(_preferenceKey, value as int);
4052
} else if (ValueT == double) {
41-
securePref.setDouble(_preferenceKey, value as double);
53+
await securePref.setDouble(_preferenceKey, value as double);
4254
} else {
43-
throw Exception("Unsupported type");
55+
throw UnsupportedError(
56+
'Type $ValueT is not supported. Only String, int, double, and bool are supported.',
57+
);
4458
}
4559
}
4660
}
Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,48 @@
11
part of '../mayr_storage.dart';
22

3+
/// Storage implementation using GetStorage.
4+
///
5+
/// Provides fast, synchronous key-value storage with support for complex types.
6+
/// Ideal for caching, frequently accessed data, and scenarios where
7+
/// synchronous access is preferred.
8+
///
9+
/// Unlike SharedPreferences, GetBoxStorage operations are synchronous
10+
/// and support any serializable type.
311
class GetBoxStorage<ValueT> {
412
final String _boxName;
513

14+
/// The underlying GetStorage instance.
615
late final GetStorage _box = GetStorage();
716

17+
/// Creates a GetBox storage handler for the given key.
818
GetBoxStorage(this._boxName);
919

10-
/// Delete stored record
20+
/// Deletes the stored value.
21+
///
22+
/// Removes the key-value pair from storage.
1123
void delete() => _box.remove(_boxName);
1224

13-
/// Listen for updates
25+
/// Listens for changes to the stored value.
26+
///
27+
/// The [handler] callback will be invoked whenever the value
28+
/// associated with this key changes.
29+
///
30+
/// Example:
31+
/// ```dart
32+
/// storage.listen((newValue) {
33+
/// print('Value changed to: $newValue');
34+
/// });
35+
/// ```
1436
void listen(void Function(ValueT newValue) handler) =>
1537
_box.listenKey(_boxName, (newValue) => handler(newValue));
1638

17-
/// Read value from storage
39+
/// Reads the stored value synchronously.
40+
///
41+
/// Returns the stored value of type [ValueT], or null if no value exists.
1842
ValueT? read() => _box.read(_boxName);
1943

20-
/// Write value to storage
44+
/// Writes a value to storage synchronously.
45+
///
46+
/// If [value] is null, the stored value will be deleted.
2147
void write(ValueT? value) => _box.write(_boxName, value);
2248
}
Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,22 @@
11
part of '../mayr_storage.dart';
22

3+
/// Storage implementation using Flutter's SharedPreferences.
4+
///
5+
/// Provides asynchronous access to platform-specific persistent storage
6+
/// for simple data types. Suitable for user preferences and non-sensitive data.
7+
///
8+
/// Supported types: [String], [int], [double], [bool]
39
class SharedPreferencesStorage<ValueT> extends PreferencesStorage<ValueT> {
410
final String _preferenceKey;
511

12+
/// Creates a SharedPreferences storage handler for the given key.
613
SharedPreferencesStorage(this._preferenceKey);
714

815
@override
916
Future<ValueT?> read() async {
10-
SharedPreferences sharedPref = await SharedPreferences.getInstance();
17+
final SharedPreferences sharedPref = await SharedPreferences.getInstance();
1118

19+
// Type-safe retrieval based on generic type
1220
if (ValueT == bool) {
1321
return sharedPref.getBool(_preferenceKey) as ValueT?;
1422
} else if (ValueT == String) {
@@ -18,26 +26,31 @@ class SharedPreferencesStorage<ValueT> extends PreferencesStorage<ValueT> {
1826
} else if (ValueT == double) {
1927
return sharedPref.getDouble(_preferenceKey) as ValueT?;
2028
} else {
21-
throw Exception("Unsupported type");
29+
throw UnsupportedError(
30+
'Type $ValueT is not supported. Only String, int, double, and bool are supported.',
31+
);
2232
}
2333
}
2434

2535
@override
2636
Future<void> write(ValueT? value) async {
27-
SharedPreferences sharedPref = await SharedPreferences.getInstance();
37+
final SharedPreferences sharedPref = await SharedPreferences.getInstance();
2838

39+
// Delete the key if value is null
2940
if (value == null) {
30-
sharedPref.clear();
41+
await sharedPref.remove(_preferenceKey);
3142
} else if (ValueT == bool) {
32-
sharedPref.setBool(_preferenceKey, value as bool);
43+
await sharedPref.setBool(_preferenceKey, value as bool);
3344
} else if (ValueT == String) {
34-
sharedPref.setString(_preferenceKey, value as String);
45+
await sharedPref.setString(_preferenceKey, value as String);
3546
} else if (ValueT == int) {
36-
sharedPref.setInt(_preferenceKey, value as int);
47+
await sharedPref.setInt(_preferenceKey, value as int);
3748
} else if (ValueT == double) {
38-
sharedPref.setDouble(_preferenceKey, value as double);
49+
await sharedPref.setDouble(_preferenceKey, value as double);
3950
} else {
40-
throw Exception("Unsupported type");
51+
throw UnsupportedError(
52+
'Type $ValueT is not supported. Only String, int, double, and bool are supported.',
53+
);
4154
}
4255
}
4356
}

lib/src/extension.dart

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,48 @@
11
part of './mayr_storage.dart';
22

3+
/// Extension on String to provide convenient storage accessors.
4+
///
5+
/// This extension allows any string to be converted into a storage handler
6+
/// by treating the string as a storage key.
37
extension KeyStorageExtensions on String {
4-
/// Get Box Storage using GetStorage internally
8+
/// Creates a GetBox storage handler for the given key.
9+
///
10+
/// Box storage provides synchronous, lightweight key-value storage
11+
/// ideal for caching and frequently accessed data.
12+
///
13+
/// Example:
14+
/// ```dart
15+
/// final storage = 'MY_KEY'.boxStorage<String>();
16+
/// storage.write('value');
17+
/// final value = storage.read();
18+
/// ```
519
GetBoxStorage<ValueT> boxStorage<ValueT>() => GetBoxStorage<ValueT>(this);
620

7-
/// Get Secure Storage using Encrypted Shared Preferences internally
21+
/// Creates a secure storage handler using Encrypted Shared Preferences.
22+
///
23+
/// Secure storage encrypts data at rest, making it suitable for
24+
/// sensitive information like tokens, passwords, and user credentials.
25+
///
26+
/// Example:
27+
/// ```dart
28+
/// final storage = 'AUTH_TOKEN'.secureStorage<String>();
29+
/// await storage.write('secret_token');
30+
/// final token = await storage.read();
31+
/// ```
832
EncryptSharedPreferencesStorage<ValueT> secureStorage<ValueT>() =>
933
EncryptSharedPreferencesStorage<ValueT>(this);
1034

11-
/// Get Shared Preferences Storage
35+
/// Creates a standard Shared Preferences storage handler.
36+
///
37+
/// Standard storage is suitable for non-sensitive configuration data,
38+
/// user preferences, and application settings.
39+
///
40+
/// Example:
41+
/// ```dart
42+
/// final storage = 'USER_THEME'.storage<String>();
43+
/// await storage.write('dark');
44+
/// final theme = await storage.read();
45+
/// ```
1246
SharedPreferencesStorage<ValueT> storage<ValueT>() =>
1347
SharedPreferencesStorage<ValueT>(this);
1448
}

lib/src/mayr_storage.dart

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,27 @@ part 'drivers/abstract/preferences_storage.dart';
88
part './drivers/shared_preferences_storage.dart';
99
part './extension.dart';
1010

11+
/// Main entry point for MayrStorage initialization.
12+
///
13+
/// This class provides centralized initialization for all storage backends
14+
/// used by the package including SharedPreferences, EncryptedSharedPreferences,
15+
/// and GetStorage.
1116
class MayrStorage {
12-
/// Init MayrStorage
13-
static Future init() async {
17+
/// Initializes all storage backends.
18+
///
19+
/// This method must be called before using any storage operations,
20+
/// typically in the main() function after WidgetsFlutterBinding.ensureInitialized().
21+
///
22+
/// Example:
23+
/// ```dart
24+
/// void main() async {
25+
/// WidgetsFlutterBinding.ensureInitialized();
26+
/// await MayrStorage.init();
27+
/// runApp(MyApp());
28+
/// }
29+
/// ```
30+
static Future<void> init() async {
1431
await GetStorage.init();
15-
1632
await EncryptedSharedPreferences.initialize("testkey#1029121@");
1733
}
1834
}

pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: mayr_storage
22
description: >-
33
Simple and unified storage solution for Flutter apps.
44
Easily manage SharedPreferences, EncryptedSharedPreferences, and GetStorage with a clean, consistent API.
5-
version: 0.1.1
5+
version: 1.0.0
66
homepage: https://github.com/YoungMayor/mayr_flutter_storage
77
repository: https://github.com/YoungMayor/mayr_flutter_storage
88
issue_tracker: https://github.com/YoungMayor/mayr_flutter_storage/issues

0 commit comments

Comments
 (0)