Created
July 31, 2024 14:04
-
-
Save BrandowBuenos/934db9e4be683561d9285af7803c4863 to your computer and use it in GitHub Desktop.
App data handler
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ignore_for_file: unnecessary_lambdas, use_build_context_synchronously | |
import 'dart:async'; | |
import 'dart:convert'; | |
import 'package:flutter/foundation.dart'; | |
import 'package:flutter_secure_storage/flutter_secure_storage.dart'; | |
import 'package:idb_shim/idb.dart'; | |
import 'package:idb_shim/idb_browser.dart'; | |
// Enum representing the different models in your app. TODO: Add your specific models here. | |
enum AppModel { | |
// TODO: Replace with your models | |
model1, | |
model2, | |
model3, | |
// ... | |
} | |
class AppData extends ChangeNotifier { | |
List<AppModel> hasError = []; | |
bool finishedSync = false; | |
Database? _db; | |
// Function to get the IndexedDB database instance. | |
Future<Database> _getDatabase() async { | |
if (_db == null) { | |
IdbFactory idbFactory = getIdbFactory()!; | |
_db = await idbFactory.open('appDatabase', version: 1, | |
onUpgradeNeeded: (VersionChangeEvent e) { | |
Database db = e.database; | |
if (!db.objectStoreNames.contains('dataStore')) { | |
db.createObjectStore('dataStore'); | |
} | |
}); | |
} | |
return _db!; | |
} | |
void setFinishedSync(bool value) { | |
finishedSync = value; | |
notifyListeners(); | |
} | |
// Function to get information about a specific model. TODO: Customize with your model details. | |
dynamic getModelInfo(AppModel model) { | |
switch (model) { | |
case AppModel.model1: | |
return { | |
'key': 'model1_key', | |
'model': Model1, | |
'list': model1Controller.model1List, | |
'stater': (items) => model1Controller.setModel1(items), | |
}; | |
case AppModel.model2: | |
return { | |
'key': 'model2_key', | |
'model': Model2, | |
'list': model2Controller.model2List, | |
'stater': (items) => model2Controller.setModel2(items), | |
}; | |
case AppModel.model3: | |
return { | |
'key': 'model3_key', | |
'model': Model3, | |
'list': model3Controller.model3List, | |
'stater': (items) => model3Controller.setModel3(items), | |
}; | |
// TODO: Add cases for other models | |
default: | |
return ''; | |
} | |
} | |
// Function to save current data for specified models. | |
Future<void> saveCurrentData(List<AppModel> models) async { | |
for (final AppModel model in models) { | |
getModelInfo(model)['stater'](getModelInfo(model)['list']); | |
} | |
for (final AppModel model in models) { | |
List<dynamic> list = getModelInfo(model)['list']; | |
await saveList(model, list); | |
} | |
} | |
// Function to save a list of data for a specific model. | |
Future<void> saveList(AppModel model, List<dynamic> list) async { | |
final String key = getModelInfo(model)['key']; | |
String encodedList = jsonEncode(list); | |
if (kIsWeb) { | |
await saveListOnIndexedDB(key, encodedList); | |
} else { | |
FlutterSecureStorage flutterSecureStorage = const FlutterSecureStorage(); | |
await flutterSecureStorage.write(key: key, value: encodedList); | |
} | |
} | |
// Function to save data to IndexedDB. | |
Future<void> saveListOnIndexedDB(String key, String value) async { | |
Database db = await _getDatabase(); | |
Transaction txn = db.transaction('dataStore', 'readwrite'); | |
ObjectStore store = txn.objectStore('dataStore'); | |
await store.put(value, key); | |
await txn.completed; | |
} | |
// Function to retrieve data from IndexedDB. | |
Future<String?> getListFromIndexedDB(String key) async { | |
Database db = await _getDatabase(); | |
Transaction txn = db.transaction('dataStore', 'readonly'); | |
ObjectStore store = txn.objectStore('dataStore'); | |
String? value = await store.getObject(key) as String?; | |
await txn.completed; | |
return value; | |
} | |
// Function to retrieve a list of data for a specific model. | |
Future<dynamic> getList(AppModel model) async { | |
final String key = getModelInfo(model)['key']; | |
String? encodedList; | |
if (kIsWeb) { | |
encodedList = await getListFromIndexedDB(key); | |
} else { | |
FlutterSecureStorage flutterSecureStorage = const FlutterSecureStorage(); | |
encodedList = await flutterSecureStorage.read(key: key); | |
} | |
if (encodedList != null) { | |
List<dynamic> jsonList = jsonDecode(encodedList); | |
// TODO: Customize the deserialization for your models | |
if (model == AppModel.model1) { | |
List<Model1> model1List = []; | |
for (final json in jsonList) { | |
model1List.add(Model1.fromJson(json)); | |
} | |
return model1List; | |
} else if (model == AppModel.model2) { | |
List<Model2> model2List = []; | |
for (final json in jsonList) { | |
model2List.add(Model2.fromJson(json)); | |
} | |
return model2List; | |
} else if (model == AppModel.model3) { | |
List<Model3> model3List = []; | |
for (final json in jsonList) { | |
model3List.add(Model3.fromJson(json)); | |
} | |
return model3List; | |
} | |
} else { | |
// TODO: Implement API call or other fallback logic | |
return api.get(model); | |
} | |
} | |
// Function to inject data from secure storage into the app state. | |
Future<void> getListFromSecureStorageAndInject(AppModel model) async { | |
dynamic list = await getList(model); | |
getModelInfo(model)['stater'](list); | |
} | |
// Function to create a new item for a specific model. | |
Future<void> createItem(AppModel model, dynamic itemToCreate, | |
{bool? ignoreRefresh}) async { | |
List<dynamic> list = getModelInfo(model)['list']; | |
list.add(itemToCreate); | |
if (ignoreRefresh != true) { | |
await saveList(model, list); | |
getModelInfo(model)['stater'](list); | |
} | |
unawaited(api.create(model, itemToCreate)); | |
} | |
// Function to update an existing item for a specific model. | |
Future<void> updateItem(AppModel model, dynamic itemToUpdate, | |
{bool? ignoreRefresh}) async { | |
List<dynamic> list = getModelInfo(model)['list']; | |
int index = list.indexWhere((element) => element.id == itemToUpdate.id); | |
if (index != -1) { | |
list[index] = itemToUpdate; | |
if (ignoreRefresh != true) { | |
await saveList(model, list); | |
getModelInfo(model)['stater'](list); | |
} | |
} | |
unawaited(api.update(model, itemToUpdate)); | |
} | |
// Function to delete an item for a specific model. | |
Future<void> deleteItem(AppModel model, dynamic itemToDelete, | |
{bool? ignoreRefresh}) async { | |
List<dynamic> list = getModelInfo(model)['list']; | |
list.removeWhere((element) => element.id == itemToDelete.id); | |
if (ignoreRefresh != true) { | |
await saveList(model, list); | |
getModelInfo(model)['stater'](list); | |
} | |
unawaited(api.delete(model, itemToDelete)); | |
} | |
// Function to clear a specific key from storage. | |
Future<void> clearKey(String key) async { | |
if (kIsWeb) { | |
await clearKeyFromIndexedDB(key); | |
} else { | |
FlutterSecureStorage flutterSecureStorage = const FlutterSecureStorage(); | |
if (await flutterSecureStorage.containsKey(key: key)) { | |
await flutterSecureStorage.delete(key: key); | |
} | |
} | |
} | |
// Function to clear a specific key from IndexedDB. | |
Future<void> clearKeyFromIndexedDB(String key) async { | |
Database db = await _getDatabase(); | |
Transaction txn = db.transaction('dataStore', 'readwrite'); | |
ObjectStore store = txn.objectStore('dataStore'); | |
await store.delete(key); | |
await txn.completed; | |
} | |
// Function to clear all keys from storage. | |
Future<void> clearAllStoreKeys() async { | |
for (final AppModel model in AppModel.values) { | |
await clearKey(getModelInfo(model)['key']); | |
} | |
} | |
bool isFinishedSync() => finishedSync && hasError.isEmpty; | |
// Function to refresh data by clearing and re-fetching it. | |
Future<void> refreshData() async { | |
await clearAllStoreKeys(); | |
api.itemsWithRelationErrors.clear(); | |
hasError.clear(); | |
setFinishedSync(false); | |
await Future.wait([ | |
getListFromSecureStorageAndInject(AppModel.model1).catchError((e) { | |
hasError.add(AppModel.model1); | |
}), | |
getListFromSecureStorageAndInject(AppModel.model2).catchError((e) { | |
hasError.add(AppModel.model2); | |
}), | |
getListFromSecureStorageAndInject(AppModel.model3).catchError((e) { | |
hasError.add(AppModel.model3); | |
}), | |
// TODO: Add more models as needed | |
]); | |
setFinishedSync(true); | |
if (hasError.isNotEmpty) { | |
CustomSnackbar.confirm( | |
navigatorKey.currentState!.context, | |
'Error syncing data. Try again?', | |
'Yes', | |
() { | |
refreshData(); | |
}, | |
); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment