Refactor verified alert to use edit menu
This commit is contained in:
parent
72873fbfc1
commit
197e180ccd
|
@ -51,10 +51,6 @@
|
||||||
"clean_cache": {
|
"clean_cache": {
|
||||||
"title": "Clean Cache",
|
"title": "Clean Cache",
|
||||||
"message": "Successfully cleaned %s cache."
|
"message": "Successfully cleaned %s cache."
|
||||||
},
|
|
||||||
"verified": {
|
|
||||||
"title": "Verified",
|
|
||||||
"message": "Ownership of this link was checked on %s"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"controls": {
|
"controls": {
|
||||||
|
@ -442,6 +438,10 @@
|
||||||
"placeholder": {
|
"placeholder": {
|
||||||
"label": "Label",
|
"label": "Label",
|
||||||
"content": "Content"
|
"content": "Content"
|
||||||
|
},
|
||||||
|
"verified": {
|
||||||
|
"short": "Verified at %s",
|
||||||
|
"long": "Ownership of this link was checked on %s"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"segmented_control": {
|
"segmented_control": {
|
||||||
|
|
|
@ -67,14 +67,17 @@ extension ProfileFieldSection {
|
||||||
}
|
}
|
||||||
cell.backgroundConfiguration = backgroundConfiguration
|
cell.backgroundConfiguration = backgroundConfiguration
|
||||||
|
|
||||||
// set checkmark
|
// set checkmark and edit menu label
|
||||||
cell.checkmark.isHidden = true
|
cell.checkmark.isHidden = true
|
||||||
|
cell.checkmarkPopoverString = nil
|
||||||
if let verifiedAt = field.verifiedAt.value {
|
if let verifiedAt = field.verifiedAt.value {
|
||||||
cell.checkmark.isHidden = false
|
cell.checkmark.isHidden = false
|
||||||
let formatter = DateFormatter()
|
let formatter = DateFormatter()
|
||||||
formatter.dateStyle = .medium
|
formatter.dateStyle = .medium
|
||||||
formatter.timeStyle = .short
|
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
|
cell.delegate = configuration.profileFieldCollectionViewCellDelegate
|
||||||
|
|
|
@ -14,11 +14,6 @@ import MastodonLocalization
|
||||||
|
|
||||||
protocol ProfileFieldCollectionViewCellDelegate: AnyObject {
|
protocol ProfileFieldCollectionViewCellDelegate: AnyObject {
|
||||||
func profileFieldCollectionViewCell(_ cell: ProfileFieldCollectionViewCell, metaLebel: MetaLabel, didSelectMeta meta: Meta)
|
func profileFieldCollectionViewCell(_ cell: ProfileFieldCollectionViewCell, metaLebel: MetaLabel, didSelectMeta meta: Meta)
|
||||||
func profileFieldCollectionViewCell(_ cell: ProfileFieldCollectionViewCell, didTapAction: ProfileFieldCollectionViewCellAction)
|
|
||||||
}
|
|
||||||
|
|
||||||
enum ProfileFieldCollectionViewCellAction {
|
|
||||||
case Checkmark
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final class ProfileFieldCollectionViewCell: UICollectionViewCell {
|
final class ProfileFieldCollectionViewCell: UICollectionViewCell {
|
||||||
|
@ -32,7 +27,14 @@ final class ProfileFieldCollectionViewCell: UICollectionViewCell {
|
||||||
let valueMetaLabel = MetaLabel(style: .profileFieldValue)
|
let valueMetaLabel = MetaLabel(style: .profileFieldValue)
|
||||||
|
|
||||||
let checkmark = UIImageView(image: Asset.Editing.checkmark.image.withRenderingMode(.alwaysTemplate))
|
let checkmark = UIImageView(image: Asset.Editing.checkmark.image.withRenderingMode(.alwaysTemplate))
|
||||||
|
var checkmarkPopoverString: String? = nil;
|
||||||
let tapGesture = UITapGestureRecognizer();
|
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() {
|
override func prepareForReuse() {
|
||||||
super.prepareForReuse()
|
super.prepareForReuse()
|
||||||
|
@ -62,6 +64,9 @@ extension ProfileFieldCollectionViewCell {
|
||||||
tapGesture.addTarget(self, action: #selector(ProfileFieldCollectionViewCell.didTapCheckmark(_:)))
|
tapGesture.addTarget(self, action: #selector(ProfileFieldCollectionViewCell.didTapCheckmark(_:)))
|
||||||
checkmark.addGestureRecognizer(tapGesture)
|
checkmark.addGestureRecognizer(tapGesture)
|
||||||
checkmark.isUserInteractionEnabled = true
|
checkmark.isUserInteractionEnabled = true
|
||||||
|
if #available(iOS 16, *) {
|
||||||
|
checkmark.addInteraction(editMenuInteraction)
|
||||||
|
}
|
||||||
|
|
||||||
// containerStackView: V - [ metaContainer | plainContainer ]
|
// containerStackView: V - [ metaContainer | plainContainer ]
|
||||||
let containerStackView = UIStackView()
|
let containerStackView = UIStackView()
|
||||||
|
@ -99,10 +104,42 @@ extension ProfileFieldCollectionViewCell {
|
||||||
valueMetaLabel.linkDelegate = self
|
valueMetaLabel.linkDelegate = self
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc public func didTapCheckmark(_: UITapGestureRecognizer) {
|
@objc public func didTapCheckmark(_ recognizer: UITapGestureRecognizer) {
|
||||||
delegate?.profileFieldCollectionViewCell(self, didTapAction: .Checkmark)
|
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
|
// MARK: - MetaLabelDelegate
|
||||||
|
@ -112,3 +149,16 @@ extension ProfileFieldCollectionViewCell: MetaLabelDelegate {
|
||||||
delegate?.profileFieldCollectionViewCell(self, metaLebel: metaLabel, didSelectMeta: meta)
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -16,7 +16,6 @@ import MastodonCore
|
||||||
|
|
||||||
protocol ProfileAboutViewControllerDelegate: AnyObject {
|
protocol ProfileAboutViewControllerDelegate: AnyObject {
|
||||||
func profileAboutViewController(_ viewController: ProfileAboutViewController, profileFieldCollectionViewCell: ProfileFieldCollectionViewCell, metaLabel: MetaLabel, didSelectMeta meta: Meta)
|
func profileAboutViewController(_ viewController: ProfileAboutViewController, profileFieldCollectionViewCell: ProfileFieldCollectionViewCell, metaLabel: MetaLabel, didSelectMeta meta: Meta)
|
||||||
func profileAboutViewController(_ viewController: ProfileAboutViewController, didTapCheckmarkFor field: ProfileFieldItem.FieldValue)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final class ProfileAboutViewController: UIViewController {
|
final class ProfileAboutViewController: UIViewController {
|
||||||
|
@ -153,21 +152,6 @@ extension ProfileAboutViewController: ProfileFieldCollectionViewCellDelegate {
|
||||||
func profileFieldCollectionViewCell(_ cell: ProfileFieldCollectionViewCell, metaLebel: MetaLabel, didSelectMeta meta: Meta) {
|
func profileFieldCollectionViewCell(_ cell: ProfileFieldCollectionViewCell, metaLebel: MetaLabel, didSelectMeta meta: Meta) {
|
||||||
delegate?.profileAboutViewController(self, profileFieldCollectionViewCell: cell, metaLabel: metaLebel, didSelectMeta: 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
|
// MARK: - ProfileFieldEditCollectionViewCellDelegate
|
||||||
|
|
|
@ -854,22 +854,6 @@ extension ProfileViewController: ProfileAboutViewControllerDelegate {
|
||||||
) {
|
) {
|
||||||
handleMetaPress(meta)
|
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
|
// MARK: - MastodonMenuDelegate
|
||||||
|
|
|
@ -87,14 +87,6 @@ public enum L10n {
|
||||||
/// Sign Up Failure
|
/// Sign Up Failure
|
||||||
public static let title = L10n.tr("Localizable", "Common.Alerts.SignUpFailure.Title")
|
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 {
|
public enum VoteFailure {
|
||||||
/// The poll has ended
|
/// The poll has ended
|
||||||
public static let pollEnded = L10n.tr("Localizable", "Common.Alerts.VoteFailure.PollEnded")
|
public static let pollEnded = L10n.tr("Localizable", "Common.Alerts.VoteFailure.PollEnded")
|
||||||
|
@ -721,6 +713,16 @@ public enum L10n {
|
||||||
/// Label
|
/// Label
|
||||||
public static let label = L10n.tr("Localizable", "Scene.Profile.Fields.Placeholder.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 {
|
public enum Header {
|
||||||
/// Follows You
|
/// Follows You
|
||||||
|
|
|
@ -22,8 +22,6 @@ Please check your internet connection.";
|
||||||
"Common.Alerts.SignOut.Message" = "Are you sure you want to sign out?";
|
"Common.Alerts.SignOut.Message" = "Are you sure you want to sign out?";
|
||||||
"Common.Alerts.SignOut.Title" = "Sign Out";
|
"Common.Alerts.SignOut.Title" = "Sign Out";
|
||||||
"Common.Alerts.SignUpFailure.Title" = "Sign Up Failure";
|
"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.PollEnded" = "The poll has ended";
|
||||||
"Common.Alerts.VoteFailure.Title" = "Vote Failure";
|
"Common.Alerts.VoteFailure.Title" = "Vote Failure";
|
||||||
"Common.Controls.Actions.Add" = "Add";
|
"Common.Controls.Actions.Add" = "Add";
|
||||||
|
@ -259,6 +257,8 @@ uploaded to Mastodon.";
|
||||||
"Scene.Profile.Fields.AddRow" = "Add Row";
|
"Scene.Profile.Fields.AddRow" = "Add Row";
|
||||||
"Scene.Profile.Fields.Placeholder.Content" = "Content";
|
"Scene.Profile.Fields.Placeholder.Content" = "Content";
|
||||||
"Scene.Profile.Fields.Placeholder.Label" = "Label";
|
"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.Header.FollowsYou" = "Follows You";
|
||||||
"Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Message" = "Confirm to block %@";
|
"Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Message" = "Confirm to block %@";
|
||||||
"Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Title" = "Block Account";
|
"Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Title" = "Block Account";
|
||||||
|
|
Loading…
Reference in New Issue