Reply
User-XkQI1 month ago
import Foundation import Flutter import SwiftUI import Octopus import OctopusUI import Combine // MARK: - SwiftUI wrapper with callback struct OctopusHomeScreenWithCallback: View { let octopus: OctopusSDK let navBarLeadingItem: OctopusHomeScreen.NavBarLeadingItemKind let navBarPrimaryColor: Bool let onNavigateToLogin: () -> Void var body: some View { OctopusHomeScreen( octopus: octopus, navBarLeadingItem: navBarLeadingItem, navBarPrimaryColor: navBarPrimaryColor ) .onReceive(NotificationCenter.default.publisher( for: NSNotification.Name("OctopusNavigateToLogin")) ) { _ in onNavigateToLogin() } } } // MARK: - Flutter View Factory final class OctopusViewFactory: NSObject, FlutterPlatformViewFactory { private let messenger: FlutterBinaryMessenger init(messenger: FlutterBinaryMessenger) { self.messenger = messenger super.init() } func createArgsCodec() -> FlutterMessageCodec & NSObjectProtocol { FlutterStandardMessageCodec.sharedInstance() } func create( withFrame frame: CGRect, viewIdentifier viewId: Int64, arguments args: Any? ) -> FlutterPlatformView { OctopusPlatformView(frame: frame, args: args) } } // MARK: - Platform View Wrapper final class OctopusPlatformView: NSObject, FlutterPlatformView { private let container: SafeHostingContainerView init(frame: CGRect, args: Any?) { self.container = SafeHostingContainerView(args: args) self.container.frame = frame super.init() } func view() -> UIView { container } } // MARK: - Hosting Container (fixes iOS 18.0 crash) private final class SafeHostingContainerView: UIView { private var hostingController: UIHostingController<AnyView>? private let args: Any? init(args: Any?) { self.args = args super.init(frame: .zero) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func didMoveToWindow() { super.didMoveToWindow() guard window != nil else { return } // Avoid double initialization guard hostingController == nil else { return } // Delay one runloop to guarantee valid UIWindowScene (prevents iOS 18.0 bug) // DispatchQueue.main.async { [weak self] in self.initializeSwiftUIView() // } } private func initializeSwiftUIView() { guard let octopus = OctopusSdkFlutterPlugin.sharedOctopus else { addErrorLabel() return } // --- Parse arguments --- let dict = args as? [String: Any] let main = (dict?["primaryMain"] as? NSNumber).map { OctopusSdkFlutterPlugin.uiColorFromARGBInt($0.intValue) } let low = (dict?["primaryLowContrast"] as? NSNumber).map { OctopusSdkFlutterPlugin.uiColorFromARGBInt($0.intValue) } let high = (dict?["primaryHighContrast"] as? NSNumber).map { OctopusSdkFlutterPlugin.uiColorFromARGBInt($0.intValue) } let onPrimary = (dict?["onPrimary"] as? NSNumber).map { OctopusSdkFlutterPlugin.uiColorFromARGBInt($0.intValue) } let logoBase64 = dict?["logoBase64"] as? String let navBarTitle = dict?["navBarTitle"] as? String let navBarPrimaryColor = (dict?["navBarPrimaryColor"] as? Bool) ?? false let themeMode = dict?["themeMode"] as? String let fontSizeTitle1 = (dict?["fontSizeTitle1"] as? NSNumber)?.intValue ?? 26 let fontSizeTitle2 = (dict?["fontSizeTitle2"] as? NSNumber)?.intValue ?? 20 let fontSizeBody1 = (dict?["fontSizeBody1"] as? NSNumber)?.intValue ?? 17 let fontSizeBody2 = (dict?["fontSizeBody2"] as? NSNumber)?.intValue ?? 14 let fontSizeCaption1 = (dict?["fontSizeCaption1"] as? NSNumber)?.intValue ?? 12 let fontSizeCaption2 = (dict?["fontSizeCaption2"] as? NSNumber)?.intValue ?? 10 var theme: OctopusTheme? = nil if main != nil || low != nil || high != nil || onPrimary != nil || logoBase64 != nil || fontSizeTitle1 != 26 || fontSizeTitle2 != 20 || fontSizeBody1 != 17 || fontSizeBody2 != 14 || fontSizeCaption1 != 12 || fontSizeCaption2 != 10 || themeMode != nil { theme = OctopusSdkFlutterPlugin.buildTheme( main: main ?? .systemBlue, low: low ?? UIColor.systemBlue.withAlphaComponent(0.2), high: high ?? .white, onPrimary: onPrimary ?? .white, logoBase64: logoBase64, fontSizeTitle1: fontSizeTitle1, fontSizeTitle2: fontSizeTitle2, fontSizeBody1: fontSizeBody1, fontSizeBody2: fontSizeBody2, fontSizeCaption1: fontSizeCaption1, fontSizeCaption2: fontSizeCaption2, themeMode: themeMode ) }