/* Example usage: confirmationDialog( store: store.scope(state: \.destination, action: UserRecipesListReducer.Action.destination), state: /UserRecipesListReducer.Destination.State.confirmation, action: UserRecipesListReducer.Destination.Action.confirmation ).store(in: &subscriptions) alert( store: store.scope(state: \.destination, action: UserRecipesListReducer.Action.destination), state: /UserRecipesListReducer.Destination.State.alert, action: UserRecipesListReducer.Destination.Action.alert ).store(in: &subscriptions) */ extension StoreViewController { func alert<DestinationState, DestinationAction, Action>( store: Store<DestinationState?, PresentationAction<DestinationAction>>, state toAlertState: @escaping (DestinationState) -> AlertState<Action>?, action fromAlertAction: @escaping (Action) -> DestinationAction ) -> any Cancellable { self.alert( store: store.scope( state: { $0.flatMap(toAlertState) }, action: { switch $0 { case .dismiss: return .dismiss case let .presented(action): return .presented(fromAlertAction(action)) } } ) ) } func alert<Action>( store: Store<AlertState<Action>?, PresentationAction<Action>> ) -> any Cancellable { let viewStore = ViewStore(store, observe: { $0 }, removeDuplicates: { ($0 != nil) == ($1 != nil) }) return viewStore.publisher.sink { alertState in if let alertState { let alertController = UIAlertController(state: alertState) { action in if let action { viewStore.send(.presented(action)) } } self.present(alertController, animated: true) } else { self.dismiss(animated: true) } } } func confirmationDialog<DestinationState, DestinationAction, Action>( store: Store<DestinationState?, PresentationAction<DestinationAction>>, state toConfirmationDialogState: @escaping (DestinationState) -> ConfirmationDialogState<Action>?, action fromConfirmationAction: @escaping (Action) -> DestinationAction ) -> any Cancellable { self.confirmationDialog( store: store.scope( state: { $0.flatMap(toConfirmationDialogState) }, action: { switch $0 { case .dismiss: return .dismiss case let .presented(action): return .presented(fromConfirmationAction(action)) } } ) ) } func confirmationDialog<Action>( store: Store<ConfirmationDialogState<Action>?, PresentationAction<Action>> ) -> any Cancellable { let viewStore = ViewStore(store, observe: { $0 }, removeDuplicates: { ($0 != nil) == ($1 != nil) }) return viewStore.publisher.sink { confirmationState in if let confirmationState { let alertController = UIAlertController(state: confirmationState) { action in if let action { viewStore.send(.presented(action)) } } self.present(alertController, animated: true) } else { self.dismiss(animated: true) } } } }