Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions packages/rocket_cache/lib/rocket_cache.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
library rocket_cache;

export 'src/rocket_cache_base.dart';
50 changes: 50 additions & 0 deletions packages/rocket_cache/lib/src/rocket_cache_base.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import 'dart:convert';
import 'package:shared_preferences/shared_preferences.dart';

class RocketCache {
static SharedPreferences? _prefs;

static Future<void> init() async {
_prefs = await SharedPreferences.getInstance();
}

/// Save data to cache
static Future<void> 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<dynamic> load(String key, {Duration? expiration}) async {
if (_prefs == null) await init();
String? encodedData = _prefs!.getString(key);
if (encodedData == null) return null;

Map<String, dynamic> 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<void> delete(String key) async {
if (_prefs == null) await init();
await _prefs!.remove(key);
}

/// Clear all cache
static Future<void> clear() async {
if (_prefs == null) await init();
await _prefs!.clear();
}
}
20 changes: 20 additions & 0 deletions packages/rocket_cache/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -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
74 changes: 74 additions & 0 deletions packages/rocket_cache/test/rocket_cache_test.dart
Original file line number Diff line number Diff line change
@@ -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);
});
});
}