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

import SignalServiceKit
public import SignalUI

public class PrivateStoryNameSettingsViewController: OWSTableViewController2 {

    let thread: TSPrivateStoryThread
    let completionHandler: () -> Void

    var hasPendingChanges: Bool { nameTextField.text?.filterForDisplay != thread.name }

    init(thread: TSPrivateStoryThread, completionHandler: @escaping () -> Void) {
        self.thread = thread
        self.completionHandler = completionHandler

        super.init()

        self.shouldAvoidKeyboard = true
    }

    // MARK: - View Lifecycle

    override public func viewDidLoad() {
        super.viewDidLoad()

        title = thread.name

        updateTableContents()
        updateNavigationBar()
    }

    override public func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        nameTextField.becomeFirstResponder()
    }

    // MARK: -

    private lazy var nameTextField: UITextField = {
        let textField = UITextField()

        textField.text = thread.name
        textField.font = .dynamicTypeBody
        textField.backgroundColor = .clear
        textField.placeholder = OWSLocalizedString(
            "NEW_PRIVATE_STORY_NAME_PLACEHOLDER",
            comment: "Placeholder text for a new private story name",
        )
        textField.returnKeyType = .done
        textField.delegate = self
        textField.addTarget(self, action: #selector(textFieldDidChange), for: .editingChanged)

        return textField
    }()

    override public func themeDidChange() {
        super.themeDidChange()

        nameTextField.textColor = Theme.primaryTextColor
    }

    private func updateNavigationBar() {
        navigationItem.leftBarButtonItem = .cancelButton { [weak self] in
            self?.didTapCancel()
        }

        navigationItem.rightBarButtonItem = .doneButton { [weak self] in
            self?.didTapDone()
        }
        navigationItem.rightBarButtonItem?.isEnabled = hasPendingChanges
    }

    private func updateTableContents() {
        let contents = OWSTableContents()

        let nameSection = OWSTableSection()
        nameSection.add(.init(
            customCellBlock: { [weak self] in
                let cell = OWSTableItem.newCell()
                cell.selectionStyle = .none
                guard let self else { return cell }

                cell.contentView.addSubview(self.nameTextField)
                self.nameTextField.autoPinEdgesToSuperviewMargins()

                return cell
            },
            actionBlock: {},
        ))
        contents.add(nameSection)

        self.contents = contents
    }

    // MARK: - Actions

    private func didTapCancel() {
        AssertIsOnMainThread()

        if hasPendingChanges {
            OWSActionSheets.showPendingChangesActionSheet {
                self.dismiss(animated: true)
            }
        } else {
            dismiss(animated: true)
        }
    }

    private func didTapDone() {
        AssertIsOnMainThread()

        guard let name = nameTextField.text?.nilIfEmpty?.filterForDisplay else {
            return showMissingNameAlert()
        }
        SSKEnvironment.shared.databaseStorageRef.asyncWrite { transaction in
            self.thread.updateWithName(name, updateStorageService: true, transaction: transaction)
        } completion: { [weak self] in
            guard let self else { return }
            self.dismiss(animated: true)
        }
    }

    @objc
    private func textFieldDidChange(_ textField: UITextField) {
        updateNavigationBar()
    }

    override public func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
        super.dismiss(animated: flag, completion: completion)
        completionHandler()
    }

    public func showMissingNameAlert() {
        AssertIsOnMainThread()

        OWSActionSheets.showActionSheet(
            title: OWSLocalizedString(
                "NEW_PRIVATE_STORY_MISSING_NAME_ALERT_TITLE",
                comment: "Title for error alert indicating that a story name is required.",
            ),
            message: OWSLocalizedString(
                "NEW_PRIVATE_STORY_MISSING_NAME_ALERT_MESSAGE",
                comment: "Message for error alert indicating that a story name is required.",
            ),
        )
    }
}

extension PrivateStoryNameSettingsViewController: UITextFieldDelegate {
    public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        if string == "\n" {
            if hasPendingChanges {
                didTapDone()
            } else {
                didTapCancel()
            }
            return false
        } else {
            return true
        }
    }
}