Refactor verified alert to use edit menu

This commit is contained in:
David Godfrey 2022-11-12 14:42:00 +00:00
parent 72873fbfc1
commit 197e180ccd
7 changed files with 78 additions and 55 deletions

View File

@ -51,10 +51,6 @@
"clean_cache": {
"title": "Clean Cache",
"message": "Successfully cleaned %s cache."
},
"verified": {
"title": "Verified",
"message": "Ownership of this link was checked on %s"
}
},
"controls": {
@ -442,6 +438,10 @@
"placeholder": {
"label": "Label",
"content": "Content"
},
"verified": {
"short": "Verified at %s",
"long": "Ownership of this link was checked on %s"
}
},
"segmented_control": {

View File

@ -67,14 +67,17 @@ extension ProfileFieldSection {
}
cell.backgroundConfiguration = backgroundConfiguration
// set checkmark
// set checkmark and edit menu label
cell.checkmark.isHidden = true
cell.checkmarkPopoverString = nil
if let verifiedAt = field.verifiedAt.value {
cell.checkmark.isHidden = false
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.timeStyle = .short
cell.checkmark.accessibilityLabel = L10n.Common.Alerts.Verified.message(formatter.string(from: verifiedAt))
let dateString = formatter.string(from: verifiedAt)
cell.checkmark.accessibilityLabel = L10n.Scene.Profile.Fields.Verified.long(dateString)
cell.checkmarkPopoverString = L10n.Scene.Profile.Fields.Verified.short(dateString)
}
cell.delegate = configuration.profileFieldCollectionViewCellDelegate

View File

@ -14,11 +14,6 @@ import MastodonLocalization
protocol ProfileFieldCollectionViewCellDelegate: AnyObject {
func profileFieldCollectionViewCell(_ cell: ProfileFieldCollectionViewCell, metaLebel: MetaLabel, didSelectMeta meta: Meta)
func profileFieldCollectionViewCell(_ cell: ProfileFieldCollectionViewCell, didTapAction: ProfileFieldCollectionViewCellAction)
}
enum ProfileFieldCollectionViewCellAction {
case Checkmark
}
final class ProfileFieldCollectionViewCell: UICollectionViewCell {
@ -32,7 +27,14 @@ final class ProfileFieldCollectionViewCell: UICollectionViewCell {
let valueMetaLabel = MetaLabel(style: .profileFieldValue)
let checkmark = UIImageView(image: Asset.Editing.checkmark.image.withRenderingMode(.alwaysTemplate))
var checkmarkPopoverString: String? = nil;
let tapGesture = UITapGestureRecognizer();
private var _editMenuInteraction: Any? = nil
@available(iOS 16, *)
fileprivate var editMenuInteraction: UIEditMenuInteraction {
_editMenuInteraction = _editMenuInteraction ?? UIEditMenuInteraction(delegate: self)
return _editMenuInteraction as! UIEditMenuInteraction
}
override func prepareForReuse() {
super.prepareForReuse()
@ -62,6 +64,9 @@ extension ProfileFieldCollectionViewCell {
tapGesture.addTarget(self, action: #selector(ProfileFieldCollectionViewCell.didTapCheckmark(_:)))
checkmark.addGestureRecognizer(tapGesture)
checkmark.isUserInteractionEnabled = true
if #available(iOS 16, *) {
checkmark.addInteraction(editMenuInteraction)
}
// containerStackView: V - [ metaContainer | plainContainer ]
let containerStackView = UIStackView()
@ -99,10 +104,42 @@ extension ProfileFieldCollectionViewCell {
valueMetaLabel.linkDelegate = self
}
@objc public func didTapCheckmark(_: UITapGestureRecognizer) {
delegate?.profileFieldCollectionViewCell(self, didTapAction: .Checkmark)
@objc public func didTapCheckmark(_ recognizer: UITapGestureRecognizer) {
if #available(iOS 16, *) {
editMenuInteraction.presentEditMenu(with: UIEditMenuConfiguration(identifier: nil, sourcePoint: recognizer.location(in: checkmark)))
} else {
guard let editMenuLabel = checkmarkPopoverString else { return }
self.isUserInteractionEnabled = true
self.becomeFirstResponder()
UIMenuController.shared.menuItems = [
UIMenuItem(
title: editMenuLabel,
action: #selector(dismissVerifiedMenu)
)
]
UIMenuController.shared.showMenu(from: checkmark, rect: checkmark.bounds)
}
}
}
// UIMenuController boilerplate
@available(iOS, deprecated: 16, message: "Can be removed when target version is >=16 -- boilerplate to maintain compatibility with UIMenuController")
extension ProfileFieldCollectionViewCell {
override var canBecomeFirstResponder: Bool { true }
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
if action == #selector(dismissVerifiedMenu) {
return true
}
return super.canPerformAction(action, withSender: sender)
}
@objc public func dismissVerifiedMenu() {
UIMenuController.shared.hideMenu()
}
}
// MARK: - MetaLabelDelegate
@ -112,3 +149,16 @@ extension ProfileFieldCollectionViewCell: MetaLabelDelegate {
delegate?.profileFieldCollectionViewCell(self, metaLebel: metaLabel, didSelectMeta: meta)
}
}
// MARK: UIEditMenuInteractionDelegate
@available(iOS 16.0, *)
extension ProfileFieldCollectionViewCell: UIEditMenuInteractionDelegate {
func editMenuInteraction(_ interaction: UIEditMenuInteraction, menuFor configuration: UIEditMenuConfiguration, suggestedActions: [UIMenuElement]) -> UIMenu? {
guard let editMenuLabel = checkmarkPopoverString else { return UIMenu(children: []) }
return UIMenu(children: [UIAction(title: editMenuLabel) { _ in return }])
}
func editMenuInteraction(_ interaction: UIEditMenuInteraction, targetRectFor configuration: UIEditMenuConfiguration) -> CGRect {
return checkmark.frame
}
}

View File

@ -16,7 +16,6 @@ import MastodonCore
protocol ProfileAboutViewControllerDelegate: AnyObject {
func profileAboutViewController(_ viewController: ProfileAboutViewController, profileFieldCollectionViewCell: ProfileFieldCollectionViewCell, metaLabel: MetaLabel, didSelectMeta meta: Meta)
func profileAboutViewController(_ viewController: ProfileAboutViewController, didTapCheckmarkFor field: ProfileFieldItem.FieldValue)
}
final class ProfileAboutViewController: UIViewController {
@ -153,21 +152,6 @@ extension ProfileAboutViewController: ProfileFieldCollectionViewCellDelegate {
func profileFieldCollectionViewCell(_ cell: ProfileFieldCollectionViewCell, metaLebel: MetaLabel, didSelectMeta meta: Meta) {
delegate?.profileAboutViewController(self, profileFieldCollectionViewCell: cell, metaLabel: metaLebel, didSelectMeta: meta)
}
func profileFieldCollectionViewCell(_ cell: ProfileFieldCollectionViewCell, didTapAction action: ProfileFieldCollectionViewCellAction) {
guard let diffableDataSource = viewModel.diffableDataSource else { return }
guard let indexPath = collectionView.indexPath(for: cell) else { return }
guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return }
switch item {
case .field(let field):
delegate?.profileAboutViewController(self, didTapCheckmarkFor: field)
case .addEntry: fallthrough
case .editField: fallthrough
case .noResult:
break
}
}
}
// MARK: - ProfileFieldEditCollectionViewCellDelegate

View File

@ -854,22 +854,6 @@ extension ProfileViewController: ProfileAboutViewControllerDelegate {
) {
handleMetaPress(meta)
}
func profileAboutViewController(_ viewController: ProfileAboutViewController, didTapCheckmarkFor field: ProfileFieldItem.FieldValue) {
guard let verifiedAt = field.verifiedAt.value else {
return
}
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.timeStyle = .short
let alert = UIAlertController(title: L10n.Common.Alerts.Verified.title, message: L10n.Common.Alerts.Verified.message(formatter.string(from: verifiedAt)), preferredStyle: .alert)
alert.addAction(UIAlertAction(title: L10n.Common.Controls.Actions.ok, style: .default) { _ in
alert.dismiss(animated: true)
})
self.present(alert, animated: true)
}
}
// MARK: - MastodonMenuDelegate

