Skip to content
Snippets Groups Projects
HomeFeature.swift 4.38 KiB
Newer Older
Dariusz Rybicki's avatar
Dariusz Rybicki committed
import Combine
import ComposableArchitecture
Dariusz Rybicki's avatar
Dariusz Rybicki committed
import ComposablePresentation
Dariusz Rybicki's avatar
Dariusz Rybicki committed
import Foundation
Dariusz Rybicki's avatar
Dariusz Rybicki committed
import RegisterFeature
import XXClient
import XXMessengerClient

public struct HomeState: Equatable {
Dariusz Rybicki's avatar
Dariusz Rybicki committed
  public init(
    failure: String? = nil,
    register: RegisterState? = nil,
    alert: AlertState<HomeAction>? = nil,
    isDeletingAccount: Bool = false
Dariusz Rybicki's avatar
Dariusz Rybicki committed
  ) {
    self.failure = failure
    self.register = register
    self.alert = alert
    self.isDeletingAccount = isDeletingAccount
Dariusz Rybicki's avatar
Dariusz Rybicki committed
  public var failure: String?
  public var register: RegisterState?
  public var alert: AlertState<HomeAction>?
  public var isDeletingAccount: Bool
Dariusz Rybicki's avatar
Dariusz Rybicki committed
public enum HomeAction: Equatable {
  public enum Messenger: Equatable {
    case start
    case didStartRegistered
    case didStartUnregistered
    case failure(NSError)
  }

  public enum DeleteAccount: Equatable {
    case buttonTapped
    case confirmed
    case success
    case failure(NSError)
  }

  case messenger(Messenger)
  case deleteAccount(DeleteAccount)
  case didDismissAlert
  case didDismissRegister
Dariusz Rybicki's avatar
Dariusz Rybicki committed
  case register(RegisterAction)
}

public struct HomeEnvironment {
  public init(
    messenger: Messenger,
    db: DBManagerGetDB,
    mainQueue: AnySchedulerOf<DispatchQueue>,
Dariusz Rybicki's avatar
Dariusz Rybicki committed
    bgQueue: AnySchedulerOf<DispatchQueue>,
    register: @escaping () -> RegisterEnvironment
  ) {
    self.messenger = messenger
    self.mainQueue = mainQueue
    self.bgQueue = bgQueue
Dariusz Rybicki's avatar
Dariusz Rybicki committed
    self.register = register
  }

  public var messenger: Messenger
  public var db: DBManagerGetDB
  public var mainQueue: AnySchedulerOf<DispatchQueue>
  public var bgQueue: AnySchedulerOf<DispatchQueue>
Dariusz Rybicki's avatar
Dariusz Rybicki committed
  public var register: () -> RegisterEnvironment
}

extension HomeEnvironment {
  public static let unimplemented = HomeEnvironment(
    messenger: .unimplemented,
    db: .unimplemented,
    mainQueue: .unimplemented,
Dariusz Rybicki's avatar
Dariusz Rybicki committed
    bgQueue: .unimplemented,
    register: { .unimplemented }
  )
}

public let homeReducer = Reducer<HomeState, HomeAction, HomeEnvironment>
{ state, action, env in
  switch action {
Dariusz Rybicki's avatar
Dariusz Rybicki committed
  case .messenger(.start):
    return .result {
Dariusz Rybicki's avatar
Dariusz Rybicki committed
      do {
        try env.messenger.start()

        if env.messenger.isConnected() == false {
          try env.messenger.connect()
        }

        if env.messenger.isLoggedIn() == false {
          if try env.messenger.isRegistered() == false {
Dariusz Rybicki's avatar
Dariusz Rybicki committed
            return .success(.messenger(.didStartUnregistered))
Dariusz Rybicki's avatar
Dariusz Rybicki committed
          }
          try env.messenger.logIn()
        }
Dariusz Rybicki's avatar
Dariusz Rybicki committed

        return .success(.messenger(.didStartRegistered))
Dariusz Rybicki's avatar
Dariusz Rybicki committed
      } catch {
Dariusz Rybicki's avatar
Dariusz Rybicki committed
        return .success(.messenger(.failure(error as NSError)))
Dariusz Rybicki's avatar
Dariusz Rybicki committed
      }
    }
    .subscribe(on: env.bgQueue)
    .receive(on: env.mainQueue)
    .eraseToEffect()

Dariusz Rybicki's avatar
Dariusz Rybicki committed
  case .messenger(.didStartUnregistered):
    state.register = RegisterState()
    return .none

  case .messenger(.didStartRegistered):
    return .none

  case .messenger(.failure(let error)):
    state.failure = error.localizedDescription
    return .none

  case .deleteAccount(.buttonTapped):
    state.alert = .confirmAccountDeletion()
    return .none

Dariusz Rybicki's avatar
Dariusz Rybicki committed
  case .deleteAccount(.confirmed):
    state.isDeletingAccount = true
Dariusz Rybicki's avatar
Dariusz Rybicki committed
    return .result {
      do {
        let contactId = try env.messenger.e2e.tryGet().getContact().getId()
        let contact = try env.db().fetchContacts(.init(id: [contactId])).first
        if let username = contact?.username {
          let ud = try env.messenger.ud.tryGet()
          try ud.permanentDeleteAccount(username: Fact(fact: username, type: 0))
        }
        try env.messenger.destroy()
        try env.db().drop()
Dariusz Rybicki's avatar
Dariusz Rybicki committed
        return .success(.deleteAccount(.success))
Dariusz Rybicki's avatar
Dariusz Rybicki committed
        return .success(.deleteAccount(.failure(error as NSError)))
      }
    }
    .subscribe(on: env.bgQueue)
    .receive(on: env.mainQueue)
    .eraseToEffect()

Dariusz Rybicki's avatar
Dariusz Rybicki committed
  case .deleteAccount(.success):
    state.isDeletingAccount = false
    return .none

Dariusz Rybicki's avatar
Dariusz Rybicki committed
  case .deleteAccount(.failure(let error)):
    state.isDeletingAccount = false
    state.alert = .accountDeletionFailed(error)
    return .none

  case .didDismissAlert:
    state.alert = nil
    return .none

  case .didDismissRegister:
    state.register = nil
    return .none

Dariusz Rybicki's avatar
Dariusz Rybicki committed
  case .register(.finished):
    state.register = nil
Dariusz Rybicki's avatar
Dariusz Rybicki committed
    return Effect(value: .messenger(.start))
Dariusz Rybicki's avatar
Dariusz Rybicki committed
  case .register(_):
    return .none
  }
}
Dariusz Rybicki's avatar
Dariusz Rybicki committed
.presenting(
  registerReducer,
  state: .keyPath(\.register),
  id: .notNil(),
  action: /HomeAction.register,
  environment: { $0.register() }
)