andoriyaprashant / andoriyaprashant/OpSo

feat: add offline support using `hive` local database — OpSo currently requires internet connectivity to display program information, showing a blank screen with no cached data when offline

Open
#482 2 comments 0 reactions 0 assignees View on GitHub
Dominant language
Dart
Stars
53
Forks
108
PR merge metrics
No merged PRs in 30d

Description

## 🚀 Problem Statement

OpSo is a **discovery app** — its primary function is providing information about open-source programs. This information (program descriptions, dates, eligibility, etc.) is largely **static content that changes infrequently**. Yet:

- If a student opens OpSo on an airplane or in a low-connectivity area, they see a loading spinner or blank screen
- Program details they were just reading are not available offline
- There is no local caching mechanism anywhere in the codebase
- The app does not function as a reliable reference tool

For a tool meant to help developers prepare for program applications, being unavailable offline is a serious UX gap.

## ✅ Proposed Solution

Use `hive` (lightweight, fast Flutter key-value database) to cache program data locally with a 24-hour TTL.

### 1. Add dependencies to `pubspec.yaml`

````yaml
dependencies:
hive: ^2.2.3
hive_flutter: ^1.1.0
connectivity_plus: ^6.0.3

dev_dependencies:
hive_generator: ^2.0.1
build_runner: ^2.4.9
````

### 2. Create cache service `lib/services/cache_service.dart`

````dart
// lib/services/cache_service.dart
import 'package:hive_flutter/hive_flutter.dart';

class CacheService {
static const _programBox = 'programs_cache';
static const _metaBox = 'cache_meta';
static const cacheTTL = Duration(hours: 24);

static Future init() async {
await Hive.initFlutter();
await Hive.openBox(_programBox);
await Hive.openBox(_metaBox);
}

static Future cachePrograms(String key, List> data) async {
final box = Hive.box(_programBox);
await box.put(key, data);
await Hive.box(_metaBox).put('${key}_timestamp', DateTime.now().toIso8601String());
}

static List>? getCachedPrograms(String key) {
final metaBox = Hive.box(_metaBox);
final timestampStr = metaBox.get('${key}_timestamp') as String?;
if (timestampStr == null) return null;

final timestamp = DateTime.parse(timestampStr);
if (DateTime.now().difference(timestamp) > cacheTTL) return null; // expired

final box = Hive.box(_programBox);
final data = box.get(key);
return data != null ? List>.from(data) : null;
}

static bool isCacheValid(String key) {
return getCachedPrograms(key) != null;
}
}
````

### 3. Create connectivity-aware data provider

````dart
// lib/providers/program_provider.dart
import 'package:connectivity_plus/connectivity_plus.dart';

class ProgramProvider extends ChangeNotifier {
List _programs = [];
bool _isOffline = false;
bool _isLoading = false;

bool get isOffline => _isOffline;

Future loadPrograms() async {
_isLoading = true;
notifyListeners();

final connectivity = await Connectivity().checkConnectivity();
_isOffline = connectivity == ConnectivityResult.none;

if (_isOffline) {
// Load from cache
final cached = CacheService.getCachedPrograms('all_programs');
if (cached != null) {
_programs = cached.map(ProgramModel.fromMap).toList();
}
} else {
// Fetch fresh data and update cache
final freshData = await ProgramRepository.fetchAll();
_programs = freshData;
await CacheService.cachePrograms('all_programs', freshData.map((p) => p.toMap()).toList());
}

_isLoading = false;
notifyListeners();
}
}
````

### 4. Show offline banner in the home screen

````dart
// lib/screens/home_screen.dart
if (provider.isOffline)
Container(
width: double.infinity,
color: Colors.orange[100],
padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 16),
child: Row(children: [
const Icon(Icons.wifi_off, size: 16, color: Colors.orange),
const SizedBox(width: 8),
const Text('You\'re offline — showing cached data', style: TextStyle(color: Colors.orange)),
]),
),
````

## 📁 Files to Create / Modify

| File | Change |
|---|---|
| `pubspec.yaml` | Add `hive`, `hive_flutter`, `connectivity_plus` |
| `lib/services/cache_service.dart` | Create Hive cache service |
| `lib/providers/program_provider.dart` | Add offline/online data loading |
| `lib/main.dart` | Initialize Hive on startup |
| `lib/screens/home_screen.dart` | Show offline banner when cache used |

**Suggested labels:** `enhancement`, `flutter`, `offline`, `performance`, `level: intermediate`

I would like to work on this. Could you please assign it to me?

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.