diff --git a/packages/rocket_cache/lib/rocket_cache.dart b/packages/rocket_cache/lib/rocket_cache.dart new file mode 100644 index 0000000..21b3096 --- /dev/null +++ b/packages/rocket_cache/lib/rocket_cache.dart @@ -0,0 +1,3 @@ +library rocket_cache; + +export 'src/rocket_cache_base.dart'; diff --git a/packages/rocket_cache/lib/src/rocket_cache_base.dart b/packages/rocket_cache/lib/src/rocket_cache_base.dart new file mode 100644 index 0000000..c94e6bd --- /dev/null +++ b/packages/rocket_cache/lib/src/rocket_cache_base.dart @@ -0,0 +1,50 @@ +import 'dart:convert'; +import 'package:shared_preferences/shared_preferences.dart'; + +class RocketCache { + static SharedPreferences? _prefs; + + static Future init() async { + _prefs = await SharedPreferences.getInstance(); + } + + /// Save data to cache + static Future save(String key, dynamic data) async { + if (_prefs == null) await init(); + String encodedData = json.encode({ + 'data': data, + 'timestamp': DateTime.now().millisecondsSinceEpoch, + }); + await _prefs!.setString(key, encodedData); + } + + /// Load data from cache + static Future load(String key, {Duration? expiration}) async { + if (_prefs == null) await init(); + String? encodedData = _prefs!.getString(key); + if (encodedData == null) return null; + + Map decoded = json.decode(encodedData); + if (expiration != null) { + DateTime timestamp = + DateTime.fromMillisecondsSinceEpoch(decoded['timestamp']); + if (DateTime.now().difference(timestamp) > expiration) { + await delete(key); + return null; + } + } + return decoded['data']; + } + + /// Delete data from cache + static Future delete(String key) async { + if (_prefs == null) await init(); + await _prefs!.remove(key); + } + + /// Clear all cache + static Future clear() async { + if (_prefs == null) await init(); + await _prefs!.clear(); + } +} diff --git a/packages/rocket_cache/pubspec.yaml b/packages/rocket_cache/pubspec.yaml new file mode 100644 index 0000000..fd84cdd --- /dev/null +++ b/packages/rocket_cache/pubspec.yaml @@ -0,0 +1,20 @@ +name: rocket_cache +description: A persistence and caching layer for the Rocket package. +version: 0.0.1 +repository: https://github.com/JahezAcademy/flutter_rocket/tree/dev/packages/rocket_cache +homepage: https://github.com/JahezAcademy/flutter_rocket +publish_to: none + +environment: + sdk: '>=3.0.0 <4.0.0' + flutter: ">=1.17.0" + +dependencies: + flutter: + sdk: flutter + shared_preferences: ^2.2.0 + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^3.0.2 diff --git a/packages/rocket_cache/test/rocket_cache_test.dart b/packages/rocket_cache/test/rocket_cache_test.dart new file mode 100644 index 0000000..889ff3e --- /dev/null +++ b/packages/rocket_cache/test/rocket_cache_test.dart @@ -0,0 +1,74 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:rocket_cache/rocket_cache.dart'; +import 'dart:convert'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + setUp(() async { + SharedPreferences.setMockInitialValues({}); + await RocketCache.init(); + }); + + group('RocketCache Tests', () { + test('Save and Load data', () async { + const key = 'test_key'; + const data = {'name': 'John', 'age': 30}; + + await RocketCache.save(key, data); + final loadedData = await RocketCache.load(key); + + expect(loadedData, equals(data)); + }); + + test('Load non-existent data returns null', () async { + final loadedData = await RocketCache.load('non_existent'); + expect(loadedData, isNull); + }); + + test('Data expiration', () async { + const key = 'expire_key'; + const data = 'some_data'; + + // Save data + await RocketCache.save(key, data); + + // Load with long expiration + final validData = + await RocketCache.load(key, expiration: const Duration(hours: 1)); + expect(validData, equals(data)); + + // Manually modify the timestamp in SharedPreferences to simulate expiration + final prefs = await SharedPreferences.getInstance(); + final encoded = prefs.getString(key)!; + final decoded = json.decode(encoded); + + // Set timestamp to 2 hours ago + decoded['timestamp'] = DateTime.now() + .subtract(const Duration(hours: 2)) + .millisecondsSinceEpoch; + await prefs.setString(key, json.encode(decoded)); + + // Load with 1 hour expiration - should be expired now + final expiredData = + await RocketCache.load(key, expiration: const Duration(hours: 1)); + expect(expiredData, isNull); + + // Check if it was deleted + expect(prefs.getString(key), isNull); + }); + + test('Delete and Clear', () async { + await RocketCache.save('key1', 'data1'); + await RocketCache.save('key2', 'data2'); + + await RocketCache.delete('key1'); + expect(await RocketCache.load('key1'), isNull); + expect(await RocketCache.load('key2'), isNotNull); + + await RocketCache.clear(); + expect(await RocketCache.load('key2'), isNull); + }); + }); +}