Skip to content

Commit 5d418bd

Browse files
authored
Merge pull request #1 from Hamdal/feat/syncache-flutter
feat: add syncache_flutter package with Flutter integration
2 parents 5003a67 + 255cbf2 commit 5d418bd

153 files changed

Lines changed: 10289 additions & 2 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

melos.yaml

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,36 @@ scripts:
3535
concurrency: 1
3636
packageFilters:
3737
dirExists: test
38-
description: Run tests for all packages
38+
flutter: false
39+
description: Run tests for Dart packages
40+
41+
test:flutter:
42+
run: flutter test
43+
exec:
44+
concurrency: 1
45+
packageFilters:
46+
dirExists: test
47+
flutter: true
48+
description: Run tests for Flutter packages
49+
50+
test:all:
51+
run: melos run test && melos run test:flutter
52+
description: Run tests for all packages (Dart and Flutter)
3953

4054
test:coverage:
4155
run: dart test --coverage=coverage
4256
exec:
4357
concurrency: 1
4458
packageFilters:
4559
dirExists: test
46-
description: Run tests with coverage for all packages
60+
flutter: false
61+
description: Run tests with coverage for Dart packages
62+
63+
test:flutter:coverage:
64+
run: flutter test --coverage
65+
exec:
66+
concurrency: 1
67+
packageFilters:
68+
dirExists: test
69+
flutter: true
70+
description: Run tests with coverage for Flutter packages
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"connectivity_plus","path":"/home/devayo/.pub-cache/hosted/pub.dev/connectivity_plus-7.0.0/","native_build":true,"dependencies":[],"dev_dependency":false}],"android":[{"name":"connectivity_plus","path":"/home/devayo/.pub-cache/hosted/pub.dev/connectivity_plus-7.0.0/","native_build":true,"dependencies":[],"dev_dependency":false}],"macos":[{"name":"connectivity_plus","path":"/home/devayo/.pub-cache/hosted/pub.dev/connectivity_plus-7.0.0/","native_build":true,"dependencies":[],"dev_dependency":false}],"linux":[{"name":"connectivity_plus","path":"/home/devayo/.pub-cache/hosted/pub.dev/connectivity_plus-7.0.0/","native_build":false,"dependencies":[],"dev_dependency":false}],"windows":[{"name":"connectivity_plus","path":"/home/devayo/.pub-cache/hosted/pub.dev/connectivity_plus-7.0.0/","native_build":true,"dependencies":[],"dev_dependency":false}],"web":[{"name":"connectivity_plus","path":"/home/devayo/.pub-cache/hosted/pub.dev/connectivity_plus-7.0.0/","dependencies":[],"dev_dependency":false}]},"dependencyGraph":[{"name":"connectivity_plus","dependencies":[]}],"date_created":"2026-03-14 13:27:00.475588","version":"3.41.2","swift_package_manager_enabled":{"ios":false,"macos":false}}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Changelog
2+
3+
All notable changes to this project will be documented in this file.
4+
5+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7+
8+
## [0.1.0] - 2026-03-14
9+
10+
### Added
11+
12+
- `SyncacheScope` - InheritedWidget for dependency injection of cache instances
13+
- `MultiSyncacheScope` - Helper for providing multiple cache types without deep nesting
14+
- `CacheBuilder` - StreamBuilder-style widget for reactive cache data display
15+
- `CacheConsumer` - Consumer pattern widget with separate listener callback
16+
- `SyncacheLifecycleObserver` - App lifecycle and reconnect handling
17+
- Automatic refetch on app resume (configurable minimum pause duration)
18+
- Automatic refetch on connectivity restoration
19+
- `FlutterNetwork` - Connectivity detection using `connectivity_plus`
20+
- Debounced connectivity change events
21+
- Concurrent initialization handled via Completer pattern
22+
- `SyncacheValueListenable` - ValueListenable wrapper for use with ValueListenableBuilder
23+
- `LifecycleConfig` - Configuration class for lifecycle behavior customization

