263 lines
8.2 KiB
Swift
263 lines
8.2 KiB
Swift
//
|
|
// Copyright (c) 2021 Open Whisper Systems. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
|
|
protocol GroupDescriptionViewControllerDelegate: class {
|
|
func groupDescriptionViewControllerDidComplete(groupDescription: String?)
|
|
}
|
|
|
|
@objc
|
|
class GroupDescriptionViewController: OWSTableViewController2 {
|
|
private let helper: GroupAttributesEditorHelper
|
|
|
|
weak var descriptionDelegate: GroupDescriptionViewControllerDelegate?
|
|
|
|
private let options: Options
|
|
struct Options: OptionSet {
|
|
let rawValue: Int
|
|
|
|
static let updateImmediately = Options(rawValue: 1 << 0)
|
|
static let editable = Options(rawValue: 1 << 1)
|
|
}
|
|
|
|
var isEditable: Bool { options.contains(.editable) }
|
|
|
|
@objc
|
|
convenience init(groupModel: TSGroupModel) {
|
|
self.init(groupModel: groupModel, options: [])
|
|
}
|
|
|
|
convenience init(
|
|
groupModel: TSGroupModel,
|
|
groupDescriptionCurrent: String? = nil,
|
|
options: Options
|
|
) {
|
|
self.init(
|
|
helper: GroupAttributesEditorHelper(groupModel: groupModel),
|
|
groupDescriptionCurrent: groupDescriptionCurrent,
|
|
options: options
|
|
)
|
|
}
|
|
|
|
required init(
|
|
helper: GroupAttributesEditorHelper,
|
|
groupDescriptionCurrent: String? = nil,
|
|
options: Options = []
|
|
) {
|
|
self.helper = helper
|
|
self.options = options
|
|
|
|
if let groupDescriptionCurrent = groupDescriptionCurrent {
|
|
self.helper.groupDescriptionOriginal = groupDescriptionCurrent
|
|
}
|
|
|
|
super.init()
|
|
|
|
shouldAvoidKeyboard = true
|
|
}
|
|
|
|
// MARK: -
|
|
|
|
override func viewDidLoad() {
|
|
super.viewDidLoad()
|
|
|
|
helper.delegate = self
|
|
helper.buildContents()
|
|
|
|
updateNavigation()
|
|
updateTableContents()
|
|
}
|
|
|
|
override func applyTheme() {
|
|
super.applyTheme()
|
|
|
|
helper.descriptionTextView.linkTextAttributes = [
|
|
.foregroundColor: Theme.primaryTextColor,
|
|
.underlineStyle: NSUnderlineStyle.single.rawValue
|
|
]
|
|
}
|
|
|
|
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
|
|
super.viewWillTransition(to: size, with: coordinator)
|
|
|
|
coordinator.animate(alongsideTransition: { (_) in
|
|
self.helper.descriptionTextView.scrollToFocus(in: self.tableView, animated: true)
|
|
}, completion: nil)
|
|
}
|
|
|
|
// Don't allow interactive dismiss when there are unsaved changes.
|
|
override var isModalInPresentation: Bool {
|
|
get { helper.hasUnsavedChanges }
|
|
set {}
|
|
}
|
|
|
|
private func updateNavigation() {
|
|
let currentGlyphCount = (helper.groupDescriptionCurrent ?? "").glyphCount
|
|
let remainingGlyphCount = max(0, GroupManager.maxGroupDescriptionGlyphCount - currentGlyphCount)
|
|
|
|
if !isEditable, let groupName = helper.groupNameCurrent {
|
|
title = groupName
|
|
} else if isEditable, remainingGlyphCount <= 100 {
|
|
let titleFormat = NSLocalizedString(
|
|
"GROUP_DESCRIPTION_VIEW_TITLE_FORMAT",
|
|
comment: "Title for the group description view. Embeds {{ the number of characters that can be added to the description without hitting the length limit }}."
|
|
)
|
|
title = String(format: titleFormat, OWSFormat.formatInt(remainingGlyphCount))
|
|
} else {
|
|
title = NSLocalizedString(
|
|
"GROUP_DESCRIPTION_VIEW_TITLE",
|
|
comment: "Title for the group description view."
|
|
)
|
|
}
|
|
|
|
if isEditable {
|
|
navigationItem.leftBarButtonItem = UIBarButtonItem(
|
|
barButtonSystemItem: .cancel,
|
|
target: self,
|
|
action: #selector(didTapCancel),
|
|
accessibilityIdentifier: "cancel_button"
|
|
)
|
|
} else {
|
|
navigationItem.leftBarButtonItem = UIBarButtonItem(
|
|
barButtonSystemItem: .done,
|
|
target: self,
|
|
action: #selector(didTapDone),
|
|
accessibilityIdentifier: "done_button"
|
|
)
|
|
}
|
|
|
|
if helper.hasUnsavedChanges {
|
|
owsAssertDebug(isEditable)
|
|
if options.contains(.updateImmediately) {
|
|
navigationItem.rightBarButtonItem = UIBarButtonItem(
|
|
title: CommonStrings.setButton,
|
|
style: .done,
|
|
target: self,
|
|
action: #selector(didTapSet),
|
|
accessibilityIdentifier: "set_button"
|
|
)
|
|
} else {
|
|
navigationItem.rightBarButtonItem = UIBarButtonItem(
|
|
barButtonSystemItem: .done,
|
|
target: self,
|
|
action: #selector(didTapDone),
|
|
accessibilityIdentifier: "done_button"
|
|
)
|
|
}
|
|
} else {
|
|
navigationItem.rightBarButtonItem = nil
|
|
}
|
|
}
|
|
|
|
public override func viewWillAppear(_ animated: Bool) {
|
|
super.viewWillAppear(animated)
|
|
|
|
updateNavigation()
|
|
|
|
if isEditable {
|
|
helper.descriptionTextView.becomeFirstResponder()
|
|
}
|
|
}
|
|
|
|
func updateTableContents() {
|
|
let contents = OWSTableContents()
|
|
|
|
let descriptionTextView = helper.descriptionTextView
|
|
let isEditable = self.isEditable
|
|
|
|
let section = OWSTableSection()
|
|
section.add(.init(
|
|
customCellBlock: {
|
|
let cell = OWSTableItem.newCell()
|
|
|
|
cell.selectionStyle = .none
|
|
|
|
cell.contentView.addSubview(descriptionTextView)
|
|
descriptionTextView.autoPinEdgesToSuperviewMargins()
|
|
|
|
if isEditable {
|
|
descriptionTextView.isEditable = true
|
|
descriptionTextView.dataDetectorTypes = []
|
|
descriptionTextView.autoSetDimension(.height, toSize: 74, relation: .greaterThanOrEqual)
|
|
} else {
|
|
descriptionTextView.isEditable = false
|
|
descriptionTextView.dataDetectorTypes = .all
|
|
}
|
|
|
|
return cell
|
|
},
|
|
actionBlock: {
|
|
if isEditable {
|
|
descriptionTextView.becomeFirstResponder()
|
|
}
|
|
}
|
|
))
|
|
|
|
if isEditable {
|
|
section.footerTitle = NSLocalizedString(
|
|
"GROUP_DESCRIPTION_VIEW_EDIT_FOOTER",
|
|
comment: "Footer text when editing the group description"
|
|
)
|
|
}
|
|
|
|
contents.addSection(section)
|
|
|
|
self.contents = contents
|
|
}
|
|
|
|
@objc
|
|
func didTapCancel() {
|
|
guard helper.hasUnsavedChanges else {
|
|
dismiss(animated: true)
|
|
return
|
|
}
|
|
|
|
OWSActionSheets.showPendingChangesActionSheet(discardAction: { [weak self] in
|
|
self?.dismiss(animated: true)
|
|
})
|
|
}
|
|
|
|
@objc
|
|
func didTapDone() {
|
|
helper.descriptionTextView.acceptAutocorrectSuggestion()
|
|
descriptionDelegate?.groupDescriptionViewControllerDidComplete(groupDescription: helper.groupDescriptionCurrent)
|
|
dismiss(animated: true)
|
|
}
|
|
|
|
@objc
|
|
func didTapSet() {
|
|
guard isEditable, helper.hasUnsavedChanges else {
|
|
return owsFailDebug("Unexpectedly trying to set")
|
|
}
|
|
|
|
helper.updateGroupIfNecessary(fromViewController: self) { [weak self] in
|
|
guard let self = self else { return }
|
|
self.descriptionDelegate?.groupDescriptionViewControllerDidComplete(
|
|
groupDescription: self.helper.groupDescriptionCurrent
|
|
)
|
|
self.dismiss(animated: true)
|
|
}
|
|
}
|
|
}
|
|
|
|
extension GroupDescriptionViewController: GroupAttributesEditorHelperDelegate {
|
|
func groupAttributesEditorContentsDidChange() {
|
|
updateNavigation()
|
|
|
|
// Kick the tableview so it recalculates sizes
|
|
UIView.performWithoutAnimation {
|
|
tableView.performBatchUpdates(nil) { (_) in
|
|
// And when the size changes have finished, make sure we're scrolled
|
|
// to the focused line
|
|
self.helper.descriptionTextView.scrollToFocus(in: self.tableView, animated: false)
|
|
}
|
|
}
|
|
}
|
|
|
|
func groupAttributesEditorSelectionDidChange() {
|
|
helper.descriptionTextView.scrollToFocus(in: tableView, animated: true)
|
|
}
|
|
}
|