Merge pull request #564 from ReactiveRaven/feature/validated-fields
Visual indication of validated URL
This commit is contained in:
commit
84ffa3ba56
@ -448,6 +448,10 @@
|
|||||||
"placeholder": {
|
"placeholder": {
|
||||||
"label": "Label",
|
"label": "Label",
|
||||||
"content": "Content"
|
"content": "Content"
|
||||||
|
},
|
||||||
|
"verified": {
|
||||||
|
"short": "Verified on %s",
|
||||||
|
"long": "Ownership of this link was checked on %s"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"segmented_control": {
|
"segmented_control": {
|
||||||
|
@ -23,6 +23,7 @@ extension ProfileFieldItem {
|
|||||||
|
|
||||||
var name: CurrentValueSubject<String, Never>
|
var name: CurrentValueSubject<String, Never>
|
||||||
var value: CurrentValueSubject<String, Never>
|
var value: CurrentValueSubject<String, Never>
|
||||||
|
var verifiedAt: CurrentValueSubject<Date?, Never>
|
||||||
|
|
||||||
let emojiMeta: MastodonContent.Emojis
|
let emojiMeta: MastodonContent.Emojis
|
||||||
|
|
||||||
@ -30,11 +31,13 @@ extension ProfileFieldItem {
|
|||||||
id: UUID = UUID(),
|
id: UUID = UUID(),
|
||||||
name: String,
|
name: String,
|
||||||
value: String,
|
value: String,
|
||||||
|
verifiedAt: Date?,
|
||||||
emojiMeta: MastodonContent.Emojis
|
emojiMeta: MastodonContent.Emojis
|
||||||
) {
|
) {
|
||||||
self.id = id
|
self.id = id
|
||||||
self.name = CurrentValueSubject(name)
|
self.name = CurrentValueSubject(name)
|
||||||
self.value = CurrentValueSubject(value)
|
self.value = CurrentValueSubject(value)
|
||||||
|
self.verifiedAt = CurrentValueSubject(verifiedAt)
|
||||||
self.emojiMeta = emojiMeta
|
self.emojiMeta = emojiMeta
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,6 +48,7 @@ extension ProfileFieldItem {
|
|||||||
return lhs.id == rhs.id
|
return lhs.id == rhs.id
|
||||||
&& lhs.name.value == rhs.name.value
|
&& lhs.name.value == rhs.name.value
|
||||||
&& lhs.value.value == rhs.value.value
|
&& lhs.value.value == rhs.value.value
|
||||||
|
&& lhs.verifiedAt.value == rhs.verifiedAt.value
|
||||||
&& lhs.emojiMeta == rhs.emojiMeta
|
&& lhs.emojiMeta == rhs.emojiMeta
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
import os
|
import os
|
||||||
import UIKit
|
import UIKit
|
||||||
import Combine
|
import Combine
|
||||||
|
import MastodonAsset
|
||||||
import MastodonCore
|
import MastodonCore
|
||||||
import MastodonMeta
|
import MastodonMeta
|
||||||
import MastodonLocalization
|
import MastodonLocalization
|
||||||
@ -48,6 +49,10 @@ extension ProfileFieldSection {
|
|||||||
do {
|
do {
|
||||||
let mastodonContent = MastodonContent(content: field.value.value, emojis: field.emojiMeta)
|
let mastodonContent = MastodonContent(content: field.value.value, emojis: field.emojiMeta)
|
||||||
let metaContent = try MastodonMetaContent.convert(document: mastodonContent)
|
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.bioAboutFieldVerifiedLink.color
|
||||||
|
}
|
||||||
cell.valueMetaLabel.configure(content: metaContent)
|
cell.valueMetaLabel.configure(content: metaContent)
|
||||||
} catch {
|
} catch {
|
||||||
let content = PlaintextMetaContent(string: field.value.value)
|
let content = PlaintextMetaContent(string: field.value.value)
|
||||||
@ -57,7 +62,23 @@ extension ProfileFieldSection {
|
|||||||
// set background
|
// set background
|
||||||
var backgroundConfiguration = UIBackgroundConfiguration.listPlainCell()
|
var backgroundConfiguration = UIBackgroundConfiguration.listPlainCell()
|
||||||
backgroundConfiguration.backgroundColor = UIColor.secondarySystemBackground
|
backgroundConfiguration.backgroundColor = UIColor.secondarySystemBackground
|
||||||
|
if (field.verifiedAt.value != nil) {
|
||||||
|
backgroundConfiguration.backgroundColor = Asset.Scene.Profile.About.bioAboutFieldVerifiedBackground.color
|
||||||
|
}
|
||||||
cell.backgroundConfiguration = backgroundConfiguration
|
cell.backgroundConfiguration = backgroundConfiguration
|
||||||
|
|
||||||
|
// 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
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,16 @@ final class ProfileFieldCollectionViewCell: UICollectionViewCell {
|
|||||||
let keyMetaLabel = MetaLabel(style: .profileFieldName)
|
let keyMetaLabel = MetaLabel(style: .profileFieldName)
|
||||||
let valueMetaLabel = MetaLabel(style: .profileFieldValue)
|
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() {
|
override func prepareForReuse() {
|
||||||
super.prepareForReuse()
|
super.prepareForReuse()
|
||||||
|
|
||||||
@ -47,6 +57,17 @@ final class ProfileFieldCollectionViewCell: UICollectionViewCell {
|
|||||||
extension ProfileFieldCollectionViewCell {
|
extension ProfileFieldCollectionViewCell {
|
||||||
|
|
||||||
private func _init() {
|
private func _init() {
|
||||||
|
// Setup colors
|
||||||
|
checkmark.tintColor = Asset.Scene.Profile.About.bioAboutFieldVerifiedCheckmark.color;
|
||||||
|
|
||||||
|
// Setup gestures
|
||||||
|
tapGesture.addTarget(self, action: #selector(ProfileFieldCollectionViewCell.didTapCheckmark(_:)))
|
||||||
|
checkmark.addGestureRecognizer(tapGesture)
|
||||||
|
checkmark.isUserInteractionEnabled = true
|
||||||
|
if #available(iOS 16, *) {
|
||||||
|
checkmark.addInteraction(editMenuInteraction)
|
||||||
|
}
|
||||||
|
|
||||||
// containerStackView: V - [ metaContainer | plainContainer ]
|
// containerStackView: V - [ metaContainer | plainContainer ]
|
||||||
let containerStackView = UIStackView()
|
let containerStackView = UIStackView()
|
||||||
containerStackView.axis = .vertical
|
containerStackView.axis = .vertical
|
||||||
@ -63,19 +84,62 @@ extension ProfileFieldCollectionViewCell {
|
|||||||
bottomAnchor.constraint(equalTo: containerStackView.bottomAnchor, constant: 11),
|
bottomAnchor.constraint(equalTo: containerStackView.bottomAnchor, constant: 11),
|
||||||
])
|
])
|
||||||
|
|
||||||
// metaContainer: V - [ keyMetaLabel | valueMetaLabel ]
|
// metaContainer: V - [ keyMetaLabel | valueContainer ]
|
||||||
let metaContainer = UIStackView()
|
let metaContainer = UIStackView()
|
||||||
metaContainer.axis = .vertical
|
metaContainer.axis = .vertical
|
||||||
metaContainer.spacing = 2
|
metaContainer.spacing = 2
|
||||||
containerStackView.addArrangedSubview(metaContainer)
|
containerStackView.addArrangedSubview(metaContainer)
|
||||||
|
|
||||||
|
// valueContainer: H - [ valueMetaLabel | checkmark ]
|
||||||
|
let valueContainer = UIStackView()
|
||||||
|
valueContainer.axis = .horizontal
|
||||||
|
valueContainer.spacing = 2
|
||||||
|
|
||||||
metaContainer.addArrangedSubview(keyMetaLabel)
|
metaContainer.addArrangedSubview(keyMetaLabel)
|
||||||
metaContainer.addArrangedSubview(valueMetaLabel)
|
valueContainer.addArrangedSubview(valueMetaLabel)
|
||||||
|
valueContainer.addArrangedSubview(checkmark)
|
||||||
|
metaContainer.addArrangedSubview(valueContainer)
|
||||||
|
|
||||||
keyMetaLabel.linkDelegate = self
|
keyMetaLabel.linkDelegate = self
|
||||||
valueMetaLabel.linkDelegate = self
|
valueMetaLabel.linkDelegate = self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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
|
// MARK: - MetaLabelDelegate
|
||||||
@ -85,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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -52,7 +52,7 @@ final class ProfileAboutViewModel {
|
|||||||
$emojiMeta
|
$emojiMeta
|
||||||
)
|
)
|
||||||
.map { fields, emojiMeta in
|
.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)
|
.assign(to: &profileInfo.$fields)
|
||||||
|
|
||||||
@ -72,6 +72,7 @@ final class ProfileAboutViewModel {
|
|||||||
ProfileFieldItem.FieldValue(
|
ProfileFieldItem.FieldValue(
|
||||||
name: field.name,
|
name: field.name,
|
||||||
value: field.value,
|
value: field.value,
|
||||||
|
verifiedAt: field.verifiedAt,
|
||||||
emojiMeta: [:] // no use for editing
|
emojiMeta: [:] // no use for editing
|
||||||
)
|
)
|
||||||
} ?? []
|
} ?? []
|
||||||
@ -92,7 +93,7 @@ extension ProfileAboutViewModel {
|
|||||||
func appendFieldItem() {
|
func appendFieldItem() {
|
||||||
var fields = profileInfoEditing.fields
|
var fields = profileInfoEditing.fields
|
||||||
guard fields.count < ProfileHeaderViewModel.maxProfileFieldCount else { return }
|
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
|
profileInfoEditing.fields = fields
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,7 +113,7 @@ extension ProfileAboutViewModel: ProfileViewModelEditable {
|
|||||||
|
|
||||||
let isFieldsEqual: Bool = {
|
let isFieldsEqual: Bool = {
|
||||||
let originalFields = self.accountForEdit?.source?.fields?.compactMap { field in
|
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
|
let editFields = profileInfoEditing.fields
|
||||||
guard editFields.count == originalFields.count else { return false }
|
guard editFields.count == originalFields.count else { return false }
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"provides-namespace" : true
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
@ -171,6 +171,11 @@ public enum Asset {
|
|||||||
public static let textFieldBackground = ColorAsset(name: "Scene/Onboarding/textField.background")
|
public static let textFieldBackground = ColorAsset(name: "Scene/Onboarding/textField.background")
|
||||||
}
|
}
|
||||||
public enum Profile {
|
public enum Profile {
|
||||||
|
public enum About {
|
||||||
|
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 enum Banner {
|
||||||
public static let bioEditBackgroundGray = ColorAsset(name: "Scene/Profile/Banner/bio.edit.background.gray")
|
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")
|
public static let nameEditBackgroundGray = ColorAsset(name: "Scene/Profile/Banner/name.edit.background.gray")
|
||||||
|
@ -741,6 +741,16 @@ public enum L10n {
|
|||||||
/// Label
|
/// Label
|
||||||
public static let label = L10n.tr("Localizable", "Scene.Profile.Fields.Placeholder.Label", fallback: "Label")
|
public static let label = L10n.tr("Localizable", "Scene.Profile.Fields.Placeholder.Label", fallback: "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
|
||||||
|
@ -263,6 +263,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";
|
||||||
@ -454,4 +456,4 @@ uploaded to Mastodon.";
|
|||||||
back in your hands.";
|
back in your hands.";
|
||||||
"Scene.Wizard.AccessibilityHint" = "Double tap to dismiss this wizard";
|
"Scene.Wizard.AccessibilityHint" = "Double tap to dismiss this wizard";
|
||||||
"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Switch between multiple accounts by holding the profile button.";
|
"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Switch between multiple accounts by holding the profile button.";
|
||||||
"Scene.Wizard.NewInMastodon" = "New in Mastodon";
|
"Scene.Wizard.NewInMastodon" = "New in Mastodon";
|
||||||
|
Loading…
x
Reference in New Issue
Block a user