From c3009d60099e1435f6f885cfe4c0629e5597efe2 Mon Sep 17 00:00:00 2001 From: David Godfrey Date: Fri, 11 Nov 2022 20:34:26 +0000 Subject: [PATCH 1/6] Add visual indication that a url has been validated in a profile's fields --- .../Diffiable/Profile/ProfileFieldItem.swift | 4 ++ .../Profile/ProfileFieldSection.swift | 11 ++++++ .../Cell/ProfileFieldCollectionViewCell.swift | 15 +++++++- .../Profile/About/ProfileAboutViewModel.swift | 7 ++-- .../Scene/Profile/About/Contents.json | 9 +++++ .../Contents.json | 38 +++++++++++++++++++ .../Contents.json | 38 +++++++++++++++++++ .../MastodonAsset/Generated/Assets.swift | 4 ++ 8 files changed, 121 insertions(+), 5 deletions(-) create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Profile/About/Contents.json create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Profile/About/bio.about.field.validated.background.colorset/Contents.json create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Profile/About/bio.about.field.validated.checkmark.colorset/Contents.json diff --git a/Mastodon/Diffiable/Profile/ProfileFieldItem.swift b/Mastodon/Diffiable/Profile/ProfileFieldItem.swift index 47848cc01..e33a2f883 100644 --- a/Mastodon/Diffiable/Profile/ProfileFieldItem.swift +++ b/Mastodon/Diffiable/Profile/ProfileFieldItem.swift @@ -23,6 +23,7 @@ extension ProfileFieldItem { var name: CurrentValueSubject var value: CurrentValueSubject + var verifiedAt: CurrentValueSubject let emojiMeta: MastodonContent.Emojis @@ -30,11 +31,13 @@ extension ProfileFieldItem { id: UUID = UUID(), name: String, value: String, + verifiedAt: Date?, emojiMeta: MastodonContent.Emojis ) { self.id = id self.name = CurrentValueSubject(name) self.value = CurrentValueSubject(value) + self.verifiedAt = CurrentValueSubject(verifiedAt) self.emojiMeta = emojiMeta } @@ -45,6 +48,7 @@ extension ProfileFieldItem { return lhs.id == rhs.id && lhs.name.value == rhs.name.value && lhs.value.value == rhs.value.value + && lhs.verifiedAt.value == rhs.verifiedAt.value && lhs.emojiMeta == rhs.emojiMeta } diff --git a/Mastodon/Diffiable/Profile/ProfileFieldSection.swift b/Mastodon/Diffiable/Profile/ProfileFieldSection.swift index 19771b5db..332916a02 100644 --- a/Mastodon/Diffiable/Profile/ProfileFieldSection.swift +++ b/Mastodon/Diffiable/Profile/ProfileFieldSection.swift @@ -8,6 +8,7 @@ import os import UIKit import Combine +import MastodonAsset import MastodonCore import MastodonMeta import MastodonLocalization @@ -57,7 +58,17 @@ extension ProfileFieldSection { // set background var backgroundConfiguration = UIBackgroundConfiguration.listPlainCell() backgroundConfiguration.backgroundColor = UIColor.secondarySystemBackground + if (field.verifiedAt.value != nil) { + backgroundConfiguration.backgroundColor = Asset.Scene.Profile.About.bioAboutFieldValidatedBackground.color + } cell.backgroundConfiguration = backgroundConfiguration + + // set checkmark + cell.checkmark.isHidden = true + if let verifiedAt = field.verifiedAt.value { + cell.checkmark.isHidden = false + cell.checkmark.accessibilityLabel = "Ownership of this link was checked on \(verifiedAt)" // TODO: I18N / L10N + } cell.delegate = configuration.profileFieldCollectionViewCellDelegate } diff --git a/Mastodon/Scene/Profile/About/Cell/ProfileFieldCollectionViewCell.swift b/Mastodon/Scene/Profile/About/Cell/ProfileFieldCollectionViewCell.swift index ed6f68fec..076b8373e 100644 --- a/Mastodon/Scene/Profile/About/Cell/ProfileFieldCollectionViewCell.swift +++ b/Mastodon/Scene/Profile/About/Cell/ProfileFieldCollectionViewCell.swift @@ -26,6 +26,8 @@ final class ProfileFieldCollectionViewCell: UICollectionViewCell { let keyMetaLabel = MetaLabel(style: .profileFieldName) let valueMetaLabel = MetaLabel(style: .profileFieldValue) + let checkmark = UIImageView(image: Asset.Editing.checkmark.image.withRenderingMode(.alwaysTemplate)) + override func prepareForReuse() { super.prepareForReuse() @@ -47,6 +49,8 @@ final class ProfileFieldCollectionViewCell: UICollectionViewCell { extension ProfileFieldCollectionViewCell { private func _init() { + checkmark.tintColor = Asset.Scene.Profile.About.bioAboutFieldValidatedCheckmark.color; + // containerStackView: V - [ metaContainer | plainContainer ] let containerStackView = UIStackView() containerStackView.axis = .vertical @@ -63,14 +67,21 @@ extension ProfileFieldCollectionViewCell { bottomAnchor.constraint(equalTo: containerStackView.bottomAnchor, constant: 11), ]) - // metaContainer: V - [ keyMetaLabel | valueMetaLabel ] + // metaContainer: V - [ keyMetaLabel | valueContainer ] let metaContainer = UIStackView() metaContainer.axis = .vertical metaContainer.spacing = 2 containerStackView.addArrangedSubview(metaContainer) + // valueContainer: H - [ valueMetaLabel | checkmark ] + let valueContainer = UIStackView() + valueContainer.axis = .horizontal + valueContainer.spacing = 2 + metaContainer.addArrangedSubview(keyMetaLabel) - metaContainer.addArrangedSubview(valueMetaLabel) + valueContainer.addArrangedSubview(valueMetaLabel) + valueContainer.addArrangedSubview(checkmark) + metaContainer.addArrangedSubview(valueContainer) keyMetaLabel.linkDelegate = self valueMetaLabel.linkDelegate = self diff --git a/Mastodon/Scene/Profile/About/ProfileAboutViewModel.swift b/Mastodon/Scene/Profile/About/ProfileAboutViewModel.swift index 68a3d0fea..044894b8a 100644 --- a/Mastodon/Scene/Profile/About/ProfileAboutViewModel.swift +++ b/Mastodon/Scene/Profile/About/ProfileAboutViewModel.swift @@ -52,7 +52,7 @@ final class ProfileAboutViewModel { $emojiMeta ) .map { fields, emojiMeta in - fields.map { ProfileFieldItem.FieldValue(name: $0.name, value: $0.value, emojiMeta: emojiMeta) } + fields.map { ProfileFieldItem.FieldValue(name: $0.name, value: $0.value, verifiedAt: $0.verifiedAt, emojiMeta: emojiMeta) } } .assign(to: &profileInfo.$fields) @@ -72,6 +72,7 @@ final class ProfileAboutViewModel { ProfileFieldItem.FieldValue( name: field.name, value: field.value, + verifiedAt: field.verifiedAt, emojiMeta: [:] // no use for editing ) } ?? [] @@ -92,7 +93,7 @@ extension ProfileAboutViewModel { func appendFieldItem() { var fields = profileInfoEditing.fields guard fields.count < ProfileHeaderViewModel.maxProfileFieldCount else { return } - fields.append(ProfileFieldItem.FieldValue(name: "", value: "", emojiMeta: [:])) + fields.append(ProfileFieldItem.FieldValue(name: "", value: "", verifiedAt: nil, emojiMeta: [:])) profileInfoEditing.fields = fields } @@ -112,7 +113,7 @@ extension ProfileAboutViewModel: ProfileViewModelEditable { let isFieldsEqual: Bool = { let originalFields = self.accountForEdit?.source?.fields?.compactMap { field in - ProfileFieldItem.FieldValue(name: field.name, value: field.value, emojiMeta: [:]) + ProfileFieldItem.FieldValue(name: field.name, value: field.value, verifiedAt: nil, emojiMeta: [:]) } ?? [] let editFields = profileInfoEditing.fields guard editFields.count == originalFields.count else { return false } diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Profile/About/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Profile/About/Contents.json new file mode 100644 index 000000000..6e965652d --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Profile/About/Contents.json @@ -0,0 +1,9 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "provides-namespace" : true + } +} diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Profile/About/bio.about.field.validated.background.colorset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Profile/About/bio.about.field.validated.background.colorset/Contents.json new file mode 100644 index 000000000..86944ced3 --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Profile/About/bio.about.field.validated.background.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.852", + "green" : "0.894", + "red" : "0.835" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.354", + "green" : "0.353", + "red" : "0.268" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Profile/About/bio.about.field.validated.checkmark.colorset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Profile/About/bio.about.field.validated.checkmark.colorset/Contents.json new file mode 100644 index 000000000..f5112f04f --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Profile/About/bio.about.field.validated.checkmark.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.371", + "green" : "0.565", + "red" : "0.290" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.603", + "green" : "0.742", + "red" : "0.476" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/MastodonSDK/Sources/MastodonAsset/Generated/Assets.swift b/MastodonSDK/Sources/MastodonAsset/Generated/Assets.swift index 5cd0059d8..45861c583 100644 --- a/MastodonSDK/Sources/MastodonAsset/Generated/Assets.swift +++ b/MastodonSDK/Sources/MastodonAsset/Generated/Assets.swift @@ -163,6 +163,10 @@ public enum Asset { public static let textFieldBackground = ColorAsset(name: "Scene/Onboarding/textField.background") } public enum Profile { + public enum About { + public static let bioAboutFieldValidatedBackground = ColorAsset(name: "Scene/Profile/About/bio.about.field.validated.background") + public static let bioAboutFieldValidatedCheckmark = ColorAsset(name: "Scene/Profile/About/bio.about.field.validated.checkmark") + } public enum Banner { public static let bioEditBackgroundGray = ColorAsset(name: "Scene/Profile/Banner/bio.edit.background.gray") public static let nameEditBackgroundGray = ColorAsset(name: "Scene/Profile/Banner/name.edit.background.gray") From 35775a5b4364d94998f3cc4890228e16b5beb5f8 Mon Sep 17 00:00:00 2001 From: David Godfrey Date: Sat, 12 Nov 2022 01:53:12 +0000 Subject: [PATCH 2/6] Alert validation time on tapping field checkmark, make validated field links green --- .../Profile/ProfileFieldSection.swift | 9 ++++- .../Cell/ProfileFieldCollectionViewCell.swift | 16 ++++++++ .../About/ProfileAboutViewController.swift | 16 ++++++++ .../Scene/Profile/ProfileViewController.swift | 16 ++++++++ .../Contents.json | 38 +++++++++++++++++++ .../MastodonAsset/Generated/Assets.swift | 1 + 6 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Profile/About/bio.about.field.validated.link.colorset/Contents.json diff --git a/Mastodon/Diffiable/Profile/ProfileFieldSection.swift b/Mastodon/Diffiable/Profile/ProfileFieldSection.swift index 332916a02..98acbb73c 100644 --- a/Mastodon/Diffiable/Profile/ProfileFieldSection.swift +++ b/Mastodon/Diffiable/Profile/ProfileFieldSection.swift @@ -49,6 +49,10 @@ extension ProfileFieldSection { do { let mastodonContent = MastodonContent(content: field.value.value, emojis: field.emojiMeta) let metaContent = try MastodonMetaContent.convert(document: mastodonContent) + cell.valueMetaLabel.linkAttributes[.foregroundColor] = Asset.Colors.brand.color + if field.verifiedAt.value != nil { + cell.valueMetaLabel.linkAttributes[.foregroundColor] = Asset.Scene.Profile.About.bioAboutFieldValidatedLink.color + } cell.valueMetaLabel.configure(content: metaContent) } catch { let content = PlaintextMetaContent(string: field.value.value) @@ -67,7 +71,10 @@ extension ProfileFieldSection { cell.checkmark.isHidden = true if let verifiedAt = field.verifiedAt.value { cell.checkmark.isHidden = false - cell.checkmark.accessibilityLabel = "Ownership of this link was checked on \(verifiedAt)" // TODO: I18N / L10N + let formatter = DateFormatter() + formatter.dateStyle = .medium + formatter.timeStyle = .short + cell.checkmark.accessibilityLabel = "Ownership of this link was checked on \(formatter.string(from: verifiedAt))" // TODO: I18N / L10N } cell.delegate = configuration.profileFieldCollectionViewCellDelegate diff --git a/Mastodon/Scene/Profile/About/Cell/ProfileFieldCollectionViewCell.swift b/Mastodon/Scene/Profile/About/Cell/ProfileFieldCollectionViewCell.swift index 076b8373e..2841ba664 100644 --- a/Mastodon/Scene/Profile/About/Cell/ProfileFieldCollectionViewCell.swift +++ b/Mastodon/Scene/Profile/About/Cell/ProfileFieldCollectionViewCell.swift @@ -14,6 +14,11 @@ 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 { @@ -27,6 +32,7 @@ final class ProfileFieldCollectionViewCell: UICollectionViewCell { let valueMetaLabel = MetaLabel(style: .profileFieldValue) let checkmark = UIImageView(image: Asset.Editing.checkmark.image.withRenderingMode(.alwaysTemplate)) + let tapGesture = UITapGestureRecognizer(); override func prepareForReuse() { super.prepareForReuse() @@ -49,8 +55,14 @@ final class ProfileFieldCollectionViewCell: UICollectionViewCell { extension ProfileFieldCollectionViewCell { private func _init() { + // Setup colors checkmark.tintColor = Asset.Scene.Profile.About.bioAboutFieldValidatedCheckmark.color; + // Setup gestures + tapGesture.addTarget(self, action: #selector(ProfileFieldCollectionViewCell.didTapCheckmark(_:))) + checkmark.addGestureRecognizer(tapGesture) + checkmark.isUserInteractionEnabled = true + // containerStackView: V - [ metaContainer | plainContainer ] let containerStackView = UIStackView() containerStackView.axis = .vertical @@ -87,6 +99,10 @@ extension ProfileFieldCollectionViewCell { valueMetaLabel.linkDelegate = self } + @objc public func didTapCheckmark(_: UITapGestureRecognizer) { + delegate?.profileFieldCollectionViewCell(self, didTapAction: .Checkmark) + } + } // MARK: - MetaLabelDelegate diff --git a/Mastodon/Scene/Profile/About/ProfileAboutViewController.swift b/Mastodon/Scene/Profile/About/ProfileAboutViewController.swift index eb1e6b39c..bf77c05b9 100644 --- a/Mastodon/Scene/Profile/About/ProfileAboutViewController.swift +++ b/Mastodon/Scene/Profile/About/ProfileAboutViewController.swift @@ -16,6 +16,7 @@ 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 { @@ -152,6 +153,21 @@ 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 diff --git a/Mastodon/Scene/Profile/ProfileViewController.swift b/Mastodon/Scene/Profile/ProfileViewController.swift index 3ce1fd33a..908725e43 100644 --- a/Mastodon/Scene/Profile/ProfileViewController.swift +++ b/Mastodon/Scene/Profile/ProfileViewController.swift @@ -854,6 +854,22 @@ 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: "Validated", message: "Ownership of this link was checked on \(formatter.string(from: verifiedAt))", preferredStyle: .alert) // TODO: I18N / L10N + alert.addAction(UIAlertAction(title: L10n.Common.Controls.Actions.ok, style: .default) { _ in + alert.dismiss(animated: true) + }) + + self.present(alert, animated: true) + } } // MARK: - MastodonMenuDelegate diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Profile/About/bio.about.field.validated.link.colorset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Profile/About/bio.about.field.validated.link.colorset/Contents.json new file mode 100644 index 000000000..f5112f04f --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Profile/About/bio.about.field.validated.link.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.371", + "green" : "0.565", + "red" : "0.290" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.603", + "green" : "0.742", + "red" : "0.476" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/MastodonSDK/Sources/MastodonAsset/Generated/Assets.swift b/MastodonSDK/Sources/MastodonAsset/Generated/Assets.swift index 45861c583..986215f5f 100644 --- a/MastodonSDK/Sources/MastodonAsset/Generated/Assets.swift +++ b/MastodonSDK/Sources/MastodonAsset/Generated/Assets.swift @@ -166,6 +166,7 @@ public enum Asset { public enum About { public static let bioAboutFieldValidatedBackground = ColorAsset(name: "Scene/Profile/About/bio.about.field.validated.background") public static let bioAboutFieldValidatedCheckmark = ColorAsset(name: "Scene/Profile/About/bio.about.field.validated.checkmark") + public static let bioAboutFieldValidatedLink = ColorAsset(name: "Scene/Profile/About/bio.about.field.validated.link") } public enum Banner { public static let bioEditBackgroundGray = ColorAsset(name: "Scene/Profile/Banner/bio.edit.background.gray") From b0a0aa268f59ae985f05f88e0fc6f4b7434b01a5 Mon Sep 17 00:00:00 2001 From: David Godfrey Date: Sat, 12 Nov 2022 02:10:16 +0000 Subject: [PATCH 3/6] Rename validated to verified in profile field code --- Mastodon/Diffiable/Profile/ProfileFieldSection.swift | 4 ++-- .../Profile/About/Cell/ProfileFieldCollectionViewCell.swift | 2 +- Mastodon/Scene/Profile/ProfileViewController.swift | 2 +- .../Contents.json | 0 .../Contents.json | 0 .../Contents.json | 0 MastodonSDK/Sources/MastodonAsset/Generated/Assets.swift | 6 +++--- 7 files changed, 7 insertions(+), 7 deletions(-) rename MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Profile/About/{bio.about.field.validated.background.colorset => bio.about.field.verified.background.colorset}/Contents.json (100%) rename MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Profile/About/{bio.about.field.validated.checkmark.colorset => bio.about.field.verified.checkmark.colorset}/Contents.json (100%) rename MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Profile/About/{bio.about.field.validated.link.colorset => bio.about.field.verified.link.colorset}/Contents.json (100%) diff --git a/Mastodon/Diffiable/Profile/ProfileFieldSection.swift b/Mastodon/Diffiable/Profile/ProfileFieldSection.swift index 98acbb73c..87f730fa8 100644 --- a/Mastodon/Diffiable/Profile/ProfileFieldSection.swift +++ b/Mastodon/Diffiable/Profile/ProfileFieldSection.swift @@ -51,7 +51,7 @@ extension ProfileFieldSection { let metaContent = try MastodonMetaContent.convert(document: mastodonContent) cell.valueMetaLabel.linkAttributes[.foregroundColor] = Asset.Colors.brand.color if field.verifiedAt.value != nil { - cell.valueMetaLabel.linkAttributes[.foregroundColor] = Asset.Scene.Profile.About.bioAboutFieldValidatedLink.color + cell.valueMetaLabel.linkAttributes[.foregroundColor] = Asset.Scene.Profile.About.bioAboutFieldVerifiedLink.color } cell.valueMetaLabel.configure(content: metaContent) } catch { @@ -63,7 +63,7 @@ extension ProfileFieldSection { var backgroundConfiguration = UIBackgroundConfiguration.listPlainCell() backgroundConfiguration.backgroundColor = UIColor.secondarySystemBackground if (field.verifiedAt.value != nil) { - backgroundConfiguration.backgroundColor = Asset.Scene.Profile.About.bioAboutFieldValidatedBackground.color + backgroundConfiguration.backgroundColor = Asset.Scene.Profile.About.bioAboutFieldVerifiedBackground.color } cell.backgroundConfiguration = backgroundConfiguration diff --git a/Mastodon/Scene/Profile/About/Cell/ProfileFieldCollectionViewCell.swift b/Mastodon/Scene/Profile/About/Cell/ProfileFieldCollectionViewCell.swift index 2841ba664..2d33b2afe 100644 --- a/Mastodon/Scene/Profile/About/Cell/ProfileFieldCollectionViewCell.swift +++ b/Mastodon/Scene/Profile/About/Cell/ProfileFieldCollectionViewCell.swift @@ -56,7 +56,7 @@ extension ProfileFieldCollectionViewCell { private func _init() { // Setup colors - checkmark.tintColor = Asset.Scene.Profile.About.bioAboutFieldValidatedCheckmark.color; + checkmark.tintColor = Asset.Scene.Profile.About.bioAboutFieldVerifiedCheckmark.color; // Setup gestures tapGesture.addTarget(self, action: #selector(ProfileFieldCollectionViewCell.didTapCheckmark(_:))) diff --git a/Mastodon/Scene/Profile/ProfileViewController.swift b/Mastodon/Scene/Profile/ProfileViewController.swift index 908725e43..70d11a823 100644 --- a/Mastodon/Scene/Profile/ProfileViewController.swift +++ b/Mastodon/Scene/Profile/ProfileViewController.swift @@ -863,7 +863,7 @@ extension ProfileViewController: ProfileAboutViewControllerDelegate { let formatter = DateFormatter() formatter.dateStyle = .medium formatter.timeStyle = .short - let alert = UIAlertController(title: "Validated", message: "Ownership of this link was checked on \(formatter.string(from: verifiedAt))", preferredStyle: .alert) // TODO: I18N / L10N + let alert = UIAlertController(title: "Verified", message: "Ownership of this link was checked on \(formatter.string(from: verifiedAt))", preferredStyle: .alert) // TODO: I18N / L10N alert.addAction(UIAlertAction(title: L10n.Common.Controls.Actions.ok, style: .default) { _ in alert.dismiss(animated: true) }) diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Profile/About/bio.about.field.validated.background.colorset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Profile/About/bio.about.field.verified.background.colorset/Contents.json similarity index 100% rename from MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Profile/About/bio.about.field.validated.background.colorset/Contents.json rename to MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Profile/About/bio.about.field.verified.background.colorset/Contents.json diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Profile/About/bio.about.field.validated.checkmark.colorset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Profile/About/bio.about.field.verified.checkmark.colorset/Contents.json similarity index 100% rename from MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Profile/About/bio.about.field.validated.checkmark.colorset/Contents.json rename to MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Profile/About/bio.about.field.verified.checkmark.colorset/Contents.json diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Profile/About/bio.about.field.validated.link.colorset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Profile/About/bio.about.field.verified.link.colorset/Contents.json similarity index 100% rename from MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Profile/About/bio.about.field.validated.link.colorset/Contents.json rename to MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Profile/About/bio.about.field.verified.link.colorset/Contents.json diff --git a/MastodonSDK/Sources/MastodonAsset/Generated/Assets.swift b/MastodonSDK/Sources/MastodonAsset/Generated/Assets.swift index 986215f5f..dec04f142 100644 --- a/MastodonSDK/Sources/MastodonAsset/Generated/Assets.swift +++ b/MastodonSDK/Sources/MastodonAsset/Generated/Assets.swift @@ -164,9 +164,9 @@ public enum Asset { } public enum Profile { public enum About { - public static let bioAboutFieldValidatedBackground = ColorAsset(name: "Scene/Profile/About/bio.about.field.validated.background") - public static let bioAboutFieldValidatedCheckmark = ColorAsset(name: "Scene/Profile/About/bio.about.field.validated.checkmark") - public static let bioAboutFieldValidatedLink = ColorAsset(name: "Scene/Profile/About/bio.about.field.validated.link") + public static let bioAboutFieldVerifiedBackground = ColorAsset(name: "Scene/Profile/About/bio.about.field.verified.background") + public static let bioAboutFieldVerifiedCheckmark = ColorAsset(name: "Scene/Profile/About/bio.about.field.verified.checkmark") + public static let bioAboutFieldVerifiedLink = ColorAsset(name: "Scene/Profile/About/bio.about.field.verified.link") } public enum Banner { public static let bioEditBackgroundGray = ColorAsset(name: "Scene/Profile/Banner/bio.edit.background.gray") From 72873fbfc1d22ba86d3b1eb227164058a2c08e43 Mon Sep 17 00:00:00 2001 From: David Godfrey Date: Sat, 12 Nov 2022 02:40:19 +0000 Subject: [PATCH 4/6] Use localisable strings in verified modal --- Localization/app.json | 4 ++++ Mastodon/Diffiable/Profile/ProfileFieldSection.swift | 2 +- Mastodon/Scene/Profile/ProfileViewController.swift | 2 +- .../Sources/MastodonLocalization/Generated/Strings.swift | 8 ++++++++ .../Resources/en.lproj/Localizable.strings | 4 +++- 5 files changed, 17 insertions(+), 3 deletions(-) diff --git a/Localization/app.json b/Localization/app.json index c5a3dac74..6ca2cbea9 100644 --- a/Localization/app.json +++ b/Localization/app.json @@ -51,6 +51,10 @@ "clean_cache": { "title": "Clean Cache", "message": "Successfully cleaned %s cache." + }, + "verified": { + "title": "Verified", + "message": "Ownership of this link was checked on %s" } }, "controls": { diff --git a/Mastodon/Diffiable/Profile/ProfileFieldSection.swift b/Mastodon/Diffiable/Profile/ProfileFieldSection.swift index 87f730fa8..01e8d8a0a 100644 --- a/Mastodon/Diffiable/Profile/ProfileFieldSection.swift +++ b/Mastodon/Diffiable/Profile/ProfileFieldSection.swift @@ -74,7 +74,7 @@ extension ProfileFieldSection { let formatter = DateFormatter() formatter.dateStyle = .medium formatter.timeStyle = .short - cell.checkmark.accessibilityLabel = "Ownership of this link was checked on \(formatter.string(from: verifiedAt))" // TODO: I18N / L10N + cell.checkmark.accessibilityLabel = L10n.Common.Alerts.Verified.message(formatter.string(from: verifiedAt)) } cell.delegate = configuration.profileFieldCollectionViewCellDelegate diff --git a/Mastodon/Scene/Profile/ProfileViewController.swift b/Mastodon/Scene/Profile/ProfileViewController.swift index 70d11a823..1faf291f3 100644 --- a/Mastodon/Scene/Profile/ProfileViewController.swift +++ b/Mastodon/Scene/Profile/ProfileViewController.swift @@ -863,7 +863,7 @@ extension ProfileViewController: ProfileAboutViewControllerDelegate { let formatter = DateFormatter() formatter.dateStyle = .medium formatter.timeStyle = .short - let alert = UIAlertController(title: "Verified", message: "Ownership of this link was checked on \(formatter.string(from: verifiedAt))", preferredStyle: .alert) // TODO: I18N / L10N + 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) }) diff --git a/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift b/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift index 44ae29267..fce4d9733 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift +++ b/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift @@ -87,6 +87,14 @@ 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) -> 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") diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings index 9114b96e5..fe9566b14 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings @@ -22,6 +22,8 @@ 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"; @@ -448,4 +450,4 @@ uploaded to Mastodon."; back in your hands."; "Scene.Wizard.AccessibilityHint" = "Double tap to dismiss this wizard"; "Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Switch between multiple accounts by holding the profile button."; -"Scene.Wizard.NewInMastodon" = "New in Mastodon"; \ No newline at end of file +"Scene.Wizard.NewInMastodon" = "New in Mastodon"; From 197e180ccdab95e834a9616e6bcb56541f76e085 Mon Sep 17 00:00:00 2001 From: David Godfrey Date: Sat, 12 Nov 2022 14:42:00 +0000 Subject: [PATCH 5/6] Refactor verified alert to use edit menu --- Localization/app.json | 8 +-- .../Profile/ProfileFieldSection.swift | 7 +- .../Cell/ProfileFieldCollectionViewCell.swift | 64 +++++++++++++++++-- .../About/ProfileAboutViewController.swift | 16 ----- .../Scene/Profile/ProfileViewController.swift | 16 ----- .../Generated/Strings.swift | 18 +++--- .../Resources/en.lproj/Localizable.strings | 4 +- 7 files changed, 78 insertions(+), 55 deletions(-) diff --git a/Localization/app.json b/Localization/app.json index 6ca2cbea9..dfb204d8c 100644 --- a/Localization/app.json +++ b/Localization/app.json @@ -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": { diff --git a/Mastodon/Diffiable/Profile/ProfileFieldSection.swift b/Mastodon/Diffiable/Profile/ProfileFieldSection.swift index 01e8d8a0a..6e57e6af9 100644 --- a/Mastodon/Diffiable/Profile/ProfileFieldSection.swift +++ b/Mastodon/Diffiable/Profile/ProfileFieldSection.swift @@ -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 diff --git a/Mastodon/Scene/Profile/About/Cell/ProfileFieldCollectionViewCell.swift b/Mastodon/Scene/Profile/About/Cell/ProfileFieldCollectionViewCell.swift index 2d33b2afe..1ed76a485 100644 --- a/Mastodon/Scene/Profile/About/Cell/ProfileFieldCollectionViewCell.swift +++ b/Mastodon/Scene/Profile/About/Cell/ProfileFieldCollectionViewCell.swift @@ -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 + } +} diff --git a/Mastodon/Scene/Profile/About/ProfileAboutViewController.swift b/Mastodon/Scene/Profile/About/ProfileAboutViewController.swift index bf77c05b9..eb1e6b39c 100644 --- a/Mastodon/Scene/Profile/About/ProfileAboutViewController.swift +++ b/Mastodon/Scene/Profile/About/ProfileAboutViewController.swift @@ -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 diff --git a/Mastodon/Scene/Profile/ProfileViewController.swift b/Mastodon/Scene/Profile/ProfileViewController.swift index 1faf291f3..3ce1fd33a 100644 --- a/Mastodon/Scene/Profile/ProfileViewController.swift +++ b/Mastodon/Scene/Profile/ProfileViewController.swift @@ -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 diff --git a/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift b/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift index fce4d9733..794cd182e 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift +++ b/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift @@ -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) -> 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) -> String { + return L10n.tr("Localizable", "Scene.Profile.Fields.Verified.Long", p1) + } + /// Verified at %s + public static func short(_ p1: UnsafePointer) -> String { + return L10n.tr("Localizable", "Scene.Profile.Fields.Verified.Short", p1) + } + } } public enum Header { /// Follows You diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings index fe9566b14..2c9b71107 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings @@ -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"; From 7b37d46c9b54f1484d76c35afb6df46eda3c52f0 Mon Sep 17 00:00:00 2001 From: David Godfrey Date: Mon, 14 Nov 2022 10:38:32 +0000 Subject: [PATCH 6/6] Update Localization/app.json Co-authored-by: Jed Fox --- Localization/app.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Localization/app.json b/Localization/app.json index dfb204d8c..867e64aed 100644 --- a/Localization/app.json +++ b/Localization/app.json @@ -440,7 +440,7 @@ "content": "Content" }, "verified": { - "short": "Verified at %s", + "short": "Verified on %s", "long": "Ownership of this link was checked on %s" } },