Consistently pluralize emoji

This commit is contained in:
Justin Mazzocchi 2021-01-11 23:33:35 -08:00
parent fab43da52f
commit ef8fd98e4b
No known key found for this signature in database
GPG key ID: E223E6937AAFB01C
17 changed files with 45 additions and 45 deletions

View file

@ -5,8 +5,8 @@ import Mastodon
import UIKit import UIKit
extension NSMutableAttributedString { extension NSMutableAttributedString {
func insert(emoji: [Emoji], view: UIView) { func insert(emojis: [Emoji], view: UIView) {
for emoji in emoji { for emoji in emojis {
let token = ":\(emoji.shortcode):" let token = ":\(emoji.shortcode):"
while let tokenRange = string.range(of: token) { while let tokenRange = string.range(of: token) {

View file

@ -23,7 +23,7 @@ extension String {
return attributed return attributed
} }
func localizedBolding(displayName: String, emoji: [Emoji], label: UILabel) -> NSAttributedString { func localizedBolding(displayName: String, emojis: [Emoji], label: UILabel) -> NSAttributedString {
let mutableString = NSMutableAttributedString( let mutableString = NSMutableAttributedString(
string: String.localizedStringWithFormat( string: String.localizedStringWithFormat(
NSLocalizedString(self, comment: ""), NSLocalizedString(self, comment: ""),
@ -38,7 +38,7 @@ extension String {
mutableString.setAttributes([NSAttributedString.Key.font: boldFont], range: range) mutableString.setAttributes([NSAttributedString.Key.font: boldFont], range: range)
} }
mutableString.insert(emoji: emoji, view: label) mutableString.insert(emojis: emojis, view: label)
mutableString.resizeAttachments(toLineHeight: label.font.lineHeight) mutableString.resizeAttachments(toLineHeight: label.font.lineHeight)
return mutableString return mutableString

View file

@ -48,7 +48,7 @@ public extension AccountViewModel {
var note: NSAttributedString { accountService.account.note.attributed } var note: NSAttributedString { accountService.account.note.attributed }
var emoji: [Emoji] { accountService.account.emojis } var emojis: [Emoji] { accountService.account.emojis }
var followingCount: Int { accountService.account.followingCount } var followingCount: Int { accountService.account.followingCount }

View file

@ -7,15 +7,15 @@ import ServiceLayer
public final class StatusViewModel: CollectionItemViewModel, AttachmentsRenderingViewModel, ObservableObject { public final class StatusViewModel: CollectionItemViewModel, AttachmentsRenderingViewModel, ObservableObject {
public let content: NSAttributedString public let content: NSAttributedString
public let contentEmoji: [Emoji] public let contentEmojis: [Emoji]
public let displayName: String public let displayName: String
public let displayNameEmoji: [Emoji] public let displayNameEmojis: [Emoji]
public let spoilerText: String public let spoilerText: String
public let isReblog: Bool public let isReblog: Bool
public let rebloggedByDisplayName: String public let rebloggedByDisplayName: String
public let rebloggedByDisplayNameEmoji: [Emoji] public let rebloggedByDisplayNameEmojis: [Emoji]
public let attachmentViewModels: [AttachmentViewModel] public let attachmentViewModels: [AttachmentViewModel]
public let pollEmoji: [Emoji] public let pollEmojis: [Emoji]
@Published public var pollOptionSelections = Set<Int>() @Published public var pollOptionSelections = Set<Int>()
public var configuration = CollectionItem.StatusConfiguration.default public var configuration = CollectionItem.StatusConfiguration.default
public let events: AnyPublisher<AnyPublisher<CollectionItemEvent, Error>, Never> public let events: AnyPublisher<AnyPublisher<CollectionItemEvent, Error>, Never>
@ -28,20 +28,20 @@ public final class StatusViewModel: CollectionItemViewModel, AttachmentsRenderin
self.statusService = statusService self.statusService = statusService
self.identification = identification self.identification = identification
content = statusService.status.displayStatus.content.attributed content = statusService.status.displayStatus.content.attributed
contentEmoji = statusService.status.displayStatus.emojis contentEmojis = statusService.status.displayStatus.emojis
displayName = statusService.status.displayStatus.account.displayName.isEmpty displayName = statusService.status.displayStatus.account.displayName.isEmpty
? statusService.status.displayStatus.account.username ? statusService.status.displayStatus.account.username
: statusService.status.displayStatus.account.displayName : statusService.status.displayStatus.account.displayName
displayNameEmoji = statusService.status.displayStatus.account.emojis displayNameEmojis = statusService.status.displayStatus.account.emojis
spoilerText = statusService.status.displayStatus.spoilerText spoilerText = statusService.status.displayStatus.spoilerText
isReblog = statusService.status.reblog != nil isReblog = statusService.status.reblog != nil
rebloggedByDisplayName = statusService.status.account.displayName.isEmpty rebloggedByDisplayName = statusService.status.account.displayName.isEmpty
? statusService.status.account.username ? statusService.status.account.username
: statusService.status.account.displayName : statusService.status.account.displayName
rebloggedByDisplayNameEmoji = statusService.status.account.emojis rebloggedByDisplayNameEmojis = statusService.status.account.emojis
attachmentViewModels = statusService.status.displayStatus.mediaAttachments attachmentViewModels = statusService.status.displayStatus.mediaAttachments
.map { AttachmentViewModel(attachment: $0, identification: identification, status: statusService.status) } .map { AttachmentViewModel(attachment: $0, identification: identification, status: statusService.status) }
pollEmoji = statusService.status.displayStatus.poll?.emojis ?? [] pollEmojis = statusService.status.displayStatus.poll?.emojis ?? []
events = eventsSubject.eraseToAnyPublisher() events = eventsSubject.eraseToAnyPublisher()
} }
} }

View file

@ -8,7 +8,7 @@ final class AccountFieldView: UIView {
let valueTextView = TouchFallthroughTextView() let valueTextView = TouchFallthroughTextView()
// swiftlint:disable:next function_body_length // swiftlint:disable:next function_body_length
init(name: String, value: NSAttributedString, verifiedAt: Date?, emoji: [Emoji]) { init(name: String, value: NSAttributedString, verifiedAt: Date?, emojis: [Emoji]) {
super.init(frame: .zero) super.init(frame: .zero)
backgroundColor = .systemBackground backgroundColor = .systemBackground
@ -36,7 +36,7 @@ final class AccountFieldView: UIView {
let mutableName = NSMutableAttributedString(string: name) let mutableName = NSMutableAttributedString(string: name)
mutableName.insert(emoji: emoji, view: nameLabel) mutableName.insert(emojis: emojis, view: nameLabel)
mutableName.resizeAttachments(toLineHeight: nameLabel.font.lineHeight) mutableName.resizeAttachments(toLineHeight: nameLabel.font.lineHeight)
nameLabel.attributedText = mutableName nameLabel.attributedText = mutableName
@ -66,7 +66,7 @@ final class AccountFieldView: UIView {
[.font: valueFont as Any, [.font: valueFont as Any,
.foregroundColor: UIColor.label], .foregroundColor: UIColor.label],
range: valueRange) range: valueRange)
mutableValue.insert(emoji: emoji, view: valueTextView) mutableValue.insert(emojis: emojis, view: valueTextView)
mutableValue.resizeAttachments(toLineHeight: valueFont.lineHeight) mutableValue.resizeAttachments(toLineHeight: valueFont.lineHeight)
valueTextView.attributedText = mutableValue valueTextView.attributedText = mutableValue

View file

@ -50,7 +50,7 @@ final class AccountHeaderView: UIView {
} else { } else {
let mutableDisplayName = NSMutableAttributedString(string: accountViewModel.displayName) let mutableDisplayName = NSMutableAttributedString(string: accountViewModel.displayName)
mutableDisplayName.insert(emoji: accountViewModel.emoji, view: displayNameLabel) mutableDisplayName.insert(emojis: accountViewModel.emojis, view: displayNameLabel)
mutableDisplayName.resizeAttachments(toLineHeight: displayNameLabel.font.lineHeight) mutableDisplayName.resizeAttachments(toLineHeight: displayNameLabel.font.lineHeight)
displayNameLabel.attributedText = mutableDisplayName displayNameLabel.attributedText = mutableDisplayName
} }
@ -70,7 +70,7 @@ final class AccountHeaderView: UIView {
string: identityProof.providerUsername, string: identityProof.providerUsername,
attributes: [.link: identityProof.profileUrl]), attributes: [.link: identityProof.profileUrl]),
verifiedAt: identityProof.updatedAt, verifiedAt: identityProof.updatedAt,
emoji: []) emojis: [])
fieldView.valueTextView.delegate = self fieldView.valueTextView.delegate = self
@ -82,7 +82,7 @@ final class AccountHeaderView: UIView {
name: field.name, name: field.name,
value: field.value.attributed, value: field.value.attributed,
verifiedAt: field.verifiedAt, verifiedAt: field.verifiedAt,
emoji: accountViewModel.emoji) emojis: accountViewModel.emojis)
fieldView.valueTextView.delegate = self fieldView.valueTextView.delegate = self
@ -99,7 +99,7 @@ final class AccountHeaderView: UIView {
[.font: noteFont as Any, [.font: noteFont as Any,
.foregroundColor: UIColor.label], .foregroundColor: UIColor.label],
range: noteRange) range: noteRange)
mutableNote.insert(emoji: accountViewModel.emoji, view: noteTextView) mutableNote.insert(emojis: accountViewModel.emojis, view: noteTextView)
mutableNote.resizeAttachments(toLineHeight: noteFont.lineHeight) mutableNote.resizeAttachments(toLineHeight: noteFont.lineHeight)
noteTextView.attributedText = mutableNote noteTextView.attributedText = mutableNote
noteTextView.isHidden = false noteTextView.isHidden = false

View file

@ -103,7 +103,7 @@ private extension AccountView {
} else { } else {
let mutableDisplayName = NSMutableAttributedString(string: accountConfiguration.viewModel.displayName) let mutableDisplayName = NSMutableAttributedString(string: accountConfiguration.viewModel.displayName)
mutableDisplayName.insert(emoji: accountConfiguration.viewModel.emoji, view: displayNameLabel) mutableDisplayName.insert(emojis: accountConfiguration.viewModel.emojis, view: displayNameLabel)
mutableDisplayName.resizeAttachments(toLineHeight: displayNameLabel.font.lineHeight) mutableDisplayName.resizeAttachments(toLineHeight: displayNameLabel.font.lineHeight)
displayNameLabel.attributedText = mutableDisplayName displayNameLabel.attributedText = mutableDisplayName
} }
@ -119,7 +119,7 @@ private extension AccountView {
[.font: noteFont as Any, [.font: noteFont as Any,
.foregroundColor: UIColor.label], .foregroundColor: UIColor.label],
range: noteRange) range: noteRange)
mutableNote.insert(emoji: accountConfiguration.viewModel.emoji, view: noteTextView) mutableNote.insert(emojis: accountConfiguration.viewModel.emojis, view: noteTextView)
mutableNote.resizeAttachments(toLineHeight: noteFont.lineHeight) mutableNote.resizeAttachments(toLineHeight: noteFont.lineHeight)
noteTextView.attributedText = mutableNote noteTextView.attributedText = mutableNote

View file

@ -88,7 +88,7 @@ private extension ConversationView {
let mutableDisplayNames = NSMutableAttributedString(string: displayNames) let mutableDisplayNames = NSMutableAttributedString(string: displayNames)
mutableDisplayNames.insert( mutableDisplayNames.insert(
emoji: viewModel.accountViewModels.map(\.emoji).reduce([], +), emojis: viewModel.accountViewModels.map(\.emojis).reduce([], +),
view: displayNamesLabel) view: displayNamesLabel)
mutableDisplayNames.resizeAttachments(toLineHeight: displayNamesLabel.font.lineHeight) mutableDisplayNames.resizeAttachments(toLineHeight: displayNamesLabel.font.lineHeight)

View file

@ -5,12 +5,12 @@ import struct Mastodon.Emoji
struct CustomEmojiText: UIViewRepresentable { struct CustomEmojiText: UIViewRepresentable {
private let attributedText: NSMutableAttributedString private let attributedText: NSMutableAttributedString
private let emoji: [Emoji] private let emojis: [Emoji]
private let textStyle: UIFont.TextStyle private let textStyle: UIFont.TextStyle
init(text: String, emoji: [Emoji], textStyle: UIFont.TextStyle) { init(text: String, emojis: [Emoji], textStyle: UIFont.TextStyle) {
attributedText = NSMutableAttributedString(string: text) attributedText = NSMutableAttributedString(string: text)
self.emoji = emoji self.emojis = emojis
self.textStyle = textStyle self.textStyle = textStyle
} }
@ -18,7 +18,7 @@ struct CustomEmojiText: UIViewRepresentable {
let label = UILabel() let label = UILabel()
label.font = UIFont.preferredFont(forTextStyle: textStyle) label.font = UIFont.preferredFont(forTextStyle: textStyle)
attributedText.insert(emoji: emoji, view: label) attributedText.insert(emojis: emojis, view: label)
attributedText.resizeAttachments(toLineHeight: label.font.lineHeight) attributedText.resizeAttachments(toLineHeight: label.font.lineHeight)
label.attributedText = attributedText label.attributedText = attributedText

View file

@ -71,7 +71,7 @@ private extension IdentitiesView {
if let account = identity.account { if let account = identity.account {
CustomEmojiText( CustomEmojiText(
text: account.displayName, text: account.displayName,
emoji: account.emojis, emojis: account.emojis,
textStyle: .headline) textStyle: .headline)
} }
Text(identity.handle) Text(identity.handle)
@ -81,7 +81,7 @@ private extension IdentitiesView {
if let instance = identity.instance { if let instance = identity.instance {
CustomEmojiText( CustomEmojiText(
text: instance.title, text: instance.title,
emoji: [], emojis: [],
textStyle: .headline) textStyle: .headline)
Text(instance.uri) Text(instance.uri)
.font(.subheadline) .font(.subheadline)

View file

@ -130,19 +130,19 @@ private extension NotificationView {
case .follow: case .follow:
typeLabel.attributedText = "notifications.followed-you".localizedBolding( typeLabel.attributedText = "notifications.followed-you".localizedBolding(
displayName: viewModel.accountViewModel.displayName, displayName: viewModel.accountViewModel.displayName,
emoji: viewModel.accountViewModel.emoji, emojis: viewModel.accountViewModel.emojis,
label: typeLabel) label: typeLabel)
iconImageView.tintColor = nil iconImageView.tintColor = nil
case .reblog: case .reblog:
typeLabel.attributedText = "notifications.reblogged-your-status".localizedBolding( typeLabel.attributedText = "notifications.reblogged-your-status".localizedBolding(
displayName: viewModel.accountViewModel.displayName, displayName: viewModel.accountViewModel.displayName,
emoji: viewModel.accountViewModel.emoji, emojis: viewModel.accountViewModel.emojis,
label: typeLabel) label: typeLabel)
iconImageView.tintColor = .systemGreen iconImageView.tintColor = .systemGreen
case .favourite: case .favourite:
typeLabel.attributedText = "notifications.favourited-your-status".localizedBolding( typeLabel.attributedText = "notifications.favourited-your-status".localizedBolding(
displayName: viewModel.accountViewModel.displayName, displayName: viewModel.accountViewModel.displayName,
emoji: viewModel.accountViewModel.emoji, emojis: viewModel.accountViewModel.emojis,
label: typeLabel) label: typeLabel)
iconImageView.tintColor = .systemYellow iconImageView.tintColor = .systemYellow
case .poll: case .poll:
@ -155,7 +155,7 @@ private extension NotificationView {
default: default:
typeLabel.attributedText = "notifications.unknown".localizedBolding( typeLabel.attributedText = "notifications.unknown".localizedBolding(
displayName: viewModel.accountViewModel.displayName, displayName: viewModel.accountViewModel.displayName,
emoji: viewModel.accountViewModel.emoji, emojis: viewModel.accountViewModel.emojis,
label: typeLabel) label: typeLabel)
iconImageView.tintColor = nil iconImageView.tintColor = nil
} }
@ -163,7 +163,7 @@ private extension NotificationView {
if viewModel.statusViewModel == nil { if viewModel.statusViewModel == nil {
let mutableDisplayName = NSMutableAttributedString(string: viewModel.accountViewModel.displayName) let mutableDisplayName = NSMutableAttributedString(string: viewModel.accountViewModel.displayName)
mutableDisplayName.insert(emoji: viewModel.accountViewModel.emoji, view: displayNameLabel) mutableDisplayName.insert(emojis: viewModel.accountViewModel.emojis, view: displayNameLabel)
mutableDisplayName.resizeAttachments(toLineHeight: displayNameLabel.font.lineHeight) mutableDisplayName.resizeAttachments(toLineHeight: displayNameLabel.font.lineHeight)
displayNameLabel.attributedText = mutableDisplayName displayNameLabel.attributedText = mutableDisplayName
accountLabel.text = viewModel.accountViewModel.accountName accountLabel.text = viewModel.accountViewModel.accountName

View file

@ -4,7 +4,7 @@ import Mastodon
import UIKit import UIKit
final class PollOptionButton: UIButton { final class PollOptionButton: UIButton {
init(title: String, emoji: [Emoji], multipleSelection: Bool) { init(title: String, emojis: [Emoji], multipleSelection: Bool) {
super.init(frame: .zero) super.init(frame: .zero)
titleLabel?.font = .preferredFont(forTextStyle: .callout) titleLabel?.font = .preferredFont(forTextStyle: .callout)
@ -16,7 +16,7 @@ final class PollOptionButton: UIButton {
let attributedTitle = NSMutableAttributedString(string: title) let attributedTitle = NSMutableAttributedString(string: title)
attributedTitle.insert(emoji: emoji, view: titleLabel!) attributedTitle.insert(emojis: emojis, view: titleLabel!)
attributedTitle.resizeAttachments(toLineHeight: titleLabel!.font.lineHeight) attributedTitle.resizeAttachments(toLineHeight: titleLabel!.font.lineHeight)
setAttributedTitle(attributedTitle, for: .normal) setAttributedTitle(attributedTitle, for: .normal)
setImage( setImage(

View file

@ -10,7 +10,7 @@ final class PollResultView: UIView {
private let percentLabel = UILabel() private let percentLabel = UILabel()
private let percentView = UIProgressView() private let percentView = UIProgressView()
init(option: Poll.Option, emoji: [Emoji], selected: Bool, multipleSelection: Bool, votersCount: Int) { init(option: Poll.Option, emojis: [Emoji], selected: Bool, multipleSelection: Bool, votersCount: Int) {
super.init(frame: .zero) super.init(frame: .zero)
addSubview(verticalStackView) addSubview(verticalStackView)
@ -45,7 +45,7 @@ final class PollResultView: UIView {
let attributedTitle = NSMutableAttributedString(string: option.title) let attributedTitle = NSMutableAttributedString(string: option.title)
attributedTitle.insert(emoji: emoji, view: titleLabel) attributedTitle.insert(emojis: emojis, view: titleLabel)
attributedTitle.resizeAttachments(toLineHeight: titleLabel.font.lineHeight) attributedTitle.resizeAttachments(toLineHeight: titleLabel.font.lineHeight)
titleLabel.attributedText = attributedTitle titleLabel.attributedText = attributedTitle

View file

@ -33,7 +33,7 @@ final class PollView: UIView {
for (index, option) in viewModel.pollOptions.enumerated() { for (index, option) in viewModel.pollOptions.enumerated() {
let button = PollOptionButton( let button = PollOptionButton(
title: option.title, title: option.title,
emoji: viewModel.pollEmoji, emojis: viewModel.pollEmojis,
multipleSelection: viewModel.isPollMultipleSelection) multipleSelection: viewModel.isPollMultipleSelection)
button.addAction( button.addAction(
@ -54,7 +54,7 @@ final class PollView: UIView {
for (index, option) in viewModel.pollOptions.enumerated() { for (index, option) in viewModel.pollOptions.enumerated() {
let resultView = PollResultView( let resultView = PollResultView(
option: option, option: option,
emoji: viewModel.pollEmoji, emojis: viewModel.pollEmojis,
selected: viewModel.pollOwnVotes.contains(index), selected: viewModel.pollOwnVotes.contains(index),
multipleSelection: viewModel.isPollMultipleSelection, multipleSelection: viewModel.isPollMultipleSelection,
votersCount: viewModel.pollVotersCount) votersCount: viewModel.pollVotersCount)

View file

@ -24,7 +24,7 @@ struct SecondaryNavigationView: View {
if let account = viewModel.identification.identity.account { if let account = viewModel.identification.identity.account {
CustomEmojiText( CustomEmojiText(
text: account.displayName, text: account.displayName,
emoji: account.emojis, emojis: account.emojis,
textStyle: .headline) textStyle: .headline)
} }
Text(viewModel.identification.identity.handle) Text(viewModel.identification.identity.handle)

View file

@ -27,12 +27,12 @@ final class StatusBodyView: UIView {
mutableContent.addAttributes( mutableContent.addAttributes(
[.font: contentFont, .foregroundColor: UIColor.label], [.font: contentFont, .foregroundColor: UIColor.label],
range: contentRange) range: contentRange)
mutableContent.insert(emoji: viewModel.contentEmoji, view: contentTextView) mutableContent.insert(emojis: viewModel.contentEmojis, view: contentTextView)
mutableContent.resizeAttachments(toLineHeight: contentFont.lineHeight) mutableContent.resizeAttachments(toLineHeight: contentFont.lineHeight)
contentTextView.attributedText = mutableContent contentTextView.attributedText = mutableContent
contentTextView.isHidden = contentTextView.text.isEmpty contentTextView.isHidden = contentTextView.text.isEmpty
mutableSpoilerText.insert(emoji: viewModel.contentEmoji, view: spoilerTextLabel) mutableSpoilerText.insert(emojis: viewModel.contentEmojis, view: spoilerTextLabel)
mutableSpoilerText.resizeAttachments(toLineHeight: spoilerTextLabel.font.lineHeight) mutableSpoilerText.resizeAttachments(toLineHeight: spoilerTextLabel.font.lineHeight)
spoilerTextLabel.font = contentFont spoilerTextLabel.font = contentFont
spoilerTextLabel.attributedText = mutableSpoilerText spoilerTextLabel.attributedText = mutableSpoilerText

View file

@ -301,7 +301,7 @@ private extension StatusView {
if viewModel.isReblog { if viewModel.isReblog {
infoLabel.attributedText = "status.reblogged-by".localizedBolding( infoLabel.attributedText = "status.reblogged-by".localizedBolding(
displayName: viewModel.rebloggedByDisplayName, displayName: viewModel.rebloggedByDisplayName,
emoji: viewModel.rebloggedByDisplayNameEmoji, emojis: viewModel.rebloggedByDisplayNameEmojis,
label: infoLabel) label: infoLabel)
infoIcon.image = UIImage( infoIcon.image = UIImage(
systemName: "arrow.2.squarepath", systemName: "arrow.2.squarepath",
@ -320,7 +320,7 @@ private extension StatusView {
infoIcon.isHidden = true infoIcon.isHidden = true
} }
mutableDisplayName.insert(emoji: viewModel.displayNameEmoji, view: displayNameLabel) mutableDisplayName.insert(emojis: viewModel.displayNameEmojis, view: displayNameLabel)
mutableDisplayName.resizeAttachments(toLineHeight: displayNameLabel.font.lineHeight) mutableDisplayName.resizeAttachments(toLineHeight: displayNameLabel.font.lineHeight)
displayNameLabel.attributedText = mutableDisplayName displayNameLabel.attributedText = mutableDisplayName