Skip to content
Snippets Groups Projects
ContactViewModel.swift 6.26 KiB
Newer Older
Bruno Muniz's avatar
Bruno Muniz committed
import UIKit
Bruno Muniz's avatar
Bruno Muniz committed
import Shared
Bruno Muniz's avatar
Bruno Muniz committed
import Combine
import XXModels
import Defaults
Bruno Muniz's avatar
Bruno Muniz committed
import XXClient
Bruno Muniz's avatar
Bruno Muniz committed
import CombineSchedulers
Bruno Muniz's avatar
Bruno Muniz committed
import XXMessengerClient
Bruno Muniz's avatar
Bruno Muniz committed
struct ContactViewState: Equatable {
Bruno Muniz's avatar
Bruno Muniz committed
  var title: String?
  var email: String?
  var phone: String?
  var photo: UIImage?
  var username: String?
  var nickname: String?
Bruno Muniz's avatar
Bruno Muniz committed
}

final class ContactViewModel {
  @Dependency(\.app.dbManager) var dbManager
  @Dependency(\.app.messenger) var messenger
  @Dependency(\.hudManager) var hudManager
Bruno Muniz's avatar
Bruno Muniz committed
  
  @KeyObject(.username, defaultValue: nil) var username: String?
  @KeyObject(.sharingEmail, defaultValue: false) var sharingEmail: Bool
  @KeyObject(.sharingPhone, defaultValue: false) var sharingPhone: Bool
  
  var contact: XXModels.Contact
  
  var popPublisher: AnyPublisher<Void, Never> { popRelay.eraseToAnyPublisher() }
  var successPublisher: AnyPublisher<Void, Never> { successRelay.eraseToAnyPublisher() }
  var popToRootPublisher: AnyPublisher<Void, Never> { popToRootRelay.eraseToAnyPublisher() }
  var statePublisher: AnyPublisher<ContactViewState, Never> { stateRelay.eraseToAnyPublisher() }
  
  private let popRelay = PassthroughSubject<Void, Never>()
  private let popToRootRelay = PassthroughSubject<Void, Never>()
  private let successRelay = PassthroughSubject<Void, Never>()
  private let stateRelay = CurrentValueSubject<ContactViewState, Never>(.init())
  
  var myId: Data {
    try! messenger.e2e.get()!.getContact().getId()
  }
  
  var backgroundScheduler: AnySchedulerOf<DispatchQueue> = DispatchQueue.global().eraseToAnyScheduler()
  
  init(_ contact: XXModels.Contact) {
    self.contact = contact
Bruno Muniz's avatar
Bruno Muniz committed
    stateRelay.value = .init(
      title: contact.nickname ?? contact.username,
      email: contact.email,
      phone: contact.phone,
Bruno Muniz's avatar
Bruno Muniz committed
      photo: contact.photo != nil ? UIImage(data: contact.photo!) : nil,
      username: contact.username,
      nickname: contact.nickname
    )
  }
  
  func didChoosePhoto(_ photo: UIImage) {
    stateRelay.value.photo = photo
    contact.photo = photo.jpegData(compressionQuality: 0.0)
    _ = try? dbManager.getDB().saveContact(contact)
Bruno Muniz's avatar
Bruno Muniz committed
  }
  