packages/syncache_flutter/LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 Hameed Abdullateef
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.
Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
# syncache_flutter
2+
3+
Flutter integration for [Syncache](https://pub.dev/packages/syncache) - lifecycle management, widgets, and connectivity detection.
4+
5+
## Installation
6+
7+
```yaml
8+
dependencies:
9+
syncache: ^0.1.0
10+
syncache_flutter: ^0.1.0
11+
```
12+
13+
## Quick Start
14+
15+
### 1. Provide the cache with SyncacheScope
16+
17+
Wrap your app (or a subtree) with `SyncacheScope` to provide cache instances to descendants:
18+
19+
```dart
20+
import 'package:syncache/syncache.dart';
21+
import 'package:syncache_flutter/syncache_flutter.dart';
22+
23+
void main() async {
24+
WidgetsFlutterBinding.ensureInitialized();
25+
26+
// Initialize connectivity detection
27+
final network = FlutterNetwork();
28+
await network.initialize();
29+
30+
// Create your cache
31+
final userCache = Syncache<User>(
32+
store: MemoryStore<User>(),
33+
network: network,
34+
);
35+
36+
runApp(
37+
SyncacheScope<User>(
38+
cache: userCache,
39+
network: network,
40+
child: MyApp(),
41+
),
42+
);
43+
}
44+
```
45+
46+
### 2. Display cached data with CacheBuilder
47+
48+
Use `CacheBuilder` to reactively display cached data:
49+
50+
```dart
51+
class UserProfile extends StatelessWidget {
52+
final String userId;
53+
54+
const UserProfile({required this.userId});
55+
56+
@override
57+
Widget build(BuildContext context) {
58+
return CacheBuilder<User>(
59+
cacheKey: 'user:$userId',
60+
fetch: (request) => api.getUser(userId),
61+
builder: (context, snapshot) {
62+
if (snapshot.hasError) {
63+
return ErrorWidget(snapshot.error!);
64+
}
65+
if (!snapshot.hasData) {
66+
return const CircularProgressIndicator();
67+
}
68+
return Text('Hello, ${snapshot.data!.name}');
69+
},
70+
);
71+
}
72+
}
73+
```
74+
75+
## Features
76+
77+
### SyncacheScope
78+
79+
Provides cache instances to the widget subtree via `InheritedWidget`:
80+
81+
```dart
82+
// Access cache anywhere in the subtree
83+
final cache = SyncacheScope.of<User>(context);
84+
85+
// Access the lifecycle observer
86+
final observer = SyncacheScope.observerOf<User>(context);
87+
```
88+
89+
### MultiSyncacheScope
90+
91+
Provide multiple cache types without deep nesting:
92+
93+
```dart
94+
MultiSyncacheScope(
95+
network: flutterNetwork,
96+
configs: [
97+
SyncacheScopeConfig<User>(userCache),
98+
SyncacheScopeConfig<Post>(postCache),
99+
SyncacheScopeConfig<Settings>(settingsCache),
100+
],
101+
child: MyApp(),
102+
)
103+
```
104+
105+
### CacheBuilder
106+
107+
StreamBuilder-style widget for reactive cache display:
108+
109+
```dart
110+
CacheBuilder<User>(
111+
cacheKey: 'user:123',
112+
fetch: fetchUser,
113+
policy: Policy.staleWhileRefresh,
114+
ttl: Duration(minutes: 5),
115+
initialData: cachedUser,
116+
buildWhen: (previous, current) => previous.id != current.id,
117+
builder: (context, snapshot) {
118+
// Build UI based on snapshot state
119+
},
120+
)
121+
```
122+
123+
### CacheConsumer
124+
125+
Consumer pattern with separate listener for side effects:
126+
127+
```dart
128+
CacheConsumer<User>(
129+
cacheKey: 'user:123',
130+
fetch: fetchUser,
131+
listener: (context, data) {
132+
// Handle side effects (e.g., show snackbar, navigate)
133+
ScaffoldMessenger.of(context).showSnackBar(
134+
SnackBar(content: Text('User updated: ${data.name}')),
135+
);
136+
},
137+
builder: (context, snapshot) {
138+
// Build UI
139+
},
140+
)
141+
```
142+
143+
### FlutterNetwork
144+
145+
Connectivity detection using `connectivity_plus`:
146+
147+
```dart
148+
final network = FlutterNetwork(
149+
debounceDuration: Duration(milliseconds: 500),
150+
);
151+
await network.initialize();
152+
153+
// Check current status
154+
print('Online: ${network.isOnline}');
155+
156+
// Listen to connectivity changes
157+
network.onConnectivityChanged.listen((isOnline) {
158+
print('Connectivity changed: $isOnline');
159+
});
160+
```
161+
162+
### Lifecycle Management
163+
164+
Configure automatic refetching on app resume and connectivity restoration:
165+
166+
```dart
167+
SyncacheScope<User>(
168+
cache: userCache,
169+
network: network,
170+
config: LifecycleConfig(
171+
refetchOnResume: true,
172+
refetchOnResumeMinDuration: Duration(minutes: 1),
173+
refetchOnReconnect: true,
174+
onRefetchError: (key, error, stackTrace) {
175+
logger.warning('Failed to refetch $key: $error');
176+
},
177+
),
178+
child: MyApp(),
179+
)
180+
```
181+
182+
### SyncacheValueListenable
183+
184+
Use with `ValueListenableBuilder` for more control:
185+
186+
```dart
187+
final listenable = cache.toValueListenable(
188+
key: 'user:123',
189+
fetch: fetchUser,
190+
);
191+
192+
ValueListenableBuilder<AsyncSnapshot<User>>(
193+
valueListenable: listenable,
194+
builder: (context, snapshot, child) {
195+
// Build UI
196+
},
197+
)
198+
199+
// Trigger manual refresh
200+
await listenable.refresh();
201+
202+
// Don't forget to dispose
203+
listenable.dispose();
204+
```
205+
206+
## API Reference
207+
208+
### Widgets
209+
210+
| Widget | Description |
211+
|--------|-------------|
212+
| `SyncacheScope<T>` | InheritedWidget for cache dependency injection |
213+
| `MultiSyncacheScope` | Provides multiple cache types without nesting |
214+
| `CacheBuilder<T>` | StreamBuilder-style reactive cache display |
215+
| `CacheConsumer<T>` | Consumer pattern with listener callback |
216+
217+
### Classes
218+
219+
| Class | Description |
220+
|-------|-------------|
221+
| `FlutterNetwork` | Connectivity detection with debouncing |
222+
| `SyncacheLifecycleObserver<T>` | App lifecycle and reconnect handling |
223+
| `LifecycleConfig` | Configuration for lifecycle behavior |
224+
| `SyncacheValueListenable<T>` | ValueListenable wrapper for cache streams |
225+
| `WatcherRegistration<T>` | Registration info for lifecycle-based refetching |
226+
227+
## Requirements
228+
229+
- Dart SDK: ^3.0.0
230+
- Flutter: >=3.10.0
231+
- syncache: ^0.1.0
232+
- connectivity_plus: ^7.0.0
233+
234+
## License
235+
236+
MIT License - see [LICENSE](LICENSE) for details.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
include: package:flutter_lints/flutter.yaml
2+
3+
linter:
4+
rules:
5+
- prefer_const_constructors
6+
- prefer_const_declarations
7+
- prefer_final_fields
8+
- prefer_final_locals
9+
- avoid_print
10+
- require_trailing_commas
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Miscellaneous
2+
*.class
3+
*.log
4+
*.pyc
5+
*.swp
6+
.DS_Store
7+
.atom/
8+
.build/
9+
.buildlog/
10+
.history
11+
.svn/
12+
.swiftpm/
13+
migrate_working_dir/
14+
15+
# IntelliJ related
16+
*.iml
17+
*.ipr
18+
*.iws
19+
.idea/
20+
21+
# The .vscode folder contains launch configuration and tasks you configure in
22+
# VS Code which you may wish to be included in version control, so this line
23+
# is commented out by default.
24+
#.vscode/
25+
26+
# Flutter/Dart/Pub related
27+
**/doc/api/
28+
**/ios/Flutter/.last_build_id
29+
.dart_tool/
30+
.flutter-plugins-dependencies
31+
.pub-cache/
32+
.pub/
33+
/build/
34+
/coverage/
35+
36+
# Symbolication related
37+
app.*.symbols
38+
39+
# Obfuscation related
40+
app.*.map.json
41+
42+
# Android Studio will place build artifacts here
43+
/android/app/debug
44+
/android/app/profile
45+
/android/app/release

0 commit comments

Comments
 (0)