Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
signalapp
GitHub Repository: signalapp/Signal-iOS
Path: blob/main/Signal/src/ViewControllers/HomeView/Stories/Settings/PrivateStoryAddRecipientsSettingsViewController.swift
1 views
//
// Copyright 2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//

import Foundation
public import SignalServiceKit
public import SignalUI

public class PrivateStoryAddRecipientsSettingsViewController: BaseMemberViewController {
    let thread: TSPrivateStoryThread
    var recipientSet: OrderedSet<PickedRecipient> = []

    override public var hasUnsavedChanges: Bool { !recipientSet.orderedMembers.isEmpty }

    public init(thread: TSPrivateStoryThread) {
        self.thread = thread
        super.init()

        memberViewDelegate = self
    }

    // MARK: - View Lifecycle

    override public func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        updateBarButtons()
    }

    private func updateBarButtons() {
        navigationItem.rightBarButtonItem = .systemItem(.save) { [weak self] in
            self?.updatePressed()
        }
        navigationItem.rightBarButtonItem?.isEnabled = hasUnsavedChanges

        title = OWSLocalizedString(
            "PRIVATE_STORY_SETTINGS_ADD_VIEWER_BUTTON",
            comment: "Button to add a new viewer on the 'private story settings' view",
        )
    }

    // MARK: - Actions

    private func updatePressed() {
        AssertIsOnMainThread()

        let uniqueId = self.thread.uniqueId
        let newValues = self.recipientSet.orderedMembers.compactMap { $0.address?.serviceId }
        ModalActivityIndicatorViewController.presentAsInvisible(fromViewController: self) { modal in
            SSKEnvironment.shared.databaseStorageRef.asyncWrite { tx in
                guard
                    let storyThread = TSPrivateStoryThread.fetchPrivateStoryThreadViaCache(uniqueId: uniqueId, transaction: tx),
                    storyThread.storyViewMode == .explicit
                else {
                    // Conflict during the update; stop.
                    return
                }
                let recipientFetcher = DependenciesBridge.shared.recipientFetcher
                let recipientIds = newValues.map { recipientFetcher.fetchOrCreate(serviceId: $0, tx: tx).id }
                let storyRecipientManager = DependenciesBridge.shared.storyRecipientManager
                failIfThrows {
                    try storyRecipientManager.insertRecipientIds(recipientIds, for: storyThread, shouldUpdateStorageService: true, tx: tx)
                }
            } completion: {
                self.navigationController?.popViewController(animated: true) { modal.dismiss(animated: false) }
            }
        }
    }
}

// MARK: -

extension PrivateStoryAddRecipientsSettingsViewController: MemberViewDelegate {
    public var memberViewRecipientSet: OrderedSet<PickedRecipient> { recipientSet }

    public var memberViewHasUnsavedChanges: Bool { hasUnsavedChanges }

    public func memberViewRemoveRecipient(_ recipient: PickedRecipient) {
        recipientSet.remove(recipient)
        updateBarButtons()
    }

    public func memberViewAddRecipient(_ recipient: PickedRecipient) -> Bool {
        recipientSet.append(recipient)
        updateBarButtons()
        return true
    }

    public func memberViewShouldShowMemberCount() -> Bool { false }

    public func memberViewShouldAllowBlockedSelection() -> Bool { false }

    public func memberViewMemberCountForDisplay() -> Int { recipientSet.count }

    public func memberViewIsPreExistingMember(_ recipient: PickedRecipient, transaction: DBReadTransaction) -> Bool {
        guard let address = recipient.address else {
            return false
        }
        let recipientDatabaseTable = DependenciesBridge.shared.recipientDatabaseTable
        guard let recipient = recipientDatabaseTable.fetchRecipient(address: address, tx: transaction) else {
            return false
        }
        let storyRecipientStore = DependenciesBridge.shared.storyRecipientStore
        do {
            return try storyRecipientStore.doesStoryThreadId(thread.sqliteRowId!, containRecipientId: recipient.id, tx: transaction)
        } catch {
            Logger.warn("Couldn't check if member is already in story thread: \(error)")
            return false
        }
    }

    public func memberViewCustomIconNameForPickedMember(_ recipient: PickedRecipient) -> String? { nil }

    public func memberViewCustomIconColorForPickedMember(_ recipient: PickedRecipient) -> UIColor? { nil }

    public func memberViewDismiss() {
        navigationController?.popViewController(animated: true)
    }
}