forked from zelo72/mastodon-ios
fix: title view label missing custom emoji issue
This commit is contained in:
parent
66643e1058
commit
ce3ac2bfd2
|
@ -56,7 +56,7 @@ extension HashtagTimelineViewController {
|
|||
super.viewDidLoad()
|
||||
|
||||
title = "#\(viewModel.hashtag)"
|
||||
titleView.update(title: viewModel.hashtag, subtitle: nil)
|
||||
titleView.update(title: viewModel.hashtag, subtitle: nil, emojiDict: [:])
|
||||
navigationItem.titleView = titleView
|
||||
|
||||
view.backgroundColor = Asset.Colors.Background.secondarySystemBackground.color
|
||||
|
@ -143,7 +143,7 @@ extension HashtagTimelineViewController {
|
|||
private func updatePromptTitle() {
|
||||
var subtitle: String?
|
||||
defer {
|
||||
titleView.update(title: "#" + viewModel.hashtag, subtitle: subtitle)
|
||||
titleView.update(title: "#" + viewModel.hashtag, subtitle: subtitle, emojiDict: [:])
|
||||
}
|
||||
guard let histories = viewModel.hashtagEntity.value?.history else {
|
||||
return
|
||||
|
|
|
@ -49,7 +49,7 @@ extension FavoriteViewController {
|
|||
|
||||
view.backgroundColor = Asset.Colors.Background.secondarySystemBackground.color
|
||||
navigationItem.titleView = titleView
|
||||
titleView.update(title: L10n.Scene.Favorite.title, subtitle: nil)
|
||||
titleView.update(title: L10n.Scene.Favorite.title, subtitle: nil, emojiDict: [:])
|
||||
|
||||
tableView.translatesAutoresizingMaskIntoConstraints = false
|
||||
view.addSubview(tableView)
|
||||
|
|
|
@ -13,6 +13,7 @@ import ActiveLabel
|
|||
import AlamofireImage
|
||||
import CropViewController
|
||||
import TwitterTextEditor
|
||||
import MastodonMeta
|
||||
|
||||
protocol ProfileHeaderViewControllerDelegate: AnyObject {
|
||||
func profileHeaderViewController(_ viewController: ProfileHeaderViewController, viewLayoutDidUpdate view: UIView)
|
||||
|
@ -166,14 +167,27 @@ extension ProfileHeaderViewController {
|
|||
)
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
Publishers.CombineLatest3(
|
||||
viewModel.isEditing.eraseToAnyPublisher(),
|
||||
viewModel.displayProfileInfo.name.removeDuplicates().eraseToAnyPublisher(),
|
||||
viewModel.editProfileInfo.name.removeDuplicates().eraseToAnyPublisher()
|
||||
Publishers.CombineLatest4(
|
||||
viewModel.isEditing,
|
||||
viewModel.displayProfileInfo.name.removeDuplicates(),
|
||||
viewModel.editProfileInfo.name.removeDuplicates(),
|
||||
viewModel.emojiDict
|
||||
)
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] isEditing, name, editingName in
|
||||
.sink { [weak self] isEditing, name, editingName, emojiDict in
|
||||
guard let self = self else { return }
|
||||
do {
|
||||
var emojis = MastodonContent.Emojis()
|
||||
for (key, value) in emojiDict {
|
||||
emojis[key] = value.absoluteString
|
||||
}
|
||||
let metaContent = try MastodonMetaContent.convert(
|
||||
document: MastodonContent(content: name ?? " ", emojis: emojis)
|
||||
)
|
||||
self.profileHeaderView.nameMetaText.configure(content: metaContent)
|
||||
} catch {
|
||||
assertionFailure()
|
||||
}
|
||||
self.profileHeaderView.nameTextField.text = isEditing ? editingName : name
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
|
@ -412,7 +426,7 @@ extension ProfileHeaderViewController {
|
|||
profileHeaderView.avatarImageView.alpha = alpha
|
||||
profileHeaderView.editAvatarBackgroundView.alpha = alpha
|
||||
profileHeaderView.nameTextFieldBackgroundView.alpha = alpha
|
||||
profileHeaderView.nameTextField.alpha = alpha
|
||||
profileHeaderView.displayNameStackView.alpha = alpha
|
||||
profileHeaderView.usernameLabel.alpha = alpha
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ import UIKit
|
|||
import ActiveLabel
|
||||
import TwitterTextEditor
|
||||
import FLAnimatedImage
|
||||
import MetaTextView
|
||||
|
||||
protocol ProfileHeaderViewDelegate: AnyObject {
|
||||
func profileHeaderView(_ profileHeaderView: ProfileHeaderView, avatarImageViewDidPressed imageView: UIImageView)
|
||||
|
@ -111,7 +112,24 @@ final class ProfileHeaderView: UIView {
|
|||
view.layer.cornerRadius = 10
|
||||
return view
|
||||
}()
|
||||
|
||||
|
||||
let displayNameStackView = UIStackView()
|
||||
let nameMetaText: MetaText = {
|
||||
let metaText = MetaText()
|
||||
metaText.textView.backgroundColor = .clear
|
||||
metaText.textView.isEditable = false
|
||||
metaText.textView.isSelectable = false
|
||||
metaText.textView.isScrollEnabled = false
|
||||
metaText.textView.layer.masksToBounds = false
|
||||
metaText.textView.font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 20, weight: .semibold), maximumPointSize: 28)
|
||||
metaText.textView.textColor = .white
|
||||
metaText.textView.textContainer.lineFragmentPadding = 0
|
||||
metaText.textAttributes = [
|
||||
.font: UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 20, weight: .semibold), maximumPointSize: 28),
|
||||
.foregroundColor: UIColor.white
|
||||
]
|
||||
return metaText
|
||||
}()
|
||||
let nameTextField: UITextField = {
|
||||
let textField = UITextField()
|
||||
textField.font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 20, weight: .semibold), maximumPointSize: 28)
|
||||
|
@ -303,7 +321,6 @@ extension ProfileHeaderView {
|
|||
nameContainerStackView.centerYAnchor.constraint(equalTo: avatarImageView.centerYAnchor),
|
||||
])
|
||||
|
||||
let displayNameStackView = UIStackView()
|
||||
displayNameStackView.axis = .horizontal
|
||||
nameTextField.translatesAutoresizingMaskIntoConstraints = false
|
||||
displayNameStackView.addArrangedSubview(nameTextField)
|
||||
|
@ -321,6 +338,16 @@ extension ProfileHeaderView {
|
|||
])
|
||||
displayNameStackView.bringSubviewToFront(nameTextField)
|
||||
displayNameStackView.addArrangedSubview(UIView())
|
||||
|
||||
// overlay meta text for display name
|
||||
nameMetaText.textView.translatesAutoresizingMaskIntoConstraints = false
|
||||
displayNameStackView.addSubview(nameMetaText.textView)
|
||||
NSLayoutConstraint.activate([
|
||||
nameMetaText.textView.topAnchor.constraint(equalTo: nameTextField.topAnchor),
|
||||
nameMetaText.textView.leadingAnchor.constraint(equalTo: nameTextField.leadingAnchor),
|
||||
nameMetaText.textView.trailingAnchor.constraint(equalTo: nameTextField.trailingAnchor),
|
||||
nameMetaText.textView.bottomAnchor.constraint(equalTo: nameTextField.bottomAnchor),
|
||||
])
|
||||
|
||||
nameContainerStackView.addArrangedSubview(displayNameStackView)
|
||||
nameContainerStackView.addArrangedSubview(usernameLabel)
|
||||
|
@ -436,6 +463,8 @@ extension ProfileHeaderView {
|
|||
|
||||
switch state {
|
||||
case .normal:
|
||||
nameMetaText.textView.alpha = 1
|
||||
nameTextField.alpha = 0
|
||||
nameTextField.isEnabled = false
|
||||
bioActiveLabelContainer.isHidden = false
|
||||
bioTextEditorView.isHidden = true
|
||||
|
@ -449,7 +478,9 @@ extension ProfileHeaderView {
|
|||
self.editAvatarBackgroundView.isHidden = true
|
||||
}
|
||||
case .editing:
|
||||
nameMetaText.textView.alpha = 0
|
||||
nameTextField.isEnabled = true
|
||||
nameTextField.alpha = 1
|
||||
bioActiveLabelContainer.isHidden = true
|
||||
bioTextEditorView.isHidden = false
|
||||
|
||||
|
|
|
@ -303,12 +303,13 @@ extension ProfileViewController {
|
|||
profileSegmentedViewController.pagingViewController.pagingDelegate = self
|
||||
|
||||
// bind view model
|
||||
Publishers.CombineLatest(
|
||||
viewModel.name.eraseToAnyPublisher(),
|
||||
viewModel.statusesCount.eraseToAnyPublisher()
|
||||
Publishers.CombineLatest3(
|
||||
viewModel.name,
|
||||
viewModel.emojiDict,
|
||||
viewModel.statusesCount
|
||||
)
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] name, statusesCount in
|
||||
.sink { [weak self] name, emojiDict, statusesCount in
|
||||
guard let self = self else { return }
|
||||
guard let title = name, let statusesCount = statusesCount,
|
||||
let formattedStatusCount = MastodonMetricFormatter().string(from: statusesCount) else {
|
||||
|
@ -316,7 +317,7 @@ extension ProfileViewController {
|
|||
return
|
||||
}
|
||||
let subtitle = L10n.Scene.Profile.subtitle(formattedStatusCount)
|
||||
self.titleView.update(title: title, subtitle: subtitle)
|
||||
self.titleView.update(title: title, subtitle: subtitle, emojiDict: emojiDict)
|
||||
self.titleView.isHidden = false
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
|
@ -368,7 +369,7 @@ extension ProfileViewController {
|
|||
.receive(on: DispatchQueue.main)
|
||||
.assign(to: \.value, on: profileHeaderViewController.viewModel.displayProfileInfo.name)
|
||||
.store(in: &disposeBag)
|
||||
viewModel.fileds
|
||||
viewModel.fields
|
||||
.removeDuplicates()
|
||||
.map { fields -> [ProfileFieldItem.FieldValue] in
|
||||
fields.map { ProfileFieldItem.FieldValue(name: $0.name, value: $0.value) }
|
||||
|
|
|
@ -39,7 +39,7 @@ class ProfileViewModel: NSObject {
|
|||
let statusesCount: CurrentValueSubject<Int?, Never>
|
||||
let followingCount: CurrentValueSubject<Int?, Never>
|
||||
let followersCount: CurrentValueSubject<Int?, Never>
|
||||
let fileds: CurrentValueSubject<[Mastodon.Entity.Field], Never>
|
||||
let fields: CurrentValueSubject<[Mastodon.Entity.Field], Never>
|
||||
let emojiDict: CurrentValueSubject<MastodonStatusContent.EmojiDict, Never>
|
||||
|
||||
// fulfill this before editing
|
||||
|
@ -82,7 +82,7 @@ class ProfileViewModel: NSObject {
|
|||
self.followersCount = CurrentValueSubject(mastodonUser.flatMap { Int(truncating: $0.followersCount) })
|
||||
self.protected = CurrentValueSubject(mastodonUser?.locked)
|
||||
self.suspended = CurrentValueSubject(mastodonUser?.suspended ?? false)
|
||||
self.fileds = CurrentValueSubject(mastodonUser?.fields ?? [])
|
||||
self.fields = CurrentValueSubject(mastodonUser?.fields ?? [])
|
||||
self.emojiDict = CurrentValueSubject(mastodonUser?.emojiDict ?? [:])
|
||||
super.init()
|
||||
|
||||
|
@ -257,7 +257,7 @@ extension ProfileViewModel {
|
|||
self.followersCount.value = mastodonUser.flatMap { Int(truncating: $0.followersCount) }
|
||||
self.protected.value = mastodonUser?.locked
|
||||
self.suspended.value = mastodonUser?.suspended ?? false
|
||||
self.fileds.value = mastodonUser?.fields ?? []
|
||||
self.fields.value = mastodonUser?.fields ?? []
|
||||
self.emojiDict.value = mastodonUser?.emojiDict ?? [:]
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ import CoreDataStack
|
|||
import Foundation
|
||||
import MastodonSDK
|
||||
import UIKit
|
||||
import ActiveLabel
|
||||
|
||||
protocol SearchRecommendAccountsCollectionViewCellDelegate: NSObject {
|
||||
func followButtonDidPressed(clickedUser: MastodonUser)
|
||||
|
@ -42,8 +43,8 @@ class SearchRecommendAccountsCollectionViewCell: UICollectionViewCell {
|
|||
|
||||
let visualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .regular))
|
||||
|
||||
let displayNameLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
let displayNameLabel: ActiveLabel = {
|
||||
let label = ActiveLabel(style: .statusName)
|
||||
label.textColor = .white
|
||||
label.textAlignment = .center
|
||||
label.font = .systemFont(ofSize: 18, weight: .semibold)
|
||||
|
@ -164,7 +165,7 @@ extension SearchRecommendAccountsCollectionViewCell {
|
|||
}
|
||||
|
||||
func config(with mastodonUser: MastodonUser) {
|
||||
displayNameLabel.text = mastodonUser.displayName.isEmpty ? mastodonUser.username : mastodonUser.displayName
|
||||
displayNameLabel.configure(content: mastodonUser.displayNameWithFallback, emojiDict: mastodonUser.emojiDict)
|
||||
acctLabel.text = "@" + mastodonUser.acct
|
||||
avatarImageView.af.setImage(
|
||||
withURL: URL(string: mastodonUser.avatar)!,
|
||||
|
|
|
@ -6,13 +6,14 @@
|
|||
//
|
||||
|
||||
import UIKit
|
||||
import ActiveLabel
|
||||
|
||||
final class DoubleTitleLabelNavigationBarTitleView: UIView {
|
||||
|
||||
let containerView = UIStackView()
|
||||
|
||||
let titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
let titleLabel: ActiveLabel = {
|
||||
let label = ActiveLabel(style: .default)
|
||||
label.font = .systemFont(ofSize: 17, weight: .semibold)
|
||||
label.textColor = Asset.Colors.Label.primary.color
|
||||
label.textAlignment = .center
|
||||
|
@ -58,8 +59,8 @@ extension DoubleTitleLabelNavigationBarTitleView {
|
|||
containerView.addArrangedSubview(subtitleLabel)
|
||||
}
|
||||
|
||||
func update(title: String, subtitle: String?) {
|
||||
titleLabel.text = title
|
||||
func update(title: String, subtitle: String?, emojiDict: MastodonStatusContent.EmojiDict) {
|
||||
titleLabel.configure(content: title, emojiDict: emojiDict)
|
||||
if let subtitle = subtitle {
|
||||
subtitleLabel.text = subtitle
|
||||
subtitleLabel.isHidden = false
|
||||
|
|
|
@ -11,6 +11,7 @@ import CoreDataStack
|
|||
import Foundation
|
||||
import MastodonSDK
|
||||
import UIKit
|
||||
import ActiveLabel
|
||||
|
||||
protocol SuggestionAccountTableViewCellDelegate: AnyObject {
|
||||
func accountButtonPressed(objectID: NSManagedObjectID, cell: SuggestionAccountTableViewCell)
|
||||
|
@ -28,8 +29,8 @@ final class SuggestionAccountTableViewCell: UITableViewCell {
|
|||
return imageView
|
||||
}()
|
||||
|
||||
let titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
let titleLabel: ActiveLabel = {
|
||||
let label = ActiveLabel(style: .statusName)
|
||||
label.textColor = Asset.Colors.brandBlue.color
|
||||
label.font = .systemFont(ofSize: 17, weight: .semibold)
|
||||
label.lineBreakMode = .byTruncatingTail
|
||||
|
@ -153,7 +154,7 @@ extension SuggestionAccountTableViewCell {
|
|||
imageTransition: .crossDissolve(0.2)
|
||||
)
|
||||
}
|
||||
titleLabel.text = account.displayName.isEmpty ? account.username : account.displayName
|
||||
titleLabel.configure(content: account.displayNameWithFallback, emojiDict: account.emojiDict)
|
||||
subTitleLabel.text = account.acct
|
||||
button.isSelected = isSelected
|
||||
button.publisher(for: .touchUpInside)
|
||||
|
|
|
@ -80,9 +80,13 @@ extension ThreadViewController {
|
|||
|
||||
viewModel.navigationBarTitle
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] title in
|
||||
.sink { [weak self] tuple in
|
||||
guard let self = self else { return }
|
||||
self.titleView.update(title: title ?? L10n.Scene.Thread.backTitle, subtitle: nil)
|
||||
guard let (title, emojiDict) = tuple else {
|
||||
self.titleView.update(title: L10n.Scene.Thread.backTitle, subtitle: nil, emojiDict: [:])
|
||||
return
|
||||
}
|
||||
self.titleView.update(title: title, subtitle: nil, emojiDict: emojiDict)
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ class ThreadViewModel {
|
|||
let ancestorItems = CurrentValueSubject<[Item], Never>([])
|
||||
let descendantNodes = CurrentValueSubject<[LeafNode], Never>([])
|
||||
let descendantItems = CurrentValueSubject<[Item], Never>([])
|
||||
let navigationBarTitle: CurrentValueSubject<String?, Never>
|
||||
let navigationBarTitle: CurrentValueSubject<(String, MastodonStatusContent.EmojiDict)?, Never>
|
||||
|
||||
init(context: AppContext, optionalStatus: Status?) {
|
||||
self.context = context
|
||||
|
@ -53,7 +53,7 @@ class ThreadViewModel {
|
|||
self.rootItem = CurrentValueSubject(optionalStatus.flatMap { Item.root(statusObjectID: $0.objectID, attribute: Item.StatusAttribute()) })
|
||||
self.existStatusFetchedResultsController = StatusFetchedResultsController(managedObjectContext: context.managedObjectContext, domain: nil, additionalTweetPredicate: nil)
|
||||
self.navigationBarTitle = CurrentValueSubject(
|
||||
optionalStatus.flatMap { L10n.Scene.Thread.title($0.author.displayNameWithFallback) }
|
||||
optionalStatus.flatMap { (L10n.Scene.Thread.title($0.author.displayNameWithFallback), $0.emojiDict) }
|
||||
)
|
||||
|
||||
// bind fetcher domain
|
||||
|
@ -85,7 +85,7 @@ class ThreadViewModel {
|
|||
return
|
||||
}
|
||||
self.rootNode.value = RootNode(domain: status.domain, statusID: status.id, replyToID: status.inReplyToID)
|
||||
self.navigationBarTitle.value = L10n.Scene.Thread.title(status.author.displayNameWithFallback)
|
||||
self.navigationBarTitle.value = (L10n.Scene.Thread.title(status.author.displayNameWithFallback), status.author.emojiDict)
|
||||
}
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
|
|
Loading…
Reference in New Issue