From bac8721aec92b68e41124540660c44102b4c470c Mon Sep 17 00:00:00 2001 From: CMK Date: Tue, 29 Jun 2021 19:19:14 +0800 Subject: [PATCH 1/6] fix: make recommend trigger refresh when view appear. resolve #164 --- Mastodon/Scene/Search/SearchViewController.swift | 6 ++++++ Mastodon/Scene/Search/SearchViewModel.swift | 14 +++++++++----- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/Mastodon/Scene/Search/SearchViewController.swift b/Mastodon/Scene/Search/SearchViewController.swift index 3731f118b..10dd46119 100644 --- a/Mastodon/Scene/Search/SearchViewController.swift +++ b/Mastodon/Scene/Search/SearchViewController.swift @@ -151,6 +151,12 @@ extension SearchViewController { view.bringSubviewToFront(statusBar) } + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + + viewModel.viewDidAppeared.send() + } + func setupSearchBar() { searchBar.delegate = self view.addSubview(searchBar) diff --git a/Mastodon/Scene/Search/SearchViewModel.swift b/Mastodon/Scene/Search/SearchViewModel.swift index e10b04c9e..48bd87b88 100644 --- a/Mastodon/Scene/Search/SearchViewModel.swift +++ b/Mastodon/Scene/Search/SearchViewModel.swift @@ -23,6 +23,7 @@ final class SearchViewModel: NSObject { let mastodonUser = CurrentValueSubject(nil) let currentMastodonUser = CurrentValueSubject(nil) + let viewDidAppeared = PassthroughSubject() // output let searchText = CurrentValueSubject("") @@ -145,9 +146,10 @@ final class SearchViewModel: NSObject { dataSource.apply(snapshot, animatingDifferences: false, completion: nil) } .store(in: &disposeBag) - - requestRecommendHashTags() - .receive(on: DispatchQueue.main) + + viewDidAppeared + .compactMap { _ in self.requestRecommendHashTags() } + .receive(on: RunLoop.main) .sink { [weak self] _ in guard let self = self else { return } if !self.recommendHashTags.isEmpty { @@ -160,8 +162,9 @@ final class SearchViewModel: NSObject { } receiveValue: { _ in } .store(in: &disposeBag) - - requestRecommendAccountsV2() + viewDidAppeared + .compactMap { _ in self.requestRecommendAccountsV2() } + .receive(on: RunLoop.main) .sink { [weak self] _ in guard let self = self else { return } if !self.recommendAccounts.isEmpty { @@ -172,6 +175,7 @@ final class SearchViewModel: NSObject { .store(in: &disposeBag) recommendAccountsFallback + .receive(on: RunLoop.main) .sink { [weak self] _ in guard let self = self else { return } self.requestRecommendAccounts() From 71cb19ccaeb1c755d20e93b5bab1bca2af9e5995 Mon Sep 17 00:00:00 2001 From: CMK Date: Tue, 29 Jun 2021 19:19:55 +0800 Subject: [PATCH 2/6] fix: auto-complete emoji may crash issue --- Mastodon.xcodeproj/project.pbxproj | 2 +- .../mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist | 4 ++-- Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 674f1d72c..da036e65d 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4778,7 +4778,7 @@ repositoryURL = "https://github.com/TwidereProject/MetaTextView.git"; requirement = { kind = exactVersion; - version = 1.2.1; + version = 1.2.2; }; }; DB0E2D2C26833FF600865C3C /* XCRemoteSwiftPackageReference "Nuke-FLAnimatedImage-Plugin" */ = { diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index b782cd198..ebbde8329 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -12,7 +12,7 @@ CoreDataStack.xcscheme_^#shared#^_ orderHint - 23 + 21 Mastodon - ASDK.xcscheme_^#shared#^_ @@ -37,7 +37,7 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 21 + 22 SuppressBuildableAutocreation diff --git a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved index d3b943377..fcd3317da 100644 --- a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -114,8 +114,8 @@ "repositoryURL": "https://github.com/TwidereProject/MetaTextView.git", "state": { "branch": null, - "revision": "2660fc30ef6ed8de347ddca499341a965d1fda56", - "version": "1.2.1" + "revision": "d48cf6a2479ce6fc4f836b6c4d7ba855cdbc71cc", + "version": "1.2.2" } }, { From 66643e10582cec18780bc04a00e6e8ae6eebc666 Mon Sep 17 00:00:00 2001 From: CMK Date: Tue, 29 Jun 2021 19:27:08 +0800 Subject: [PATCH 3/6] fix: disable drag and link preview for text editor in compose scene --- .../Scene/Compose/ComposeViewController.swift | 16 ++++++++++++++++ .../ComposeStatusContentTableViewCell.swift | 1 + 2 files changed, 17 insertions(+) diff --git a/Mastodon/Scene/Compose/ComposeViewController.swift b/Mastodon/Scene/Compose/ComposeViewController.swift index c13cedb8c..361aff090 100644 --- a/Mastodon/Scene/Compose/ComposeViewController.swift +++ b/Mastodon/Scene/Compose/ComposeViewController.swift @@ -767,6 +767,22 @@ extension ComposeViewController: UITextViewDelegate { return autoCompleteInfo } + func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool { + if textView === textEditorView()?.textView { + return false + } + + return true + } + + func textView(_ textView: UITextView, shouldInteractWith textAttachment: NSTextAttachment, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool { + if textView === textEditorView()?.textView { + return false + } + + return true + } + } // MARK: - TextEditorViewTextAttributesDelegate diff --git a/Mastodon/Scene/Compose/TableViewCell/ComposeStatusContentTableViewCell.swift b/Mastodon/Scene/Compose/TableViewCell/ComposeStatusContentTableViewCell.swift index 9946b1c9c..6ada8d7c5 100644 --- a/Mastodon/Scene/Compose/TableViewCell/ComposeStatusContentTableViewCell.swift +++ b/Mastodon/Scene/Compose/TableViewCell/ComposeStatusContentTableViewCell.swift @@ -27,6 +27,7 @@ final class ComposeStatusContentTableViewCell: UITableViewCell { metaText.textView.backgroundColor = .clear metaText.textView.isScrollEnabled = false metaText.textView.keyboardType = .twitter + metaText.textView.textDragInteraction?.isEnabled = false // disable drag for link and attachment metaText.textView.textContainer.lineFragmentPadding = 10 // leading inset metaText.textView.font = UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 17, weight: .regular)) metaText.textView.attributedPlaceholder = { From ce3ac2bfd2efe0d32032e3551e08b28964c9d952 Mon Sep 17 00:00:00 2001 From: CMK Date: Tue, 29 Jun 2021 19:27:40 +0800 Subject: [PATCH 4/6] fix: title view label missing custom emoji issue --- .../HashtagTimelineViewController.swift | 4 +-- .../Favorite/FavoriteViewController.swift | 2 +- .../Header/ProfileHeaderViewController.swift | 26 ++++++++++---- .../Header/View/ProfileHeaderView.swift | 35 +++++++++++++++++-- .../Scene/Profile/ProfileViewController.swift | 13 +++---- Mastodon/Scene/Profile/ProfileViewModel.swift | 6 ++-- ...hRecommendAccountsCollectionViewCell.swift | 7 ++-- ...ubleTitleLabelNavigationBarTitleView.swift | 9 ++--- .../SuggestionAccountTableViewCell.swift | 7 ++-- .../Scene/Thread/ThreadViewController.swift | 8 +++-- Mastodon/Scene/Thread/ThreadViewModel.swift | 6 ++-- 11 files changed, 88 insertions(+), 35 deletions(-) diff --git a/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewController.swift b/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewController.swift index eb7753337..ee5c44971 100644 --- a/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewController.swift +++ b/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewController.swift @@ -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 diff --git a/Mastodon/Scene/Profile/Favorite/FavoriteViewController.swift b/Mastodon/Scene/Profile/Favorite/FavoriteViewController.swift index 46b88796e..d34240a85 100644 --- a/Mastodon/Scene/Profile/Favorite/FavoriteViewController.swift +++ b/Mastodon/Scene/Profile/Favorite/FavoriteViewController.swift @@ -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) diff --git a/Mastodon/Scene/Profile/Header/ProfileHeaderViewController.swift b/Mastodon/Scene/Profile/Header/ProfileHeaderViewController.swift index 48470a241..94be3e6f5 100644 --- a/Mastodon/Scene/Profile/Header/ProfileHeaderViewController.swift +++ b/Mastodon/Scene/Profile/Header/ProfileHeaderViewController.swift @@ -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 } diff --git a/Mastodon/Scene/Profile/Header/View/ProfileHeaderView.swift b/Mastodon/Scene/Profile/Header/View/ProfileHeaderView.swift index f9f2e98d4..abeac9855 100644 --- a/Mastodon/Scene/Profile/Header/View/ProfileHeaderView.swift +++ b/Mastodon/Scene/Profile/Header/View/ProfileHeaderView.swift @@ -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 diff --git a/Mastodon/Scene/Profile/ProfileViewController.swift b/Mastodon/Scene/Profile/ProfileViewController.swift index 476d03a9d..7b6a1db86 100644 --- a/Mastodon/Scene/Profile/ProfileViewController.swift +++ b/Mastodon/Scene/Profile/ProfileViewController.swift @@ -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) } diff --git a/Mastodon/Scene/Profile/ProfileViewModel.swift b/Mastodon/Scene/Profile/ProfileViewModel.swift index ddd1ee291..45a2386be 100644 --- a/Mastodon/Scene/Profile/ProfileViewModel.swift +++ b/Mastodon/Scene/Profile/ProfileViewModel.swift @@ -39,7 +39,7 @@ class ProfileViewModel: NSObject { let statusesCount: CurrentValueSubject let followingCount: CurrentValueSubject let followersCount: CurrentValueSubject - let fileds: CurrentValueSubject<[Mastodon.Entity.Field], Never> + let fields: CurrentValueSubject<[Mastodon.Entity.Field], Never> let emojiDict: CurrentValueSubject // 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 ?? [:] } diff --git a/Mastodon/Scene/Search/CollectionViewCell/SearchRecommendAccountsCollectionViewCell.swift b/Mastodon/Scene/Search/CollectionViewCell/SearchRecommendAccountsCollectionViewCell.swift index d76cb24bd..b69914dbe 100644 --- a/Mastodon/Scene/Search/CollectionViewCell/SearchRecommendAccountsCollectionViewCell.swift +++ b/Mastodon/Scene/Search/CollectionViewCell/SearchRecommendAccountsCollectionViewCell.swift @@ -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)!, diff --git a/Mastodon/Scene/Share/View/Content/DoubleTitleLabelNavigationBarTitleView.swift b/Mastodon/Scene/Share/View/Content/DoubleTitleLabelNavigationBarTitleView.swift index b136859a8..33ef86dd0 100644 --- a/Mastodon/Scene/Share/View/Content/DoubleTitleLabelNavigationBarTitleView.swift +++ b/Mastodon/Scene/Share/View/Content/DoubleTitleLabelNavigationBarTitleView.swift @@ -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 diff --git a/Mastodon/Scene/SuggestionAccount/TableViewCell/SuggestionAccountTableViewCell.swift b/Mastodon/Scene/SuggestionAccount/TableViewCell/SuggestionAccountTableViewCell.swift index db56d63ca..221f9a208 100644 --- a/Mastodon/Scene/SuggestionAccount/TableViewCell/SuggestionAccountTableViewCell.swift +++ b/Mastodon/Scene/SuggestionAccount/TableViewCell/SuggestionAccountTableViewCell.swift @@ -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) diff --git a/Mastodon/Scene/Thread/ThreadViewController.swift b/Mastodon/Scene/Thread/ThreadViewController.swift index 2023d1b1d..02cf3c38d 100644 --- a/Mastodon/Scene/Thread/ThreadViewController.swift +++ b/Mastodon/Scene/Thread/ThreadViewController.swift @@ -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) } diff --git a/Mastodon/Scene/Thread/ThreadViewModel.swift b/Mastodon/Scene/Thread/ThreadViewModel.swift index febc34d17..0599a0654 100644 --- a/Mastodon/Scene/Thread/ThreadViewModel.swift +++ b/Mastodon/Scene/Thread/ThreadViewModel.swift @@ -45,7 +45,7 @@ class ThreadViewModel { let ancestorItems = CurrentValueSubject<[Item], Never>([]) let descendantNodes = CurrentValueSubject<[LeafNode], Never>([]) let descendantItems = CurrentValueSubject<[Item], Never>([]) - let navigationBarTitle: CurrentValueSubject + 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) From 9858a39f3d6fb21babd8ce2a9deb2e4cf6aab520 Mon Sep 17 00:00:00 2001 From: CMK Date: Tue, 29 Jun 2021 19:55:42 +0800 Subject: [PATCH 5/6] fix: reblog not disable for non-public post issue. resolve #173 --- .../Diffiable/Section/StatusSection.swift | 10 ++++++++-- Mastodon/Extension/CoreDataStack/Status.swift | 7 +++++++ .../Compose/View/ComposeToolbarView.swift | 9 --------- .../Scene/Share/View/Content/StatusView.swift | 19 +++++++++++++++---- 4 files changed, 30 insertions(+), 15 deletions(-) diff --git a/Mastodon/Diffiable/Section/StatusSection.swift b/Mastodon/Diffiable/Section/StatusSection.swift index b94ed3328..c7408339c 100644 --- a/Mastodon/Diffiable/Section/StatusSection.swift +++ b/Mastodon/Diffiable/Section/StatusSection.swift @@ -574,9 +574,8 @@ extension StatusSection { cell.statusView.contentMetaText.textView.accessibilityLanguage = (status.reblog ?? status).language // set visibility - if let visibility = (status.reblog ?? status).visibility { + if let visibility = (status.reblog ?? status).visibilityEnum { cell.statusView.updateVisibility(visibility: visibility) - cell.statusView.revealContentWarningButton.publisher(for: \.isHidden) .receive(on: DispatchQueue.main) .sink { [weak cell] isHidden in @@ -953,6 +952,13 @@ extension StatusSection { guard status.reblogsCount.intValue > 0 else { return nil } return L10n.Common.Controls.Timeline.Accessibility.countReblogs(status.reblogsCount.intValue) }() + + // disable reblog when non-public (except self) + cell.statusView.actionToolbarContainer.reblogButton.isEnabled = true + if let visibility = status.visibilityEnum, visibility != .public, status.author.id != requestUserID { + cell.statusView.actionToolbarContainer.reblogButton.isEnabled = false + } + // set like let isLike = status.favouritedBy.flatMap { $0.contains(where: { $0.id == requestUserID }) } ?? false let favoriteCountTitle: String = { diff --git a/Mastodon/Extension/CoreDataStack/Status.swift b/Mastodon/Extension/CoreDataStack/Status.swift index d8e1b9307..7b64e6a9d 100644 --- a/Mastodon/Extension/CoreDataStack/Status.swift +++ b/Mastodon/Extension/CoreDataStack/Status.swift @@ -89,3 +89,10 @@ extension Status { } extension Status: EmojiContainer { } + + +extension Status { + var visibilityEnum: Mastodon.Entity.Status.Visibility? { + return visibility.flatMap { Mastodon.Entity.Status.Visibility(rawValue: $0) } + } +} diff --git a/Mastodon/Scene/Compose/View/ComposeToolbarView.swift b/Mastodon/Scene/Compose/View/ComposeToolbarView.swift index 1dd19c552..3edb17e41 100644 --- a/Mastodon/Scene/Compose/View/ComposeToolbarView.swift +++ b/Mastodon/Scene/Compose/View/ComposeToolbarView.swift @@ -202,15 +202,6 @@ extension ComposeToolbarView { } } - func imageNameForTimeline() -> String { - switch self { - case .public: return "globe" - // case .unlisted: return "eye.slash" - case .private: return "person.3" - case .direct: return "at" - } - } - var visibility: Mastodon.Entity.Status.Visibility { switch self { case .public: return .public diff --git a/Mastodon/Scene/Share/View/Content/StatusView.swift b/Mastodon/Scene/Share/View/Content/StatusView.swift index 84166c627..e4c3b6f0f 100644 --- a/Mastodon/Scene/Share/View/Content/StatusView.swift +++ b/Mastodon/Scene/Share/View/Content/StatusView.swift @@ -14,6 +14,7 @@ import AlamofireImage import FLAnimatedImage import MetaTextView import Meta +import MastodonSDK // TODO: // import LinkPresentation @@ -498,10 +499,20 @@ extension StatusView { } // TODO: a11y } - - func updateVisibility(visibility: String) { - guard let visibility = ComposeToolbarView.VisibilitySelectionType(rawValue: visibility) else { return } - visibilityImageView.image = UIImage(systemName: visibility.imageNameForTimeline(), withConfiguration: UIImage.SymbolConfiguration(pointSize: 13, weight: .regular)) + + func updateVisibility(visibility: Mastodon.Entity.Status.Visibility) { + switch visibility { + case .public: + visibilityImageView.image = UIImage(systemName: "globe", withConfiguration: UIImage.SymbolConfiguration(pointSize: 13, weight: .regular)) + case .private: + visibilityImageView.image = UIImage(systemName: "person.3", withConfiguration: UIImage.SymbolConfiguration(pointSize: 13, weight: .regular)) + case .unlisted: + visibilityImageView.image = UIImage(systemName: "eye.slash", withConfiguration: UIImage.SymbolConfiguration(pointSize: 13, weight: .regular)) + case .direct: + visibilityImageView.image = UIImage(systemName: "at", withConfiguration: UIImage.SymbolConfiguration(pointSize: 13, weight: .regular)) + case ._other: + visibilityImageView.image = nil + } } } From 6aa91dbcfa9372e69b349f0c0aeea3167cad74d3 Mon Sep 17 00:00:00 2001 From: CMK Date: Tue, 29 Jun 2021 20:00:58 +0800 Subject: [PATCH 6/6] fix: author name missing emoji issue in compose scene --- Mastodon/Diffiable/Item/ComposeStatusItem.swift | 2 ++ Mastodon/Diffiable/Section/ComposeStatusSection.swift | 9 +++++---- Mastodon/Scene/Compose/ComposeViewModel.swift | 1 + 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Mastodon/Diffiable/Item/ComposeStatusItem.swift b/Mastodon/Diffiable/Item/ComposeStatusItem.swift index 96ea8b05f..7c916b166 100644 --- a/Mastodon/Diffiable/Item/ComposeStatusItem.swift +++ b/Mastodon/Diffiable/Item/ComposeStatusItem.swift @@ -25,6 +25,7 @@ extension ComposeStatusItem { let avatarURL = CurrentValueSubject(nil) let displayName = CurrentValueSubject(nil) + let emojiDict = CurrentValueSubject([:]) let username = CurrentValueSubject(nil) let composeContent = CurrentValueSubject(nil) @@ -34,6 +35,7 @@ extension ComposeStatusItem { static func == (lhs: ComposeStatusAttribute, rhs: ComposeStatusAttribute) -> Bool { return lhs.avatarURL.value == rhs.avatarURL.value && lhs.displayName.value == rhs.displayName.value && + lhs.emojiDict.value == rhs.emojiDict.value && lhs.username.value == rhs.username.value && lhs.composeContent.value == rhs.composeContent.value && lhs.isContentWarningComposing.value == rhs.isContentWarningComposing.value && diff --git a/Mastodon/Diffiable/Section/ComposeStatusSection.swift b/Mastodon/Diffiable/Section/ComposeStatusSection.swift index b82116ad4..3419cc113 100644 --- a/Mastodon/Diffiable/Section/ComposeStatusSection.swift +++ b/Mastodon/Diffiable/Section/ComposeStatusSection.swift @@ -43,13 +43,14 @@ extension ComposeStatusSection { } .store(in: &cell.disposeBag) // set display name and username - Publishers.CombineLatest( - attribute.displayName.eraseToAnyPublisher(), + Publishers.CombineLatest3( + attribute.displayName, + attribute.emojiDict, attribute.username.eraseToAnyPublisher() ) .receive(on: DispatchQueue.main) - .sink { displayName, username in - cell.statusView.nameLabel.text = displayName + .sink { displayName, emojiDict, username in + cell.statusView.nameLabel.configure(content: displayName ?? " ", emojiDict: emojiDict) cell.statusView.usernameLabel.text = username.flatMap { "@" + $0 } ?? " " } .store(in: &cell.disposeBag) diff --git a/Mastodon/Scene/Compose/ComposeViewModel.swift b/Mastodon/Scene/Compose/ComposeViewModel.swift index af8c8e2ac..68880e819 100644 --- a/Mastodon/Scene/Compose/ComposeViewModel.swift +++ b/Mastodon/Scene/Compose/ComposeViewModel.swift @@ -181,6 +181,7 @@ final class ComposeViewModel: NSObject { } return displayName }() + self.composeStatusAttribute.emojiDict.value = mastodonUser?.emojiDict ?? [:] self.composeStatusAttribute.username.value = username } .store(in: &disposeBag)