Skip to content

Commit

Permalink
More clean up for streams implementation and add resend last module m…
Browse files Browse the repository at this point in the history
…ethod
  • Loading branch information
crow committed Aug 30, 2024
1 parent 590bd5d commit 7a050df
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 44 deletions.
19 changes: 6 additions & 13 deletions ios/Classes/SwiftAirshipPlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,10 @@ public class SwiftAirshipPlugin: NSObject, FlutterPlugin {
case "inApp#getDisplayInterval":
return try AirshipProxy.shared.inApp.getDisplayInterval()

case "inApp#resendEmbeddedEvent":
AirshipProxy.shared.inApp.resendLastEmbeddedEvent()
return nil

// Analytics
case "analytics#trackScreen":
try AirshipProxy.shared.analytics.trackScreen(
Expand Down Expand Up @@ -457,6 +461,7 @@ public class SwiftAirshipPlugin: NSObject, FlutterPlugin {
try AirshipProxy.shared.featureFlagManager.trackInteraction(flag: featureFlagProxy)

return nil

default:
return FlutterError(
code:"UNAVAILABLE",
Expand Down Expand Up @@ -542,13 +547,9 @@ extension FlutterMethodCall {
}
}

protocol AirshipEventStreamHandlerDelegate: AnyObject {
func handlerWasRemoved(_ handler: AirshipEventStreamHandler)
}

class AirshipEventStreamHandler: NSObject, FlutterStreamHandler {
private var eventSink: FlutterEventSink?
weak var delegate: AirshipEventStreamHandlerDelegate?

func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
self.eventSink = events
Expand All @@ -557,7 +558,6 @@ class AirshipEventStreamHandler: NSObject, FlutterStreamHandler {

func onCancel(withArguments arguments: Any?) -> FlutterError? {
self.eventSink = nil
delegate?.handlerWasRemoved(self)
return nil
}

Expand All @@ -570,7 +570,7 @@ class AirshipEventStreamHandler: NSObject, FlutterStreamHandler {
}
}

class AirshipEventStream: NSObject, AirshipEventStreamHandlerDelegate {
class AirshipEventStream: NSObject {
private let eventType: AirshipProxyEventType
private let name: String
private let lock = AirshipLock()
Expand All @@ -587,7 +587,6 @@ class AirshipEventStream: NSObject, AirshipEventStreamHandlerDelegate {
binaryMessenger: registrar.messenger()
)
let handler = AirshipEventStreamHandler()
handler.delegate = self
eventChannel.setStreamHandler(handler)

lock.sync {
Expand Down Expand Up @@ -617,10 +616,4 @@ class AirshipEventStream: NSObject, AirshipEventStreamHandlerDelegate {
}
return result
}

func handlerWasRemoved(_ handler: AirshipEventStreamHandler) {
lock.sync {
handlers.removeAll { $0 === handler }
}
}
}
61 changes: 30 additions & 31 deletions lib/src/airship_in_app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,64 +4,63 @@ import 'dart:async';

class AirshipInApp {
final AirshipModule _module;
final Map<String, StreamController<bool>> _isEmbeddedAvailableControllers =
{};
List<EmbeddedInfo> _embeddedInfos = [];
late final StreamController<EmbeddedInfoUpdatedEvent>
late final StreamController<List<EmbeddedInfo>>
_embeddedInfoUpdatedController;
late final StreamSubscription<EmbeddedInfoUpdatedEvent> _subscription;

List<EmbeddedInfo> getEmbeddedInfos() => _embeddedInfos;
StreamSubscription? _eventSubscription;
bool _isFirstStream = true;

AirshipInApp(this._module) {
_embeddedInfoUpdatedController =
StreamController<EmbeddedInfoUpdatedEvent>.broadcast();
_setupEventStream();
_subscription = onEmbeddedInfoUpdated.listen(_updateEmbeddedIds);
_setupController();
}

/// A flag to determine if an embedded id is available that is not live updated
List<EmbeddedInfo> getEmbeddedInfos() => _embeddedInfos;

bool isEmbeddedAvailable({required String embeddedId}) =>
_embeddedInfos.any((info) => info.embeddedId == embeddedId);

/// A live updated stream to determine if an embedded id is available
Stream<bool> isEmbeddedAvailableStream({required String embeddedId}) =>
(_isEmbeddedAvailableControllers[embeddedId] ??=
StreamController<bool>.broadcast()
..add(isEmbeddedAvailable(embeddedId: embeddedId)))
.stream;
onEmbeddedInfoUpdated.map((embeddedInfos) =>
embeddedInfos.any((info) => info.embeddedId == embeddedId));

Stream<EmbeddedInfoUpdatedEvent> get onEmbeddedInfoUpdated =>
Stream<List<EmbeddedInfo>> get onEmbeddedInfoUpdated =>
_embeddedInfoUpdatedController.stream;

void _setupController() {
_embeddedInfoUpdatedController =
StreamController<List<EmbeddedInfo>>.broadcast(onListen: () {
if (_isFirstStream) {
_isFirstStream = false;
_resendLastEmbeddedUpdate();
}
});
}

void _setupEventStream() {
_module
_eventSubscription = _module
.getEventStream("com.airship.flutter/event/pending_embedded_updated")
.listen((event) {
try {
_embeddedInfoUpdatedController
.add(EmbeddedInfoUpdatedEvent.fromJson(event));
final updatedEvent = EmbeddedInfoUpdatedEvent.fromJson(event);
_embeddedInfos = updatedEvent.embeddedInfos;
_embeddedInfoUpdatedController.add(_embeddedInfos);
} catch (e) {
print("Error parsing EmbeddedInfoUpdatedEvent: $e");
}
});
}

void _updateEmbeddedIds(EmbeddedInfoUpdatedEvent event) {
/// Update the embedded infos list
_embeddedInfos = event.embeddedInfos;

/// Update stream controllers for each embedded id so everything remains synced
_isEmbeddedAvailableControllers.forEach((id, controller) =>
controller.add(isEmbeddedAvailable(embeddedId: id)));
Future<void> _resendLastEmbeddedUpdate() async {
try {
await _module.channel.invokeMethod("inApp#resendEmbeddedEvent");
} catch (e) {
print("Error resending embedded update: $e");
}
}

void dispose() {
_subscription.cancel();

/// Remove and close all stream controllers for each embedded id
_isEmbeddedAvailableControllers.values
.forEach((controller) => controller.close());
_eventSubscription?.cancel();
_embeddedInfoUpdatedController.close();
}
}

0 comments on commit 7a050df

Please sign in to comment.