  func didTapDelete() {
Bruno Muniz's avatar
Bruno Muniz committed
    
    do {
      try messenger.e2e.get()!.deleteRequest.partnerId(contact.id)
      try dbManager.getDB().deleteContact(contact)
Bruno Muniz's avatar
Bruno Muniz committed
      
Bruno Muniz's avatar
Bruno Muniz committed
      popToRootRelay.send()
    } catch {
      hudManager.show(.init(error: error))
Bruno Muniz's avatar
Bruno Muniz committed
  }
  
  func didTapReject() {
    // TODO: Reject function on the API?
    _ = try? dbManager.getDB().deleteContact(contact)
Bruno Muniz's avatar
Bruno Muniz committed
    popRelay.send()
  }
  
  func didTapClear() {
    _ = try? dbManager.getDB().deleteMessages(.init(chat: .direct(myId, contact.id)))
Bruno Muniz's avatar
Bruno Muniz committed
  }
  
  func didUpdateNickname(_ string: String) {
    contact.nickname = string.isEmpty ? nil : string
    stateRelay.value.title = string.isEmpty ? contact.username : string
    _ = try? dbManager.getDB().saveContact(contact)
Bruno Muniz's avatar
Bruno Muniz committed
    
    stateRelay.value.nickname = contact.nickname
  }
  
  func didTapResend() {
Bruno Muniz's avatar
Bruno Muniz committed
    contact.authStatus = .requesting
    
    backgroundScheduler.schedule { [weak self] in
Bruno Muniz's avatar
Bruno Muniz committed
      guard let self else { return }
Bruno Muniz's avatar
Bruno Muniz committed
      
      do {
        try self.dbManager.getDB().saveContact(self.contact)
Bruno Muniz's avatar
Bruno Muniz committed
        
        var includedFacts: [Fact] = []
        let myFacts = try self.messenger.ud.get()!.getFacts()
        
        if let fact = myFacts.get(.username) {
          includedFacts.append(fact)
        }
        
        if self.sharingEmail, let fact = myFacts.get(.email) {
          includedFacts.append(fact)
        }
        
        if self.sharingPhone, let fact = myFacts.get(.phone) {
          includedFacts.append(fact)
        }
        
        let _ = try self.messenger.e2e.get()!.requestAuthenticatedChannel(
          partner: .live(self.contact.marshaled!),
          myFacts: includedFacts
Bruno Muniz's avatar
Bruno Muniz committed
        
        self.contact.authStatus = .requested
        try self.dbManager.getDB().saveContact(self.contact)
Bruno Muniz's avatar
Bruno Muniz committed
        
        self.hudManager.hide()
Bruno Muniz's avatar
Bruno Muniz committed
        self.popRelay.send()
      } catch {
        self.contact.authStatus = .requestFailed
        _ = try? self.dbManager.getDB().saveContact(self.contact)
        self.hudManager.show(.init(error: error))
Bruno Muniz's avatar
Bruno Muniz committed
      }
Bruno Muniz's avatar
Bruno Muniz committed
    }
Bruno Muniz's avatar
Bruno Muniz committed
  }
  
  func didTapRequest(with nickname: String) {
Bruno Muniz's avatar
Bruno Muniz committed
    contact.nickname = nickname
    contact.authStatus = .requesting
    
    backgroundScheduler.schedule { [weak self] in
Bruno Muniz's avatar
Bruno Muniz committed
      guard let self else { return }
Bruno Muniz's avatar
Bruno Muniz committed
      
      do {
        try self.dbManager.getDB().saveContact(self.contact)
Bruno Muniz's avatar
Bruno Muniz committed
        
        var includedFacts: [Fact] = []
        let myFacts = try self.messenger.ud.get()!.getFacts()
        
        if let fact = myFacts.get(.username) {
          includedFacts.append(fact)
Bruno Muniz's avatar
Bruno Muniz committed
        }
Bruno Muniz's avatar
Bruno Muniz committed
        
        if self.sharingEmail, let fact = myFacts.get(.email) {
          includedFacts.append(fact)
Bruno Muniz's avatar
Bruno Muniz committed
        }
Bruno Muniz's avatar
Bruno Muniz committed
        
        if self.sharingPhone, let fact = myFacts.get(.phone) {
          includedFacts.append(fact)
Bruno Muniz's avatar
Bruno Muniz committed
        }
Bruno Muniz's avatar
Bruno Muniz committed
        
        let _ = try self.messenger.e2e.get()!.requestAuthenticatedChannel(
          partner: .live(self.contact.marshaled!),
          myFacts: includedFacts
        )
        
        self.contact.authStatus = .requested
        try self.dbManager.getDB().saveContact(self.contact)
Bruno Muniz's avatar
Bruno Muniz committed
        
        self.hudManager.hide()
Bruno Muniz's avatar
Bruno Muniz committed
        self.successRelay.send()
      } catch {
        self.contact.authStatus = .requestFailed
        _ = try? self.dbManager.getDB().saveContact(self.contact)
        self.hudManager.show(.init(error: error))
Bruno Muniz's avatar
Bruno Muniz committed
      }
Bruno Muniz's avatar
Bruno Muniz committed
    }
Bruno Muniz's avatar
Bruno Muniz committed
  }
  
  func didTapAccept(_ nickname: String) {
Bruno Muniz's avatar
Bruno Muniz committed
    contact.nickname = nickname
    contact.authStatus = .confirming
    
    backgroundScheduler.schedule { [weak self] in
Bruno Muniz's avatar
Bruno Muniz committed
      guard let self else { return }
Bruno Muniz's avatar
Bruno Muniz committed
      
      do {
        try self.dbManager.getDB().saveContact(self.contact)
Bruno Muniz's avatar
Bruno Muniz committed
        
        let _ = try self.messenger.e2e.get()!.confirmReceivedRequest(partner: XXClient.Contact.live(self.contact.marshaled!))
        
        self.contact.authStatus = .friend
        try self.dbManager.getDB().saveContact(self.contact)
Bruno Muniz's avatar
Bruno Muniz committed
        
        self.hudManager.hide()
Bruno Muniz's avatar
Bruno Muniz committed
        self.popRelay.send()
      } catch {
        self.contact.authStatus = .confirmationFailed
        _ = try? self.dbManager.getDB().saveContact(self.contact)
        self.hudManager.show(.init(error: error))
Bruno Muniz's avatar
Bruno Muniz committed
      }
Bruno Muniz's avatar
Bruno Muniz committed
    }
Bruno Muniz's avatar
Bruno Muniz committed
  }
Bruno Muniz's avatar
Bruno Muniz committed
}