View File

@ -87,14 +87,6 @@ public enum L10n {
/// Sign Up Failure
public static let title = L10n.tr("Localizable", "Common.Alerts.SignUpFailure.Title")
}
public enum Verified {
/// Ownership of this link was checked on %s
public static func message(_ p1: UnsafePointer<CChar>) -> String {
return L10n.tr("Localizable", "Common.Alerts.Verified.Message", p1)
}
/// Verified
public static let title = L10n.tr("Localizable", "Common.Alerts.Verified.Title")
}
public enum VoteFailure {
/// The poll has ended
public static let pollEnded = L10n.tr("Localizable", "Common.Alerts.VoteFailure.PollEnded")
@ -721,6 +713,16 @@ public enum L10n {
/// Label
public static let label = L10n.tr("Localizable", "Scene.Profile.Fields.Placeholder.Label")
}
public enum Verified {
/// Ownership of this link was checked on %s
public static func long(_ p1: UnsafePointer<CChar>) -> String {
return L10n.tr("Localizable", "Scene.Profile.Fields.Verified.Long", p1)
}
/// Verified at %s
public static func short(_ p1: UnsafePointer<CChar>) -> String {
return L10n.tr("Localizable", "Scene.Profile.Fields.Verified.Short", p1)
}
}
}
public enum Header {
/// Follows You

View File

@ -22,8 +22,6 @@ Please check your internet connection.";
"Common.Alerts.SignOut.Message" = "Are you sure you want to sign out?";
"Common.Alerts.SignOut.Title" = "Sign Out";
"Common.Alerts.SignUpFailure.Title" = "Sign Up Failure";
"Common.Alerts.Verified.Title" = "Verified";
"Common.Alerts.Verified.Message" = "Ownership of this link was checked on %s";
"Common.Alerts.VoteFailure.PollEnded" = "The poll has ended";
"Common.Alerts.VoteFailure.Title" = "Vote Failure";
"Common.Controls.Actions.Add" = "Add";
@ -259,6 +257,8 @@ uploaded to Mastodon.";
"Scene.Profile.Fields.AddRow" = "Add Row";
"Scene.Profile.Fields.Placeholder.Content" = "Content";
"Scene.Profile.Fields.Placeholder.Label" = "Label";
"Scene.Profile.Fields.Verified.Short" = "Verified at %s";
"Scene.Profile.Fields.Verified.Long" = "Ownership of this link was checked on %s";
"Scene.Profile.Header.FollowsYou" = "Follows You";
"Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Message" = "Confirm to block %@";
"Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Title" = "Block Account";