#ifdef RCT_NEW_ARCH_ENABLED #import "RCTSecurePDFViewerComponentView.h" #import #import #import #import #import "react/renderer/components/SecurePdfViewer/ComponentDescriptors.h" #import "react/renderer/components/SecurePdfViewer/EventEmitters.h" #import "react/renderer/components/SecurePdfViewer/Props.h" #import "react/renderer/components/SecurePdfViewer/RCTComponentViewHelpers.h" #if __has_include("secure_pdf_viewer-Swift.h") #import "secure_pdf_viewer-Swift.h" #else #import #endif using namespace facebook::react; @interface RCTSecurePDFViewerComponentView () @end @implementation RCTSecurePDFViewerComponentView { SecurePdfViewerComponentView *_swiftView; std::shared_ptr _props; std::shared_ptr _eventEmitter; BOOL _needsForceUpdate; } - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { static const auto defaultProps = std::make_shared(); _props = defaultProps; _needsForceUpdate = NO; _swiftView = [[SecurePdfViewerComponentView alloc] initWithFrame:self.bounds]; _swiftView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; self.contentView = _swiftView; } return self; } - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps { const auto &oldViewProps = *std::static_pointer_cast(_props); const auto &newViewProps = *std::static_pointer_cast(props); // Force update source if the component was recycled, even if the source is the same if (oldViewProps.source != newViewProps.source || _needsForceUpdate) { _swiftView.source = [NSString stringWithUTF8String:newViewProps.source.c_str()]; _needsForceUpdate = NO; } if (oldViewProps.password != newViewProps.password || _needsForceUpdate) { if (!newViewProps.password.empty()) { _swiftView.password = [NSString stringWithUTF8String:newViewProps.password.c_str()]; } } if (oldViewProps.allowLinks != newViewProps.allowLinks) { _swiftView.allowLinks = newViewProps.allowLinks; } [super updateProps:props oldProps:oldProps]; _props = std::static_pointer_cast(props); } - (void)updateEventEmitter:(EventEmitter::Shared const &)eventEmitter { [super updateEventEmitter:eventEmitter]; _eventEmitter = std::static_pointer_cast(eventEmitter); __weak __typeof(self) weakSelf = self; _swiftView.onLinkPressed = ^(NSDictionary *payload) { __strong __typeof(weakSelf) strongSelf = weakSelf; if (strongSelf && strongSelf->_eventEmitter) { auto eventEmitter = strongSelf->_eventEmitter; SecurePdfViewerEventEmitter::OnLinkPressed event; event.url = std::string([[payload objectForKey:@"url"] UTF8String] ?: ""); eventEmitter->onLinkPressed(event); } }; _swiftView.onLinkPressedDisabled = ^(NSDictionary *payload) { __strong __typeof(weakSelf) strongSelf = weakSelf; if (strongSelf && strongSelf->_eventEmitter) { auto eventEmitter = strongSelf->_eventEmitter; eventEmitter->onLinkPressedDisabled({}); } }; _swiftView.onLoad = ^(NSDictionary *payload) { __strong __typeof(weakSelf) strongSelf = weakSelf; if (strongSelf && strongSelf->_eventEmitter) { auto eventEmitter = strongSelf->_eventEmitter; eventEmitter->onLoad({}); } }; _swiftView.onPasswordRequired = ^(NSDictionary *payload) { __strong __typeof(weakSelf) strongSelf = weakSelf; if (strongSelf && strongSelf->_eventEmitter) { auto eventEmitter = strongSelf->_eventEmitter; SecurePdfViewerEventEmitter::OnPasswordRequired event; event.maxAttempts = [[payload objectForKey:@"maxAttempts"] intValue]; event.remainingAttempts = [[payload objectForKey:@"remainingAttempts"] intValue]; eventEmitter->onPasswordRequired(event); } }; _swiftView.onPasswordFailed = ^(NSDictionary *payload) { __strong __typeof(weakSelf) strongSelf = weakSelf; if (strongSelf && strongSelf->_eventEmitter) { auto eventEmitter = strongSelf->_eventEmitter; SecurePdfViewerEventEmitter::OnPasswordFailed event; event.remainingAttempts = [[payload objectForKey:@"remainingAttempts"] intValue]; eventEmitter->onPasswordFailed(event); } }; _swiftView.onPasswordFailureLimitReached = ^(NSDictionary *payload) { __strong __typeof(weakSelf) strongSelf = weakSelf; if (strongSelf && strongSelf->_eventEmitter) { auto eventEmitter = strongSelf->_eventEmitter; SecurePdfViewerEventEmitter::OnPasswordFailureLimitReached event; event.maxAttempts = [[payload objectForKey:@"maxAttempts"] intValue]; eventEmitter->onPasswordFailureLimitReached(event); } }; _swiftView.onLoadError = ^(NSDictionary *payload) { __strong __typeof(weakSelf) strongSelf = weakSelf; if (strongSelf && strongSelf->_eventEmitter) { auto eventEmitter = strongSelf->_eventEmitter; SecurePdfViewerEventEmitter::OnLoadError event; event.message = std::string([[payload objectForKey:@"message"] UTF8String] ?: ""); eventEmitter->onLoadError(event); } }; _swiftView.onTap = ^(NSDictionary *payload) { __strong __typeof(weakSelf) strongSelf = weakSelf; if (strongSelf && strongSelf->_eventEmitter) { auto eventEmitter = strongSelf->_eventEmitter; SecurePdfViewerEventEmitter::OnTap event; event.x = [[payload objectForKey:@"x"] doubleValue]; event.y = [[payload objectForKey:@"y"] doubleValue]; eventEmitter->onTap(event); } }; } - (void)prepareForRecycle { [super prepareForRecycle]; // Do NOT set _props or _eventEmitter to nullptr - Fabric will handle lifecycle // Clear event handlers to prevent stale callbacks _swiftView.onLinkPressed = nil; _swiftView.onLinkPressedDisabled = nil; _swiftView.onLoad = nil; _swiftView.onPasswordRequired = nil; _swiftView.onPasswordFailed = nil; _swiftView.onPasswordFailureLimitReached = nil; _swiftView.onLoadError = nil; _swiftView.onTap = nil; // Clear the PDF document and reset state to prevent showing old content [_swiftView resetPDFState]; _swiftView.password = nil; // Set flag to force update on next props, even if source is the same _needsForceUpdate = YES; } + (ComponentDescriptorProvider)componentDescriptorProvider { return concreteComponentDescriptorProvider(); } @end Class SecurePdfViewerCls(void) { return RCTSecurePDFViewerComponentView.class; } #endif