Skip to content

Instantly share code, notes, and snippets.

@simme
Created April 4, 2023 08:44
Show Gist options
  • Select an option

  • Save simme/cff23d521653f380310c04fc785364c5 to your computer and use it in GitHub Desktop.

Select an option

Save simme/cff23d521653f380310c04fc785364c5 to your computer and use it in GitHub Desktop.

Revisions

  1. simme created this gist Apr 4, 2023.
    91 changes: 91 additions & 0 deletions StoreControllerDialogs.swift
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,91 @@
    /*
    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)
    }
    }
    }
    }