diff --git a/modules/ensemble/lib/action/invoke_api_action.dart b/modules/ensemble/lib/action/invoke_api_action.dart index 23ebc991d..220667680 100644 --- a/modules/ensemble/lib/action/invoke_api_action.dart +++ b/modules/ensemble/lib/action/invoke_api_action.dart @@ -63,7 +63,7 @@ class InvokeAPIAction extends EnsembleAction { } class InvokeAPIController { - Future executeWithContext( + Future executeWithContext( BuildContext context, InvokeAPIAction action, {Map? additionalInputs}) { ScopeManager? foundScopeManager = @@ -90,9 +90,10 @@ class InvokeAPIController { return APIProviders.of(context).getProvider(provider); } - Future execute(InvokeAPIAction action, BuildContext context, + Future execute(InvokeAPIAction action, BuildContext context, ScopeManager scopeManager, Map? apiMap) async { YamlMap? apiDefinition = apiMap?[action.apiName]; + if (apiDefinition != null) { ScopeManager apiScopeManager = scopeManager.newCreateChildScope(ephemeral: true); @@ -144,13 +145,27 @@ class InvokeAPIController { } APIProvider apiProvider = getAPIProvider(context, apiDefinition); + var isChangeListener = apiDefinition['listenForChanges']; + + if (isChangeListener is! bool) { + isChangeListener = apiScopeManager.dataContext + .getContextById(apiDefinition['listenForChanges']); + + if (!isChangeListener) { + if (apiProvider is LiveAPIProvider) { + await (apiProvider as LiveAPIProvider) + .unSubscribeToApi(action.apiName); + } + return null; + } + } + if (AppConfig(context, apiScopeManager.dataContext.getAppId()) .isMockResponse() && apiDefinition['mockResponse'] != null) { response = await apiProvider.invokeMockAPI( apiScopeManager.dataContext, apiDefinition['mockResponse']); - } else if (apiDefinition['listenForChanges'] == true && - apiProvider is LiveAPIProvider) { + } else if (isChangeListener == true && apiProvider is LiveAPIProvider) { response = await (apiProvider as LiveAPIProvider).subscribeToApi( context, apiDefinition, diff --git a/modules/ensemble/lib/framework/apiproviders/api_provider.dart b/modules/ensemble/lib/framework/apiproviders/api_provider.dart index f86978ee4..c9008e519 100644 --- a/modules/ensemble/lib/framework/apiproviders/api_provider.dart +++ b/modules/ensemble/lib/framework/apiproviders/api_provider.dart @@ -16,6 +16,7 @@ abstract class APIProvider { mixin LiveAPIProvider { Future subscribeToApi(BuildContext context, YamlMap api, DataContext eContext, String apiName, ResponseListener listener); + Future unSubscribeToApi(String apiName); } class APIProviders extends InheritedWidget { diff --git a/modules/ensemble/lib/framework/apiproviders/firestore/firestore_api_provider.dart b/modules/ensemble/lib/framework/apiproviders/firestore/firestore_api_provider.dart index 7ff54b7b1..ad8827642 100644 --- a/modules/ensemble/lib/framework/apiproviders/firestore/firestore_api_provider.dart +++ b/modules/ensemble/lib/framework/apiproviders/firestore/firestore_api_provider.dart @@ -13,9 +13,13 @@ import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/foundation.dart'; class FirestoreAPIProvider extends APIProvider with LiveAPIProvider { + FirestoreAPIProvider._(); + static final FirestoreAPIProvider _instance = FirestoreAPIProvider._(); + factory FirestoreAPIProvider() => _instance; + FirebaseApp? _app; FirebaseFirestore get firestore => FirebaseFirestore.instanceFor(app: _app!); - List _subscriptions = []; + Map _subscriptions = {}; late FirestoreApp firestoreApp; @override @@ -237,6 +241,12 @@ class FirestoreAPIProvider extends APIProvider with LiveAPIProvider { throw UnimplementedError(); } + @override + Future unSubscribeToApi(String apiName) async { + if (!_subscriptions.containsKey(apiName)) return; + await _subscriptions[apiName]?.cancel(); + } + @override Future subscribeToApi(BuildContext context, YamlMap apiMap, DataContext eContext, String apiName, ResponseListener listener) async { @@ -257,20 +267,25 @@ class FirestoreAPIProvider extends APIProvider with LiveAPIProvider { if (isDocumentPath) { DocumentReference docRef = firestore.doc(path); - _subscriptions.add(docRef.snapshots().listen((DocumentSnapshot snapshot) { - listener.call(getOKResponse(apiName, snapshot)); - })); + + _subscriptions.addAll({ + apiName: docRef.snapshots().listen((DocumentSnapshot snapshot) { + listener.call(getOKResponse(apiName, snapshot)); + }) + }); } else { Query query = firestoreApp.getQuery(api); - _subscriptions.add(query.snapshots().listen((QuerySnapshot snapshot) { - listener.call(getOKResponse(apiName, snapshot)); - })); + _subscriptions.addAll({ + apiName: query.snapshots().listen((QuerySnapshot snapshot) { + listener.call(getOKResponse(apiName, snapshot)); + }) + }); } Map body = { 'message': 'Subscribed to API', 'documents': [] }; - ; + return FirestoreResponse( apiState: APIState.success, body: body, @@ -283,11 +298,11 @@ class FirestoreAPIProvider extends APIProvider with LiveAPIProvider { dispose() { try { if (_subscriptions.isNotEmpty) { - for (var subscription in _subscriptions) { + for (var subscription in _subscriptions.values) { subscription.cancel(); } } - _subscriptions = []; + _subscriptions = {}; } catch (e) { print('Error disposing FirestoreAPIProvider: $e'); }