From b5e8df92de4c1154d67e18c557b9a3a1a1a2b1d3 Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 4 Aug 2021 14:09:45 +0800 Subject: [PATCH 1/9] chore: set setting footer label font style to footnote --- Mastodon.xcodeproj/project.pbxproj | 20 ++++++++++---------- Mastodon/Extension/MetaLabel.swift | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 56674070..0aca29c9 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -2561,11 +2561,19 @@ children = ( DB084B5125CBC56300F898ED /* CoreDataStack */, DB6C8C0525F0921200AAA452 /* MastodonSDK */, - DB44384E25E8C1FA008912A2 /* CALayer.swift */, 2DF123A625C3B0210020F248 /* ActiveLabel.swift */, + 5DF1056325F887CB00D6C0D4 /* AVPlayer.swift */, + 0F20223826146553000C64BF /* Array.swift */, + DB44384E25E8C1FA008912A2 /* CALayer.swift */, + 2D206B8525F5FB0900143C56 /* Double.swift */, + DB97131E2666078B00BD1E90 /* Date.swift */, + DBB3BA2926A81C020004F2D4 /* FLAnimatedImageView.swift */, DB0E91E926A9675100BD2ACC /* MetaLabel.swift */, DB68586325E619B700F0A850 /* NSKeyValueObservation.swift */, + DB47229625F9EFAD00DA7F53 /* NSManagedObjectContext.swift */, + DBAC6489267DC355007FE9FD /* NSDiffableDataSourceSnapshot.swift */, DB0140CE25C42AEE00F9F3CF /* OSLog.swift */, + 2D939AB425EDD8A90076FA61 /* String.swift */, DB68A06225E905E000CFDF14 /* UIApplication.swift */, DB45FAB525CA5485005A8AC7 /* UIAlertController.swift */, 2D42FF8E25C8228A004A627A /* UIButton.swift */, @@ -2573,24 +2581,16 @@ DB4481B825EE289600BEFB67 /* UITableView.swift */, DBD376B1269302A4007FEC24 /* UITableViewCell.swift */, 0FAA101B25E10E760017CCDE /* UIFont.swift */, - 2D939AB425EDD8A90076FA61 /* String.swift */, - 2D206B8525F5FB0900143C56 /* Double.swift */, 2D206B9125F60EA700143C56 /* UIControl.swift */, - 5DF1056325F887CB00D6C0D4 /* AVPlayer.swift */, - DB47229625F9EFAD00DA7F53 /* NSManagedObjectContext.swift */, 2D32EAB925CB9B0500C9ED86 /* UIView.swift */, 5DA732CB2629CEF500A92342 /* UIView+Remove.swift */, - DB8AF55C25C138B7002E6C99 /* UIViewController.swift */, 2D24E1222626ED9D00A59D4F /* UIView+Gesture.swift */, + DB8AF55C25C138B7002E6C99 /* UIViewController.swift */, 2D3F9E0325DFA133004262D9 /* UITapGestureRecognizer.swift */, 2D84350425FF858100EECE90 /* UIScrollView.swift */, DB9E0D6E25EE008500CFDD76 /* UIInterpolatingMotionEffect.swift */, - 0F20223826146553000C64BF /* Array.swift */, DBCC3B2F261440A50045B23D /* UITabBarController.swift */, DBCC3B35261440BA0045B23D /* UINavigationController.swift */, - DB97131E2666078B00BD1E90 /* Date.swift */, - DBAC6489267DC355007FE9FD /* NSDiffableDataSourceSnapshot.swift */, - DBB3BA2926A81C020004F2D4 /* FLAnimatedImageView.swift */, ); path = Extension; sourceTree = ""; diff --git a/Mastodon/Extension/MetaLabel.swift b/Mastodon/Extension/MetaLabel.swift index e1ea3273..baac9379 100644 --- a/Mastodon/Extension/MetaLabel.swift +++ b/Mastodon/Extension/MetaLabel.swift @@ -65,7 +65,7 @@ extension MetaLabel { textColor = .white case .settingTableFooter: - font = .preferredFont(forTextStyle: .body) + font = .preferredFont(forTextStyle: .footnote) textColor = Asset.Colors.Label.secondary.color numberOfLines = 0 textContainer.maximumNumberOfLines = 0 From 0ee2dea581f4093fd48f55fdaa898c5d3de332d1 Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 4 Aug 2021 14:59:42 +0800 Subject: [PATCH 2/9] fix: server rules prompt footer text is selectable issue --- .../MastodonServerRulesViewController.swift | 103 ++++++++++++------ 1 file changed, 70 insertions(+), 33 deletions(-) diff --git a/Mastodon/Scene/Onboarding/ServerRules/MastodonServerRulesViewController.swift b/Mastodon/Scene/Onboarding/ServerRules/MastodonServerRulesViewController.swift index 3faa3a83..c31e9130 100644 --- a/Mastodon/Scene/Onboarding/ServerRules/MastodonServerRulesViewController.swift +++ b/Mastodon/Scene/Onboarding/ServerRules/MastodonServerRulesViewController.swift @@ -10,6 +10,7 @@ import UIKit import Combine import MastodonSDK import SafariServices +import MetaTextKit final class MastodonServerRulesViewController: UIViewController, NeedsDependency { @@ -53,15 +54,21 @@ final class MastodonServerRulesViewController: UIViewController, NeedsDependency return view }() - private(set) lazy var bottomPromptTextView: UITextView = { - let textView = UITextView() - textView.font = UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 17, weight: .regular), maximumPointSize: 22) - textView.textColor = .label - textView.isSelectable = true - textView.isEditable = false - textView.isScrollEnabled = false - textView.backgroundColor = Asset.Theme.Mastodon.systemGroupedBackground.color - return textView + private(set) lazy var bottomPromptMetaText: MetaText = { + let metaText = MetaText() + metaText.textAttributes = [ + .font: UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 17, weight: .regular), maximumPointSize: 22), + .foregroundColor: UIColor.label, + ] + metaText.linkAttributes = [ + .font: UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 17, weight: .regular), maximumPointSize: 22), + .foregroundColor: Asset.Colors.brandBlue.color, + ] + metaText.textView.isEditable = false + metaText.textView.isSelectable = false + metaText.textView.isScrollEnabled = false + metaText.textView.backgroundColor = Asset.Theme.Mastodon.systemGroupedBackground.color // needs background color to prevent server rules text overlap + return metaText }() let confirmButton: PrimaryActionButton = { @@ -114,13 +121,13 @@ extension MastodonServerRulesViewController { confirmButton.heightAnchor.constraint(equalToConstant: MastodonServerRulesViewController.actionButtonHeight).priority(.defaultHigh), ]) - bottomPromptTextView.translatesAutoresizingMaskIntoConstraints = false - bottomContainerView.addSubview(bottomPromptTextView) + bottomPromptMetaText.textView.translatesAutoresizingMaskIntoConstraints = false + bottomContainerView.addSubview(bottomPromptMetaText.textView) NSLayoutConstraint.activate([ - bottomPromptTextView.frameLayoutGuide.topAnchor.constraint(equalTo: bottomContainerView.topAnchor, constant: 20), - bottomPromptTextView.frameLayoutGuide.leadingAnchor.constraint(equalTo: bottomContainerView.readableContentGuide.leadingAnchor), - bottomPromptTextView.frameLayoutGuide.trailingAnchor.constraint(equalTo: bottomContainerView.readableContentGuide.trailingAnchor), - confirmButton.topAnchor.constraint(equalTo: bottomPromptTextView.frameLayoutGuide.bottomAnchor, constant: 20), + bottomPromptMetaText.textView.frameLayoutGuide.topAnchor.constraint(equalTo: bottomContainerView.topAnchor, constant: 20), + bottomPromptMetaText.textView.frameLayoutGuide.leadingAnchor.constraint(equalTo: bottomContainerView.readableContentGuide.leadingAnchor), + bottomPromptMetaText.textView.frameLayoutGuide.trailingAnchor.constraint(equalTo: bottomContainerView.readableContentGuide.trailingAnchor), + confirmButton.topAnchor.constraint(equalTo: bottomPromptMetaText.textView.frameLayoutGuide.bottomAnchor, constant: 20), ]) scrollView.translatesAutoresizingMaskIntoConstraints = false @@ -175,34 +182,64 @@ extension MastodonServerRulesViewController { } func configTextView() { - let str = NSString(string: L10n.Scene.ServerRules.prompt(viewModel.domain)) - let termsOfServiceRange = str.range(of: L10n.Scene.ServerRules.termsOfService) - let privacyRange = str.range(of: L10n.Scene.ServerRules.privacyPolicy) - let attributeString = NSMutableAttributedString( - string: L10n.Scene.ServerRules.prompt(viewModel.domain), - attributes: [ - NSAttributedString.Key.font: UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 17, weight: .regular), maximumPointSize: 22), - NSAttributedString.Key.foregroundColor: UIColor.label - ] - ) - attributeString.addAttribute(.link, value: Mastodon.API.serverRulesURL(domain: viewModel.domain), range: termsOfServiceRange) - attributeString.addAttribute(.link, value: Mastodon.API.privacyURL(domain: viewModel.domain), range: privacyRange) - let linkAttributes = [NSAttributedString.Key.foregroundColor: Asset.Colors.brandBlue.color] - bottomPromptTextView.attributedText = attributeString - bottomPromptTextView.linkTextAttributes = linkAttributes - bottomPromptTextView.delegate = self + let metaContent = ServerRulesPromptMetaContent(domain: viewModel.domain) + bottomPromptMetaText.configure(content: metaContent) + bottomPromptMetaText.textView.linkDelegate = self + } + + struct ServerRulesPromptMetaContent: MetaContent { + let string: String + let entities: [Meta.Entity] + + init(domain: String) { + let _string = L10n.Scene.ServerRules.prompt(domain) + self.string = _string + + var _entities: [Meta.Entity] = [] + + let termsOfServiceText = L10n.Scene.ServerRules.termsOfService + if let termsOfServiceRange = _string.range(of: termsOfServiceText) { + let url = Mastodon.API.serverRulesURL(domain: domain) + let entity = Meta.Entity(range: NSRange(termsOfServiceRange, in: _string), meta: .url(termsOfServiceText, trimmed: termsOfServiceText, url: url.absoluteString, userInfo: nil)) + _entities.append(entity) + } + + let privacyPolicyText = L10n.Scene.ServerRules.privacyPolicy + if let privacyPolicyRange = _string.range(of: privacyPolicyText) { + let url = Mastodon.API.privacyURL(domain: domain) + let entity = Meta.Entity(range: NSRange(privacyPolicyRange, in: _string), meta: .url(privacyPolicyText, trimmed: privacyPolicyText, url: url.absoluteString, userInfo: nil)) + _entities.append(entity) + } + + self.entities = _entities + } + + func metaAttachment(for entity: Meta.Entity) -> MetaAttachment? { + return nil + } } } extension MastodonServerRulesViewController: UITextViewDelegate { func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool { - let safariVC = SFSafariViewController(url: URL) - self.present(safariVC, animated: true, completion: nil) return false } } +// MARK: - MetaTextViewDelegate +extension MastodonServerRulesViewController: MetaTextViewDelegate { + func metaTextView(_ metaTextView: MetaTextView, didSelectMeta meta: Meta) { + switch meta { + case .url(_, _, let url, _): + guard let url = URL(string: url) else { return } + coordinator.present(scene: .safari(url: url), from: nil, transition: .safariPresent(animated: true, completion: nil)) + default: + break + } + } +} + extension MastodonServerRulesViewController { @objc private func confirmButtonPressed(_ sender: UIButton) { os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) From 7165ca5b3861ae38b2cc2285842b3648d0d9bc6e Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 4 Aug 2021 15:17:04 +0800 Subject: [PATCH 3/9] fix: ignore approval required servers from list when sign up --- ...stodonPickServerViewModel+LoadIndexedServerState.swift | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel+LoadIndexedServerState.swift b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel+LoadIndexedServerState.swift index 0c4910d1..1cb9b508 100644 --- a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel+LoadIndexedServerState.swift +++ b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel+LoadIndexedServerState.swift @@ -55,7 +55,13 @@ extension MastodonPickServerViewModel.LoadIndexedServerState { } receiveValue: { [weak self] response in guard let _ = self else { return } stateMachine.enter(Idle.self) - viewModel.indexedServers.value = response.value + + // ignore approval required servers + var servers = response.value + if viewModel.mode == .signUp { + servers = servers.filter { !$0.approvalRequired } + } + viewModel.indexedServers.value = servers } .store(in: &viewModel.disposeBag) } From 921e85035044b559d8f7ee75984bff569ff17e4f Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 4 Aug 2021 15:18:57 +0800 Subject: [PATCH 4/9] chore: set server rules text trimmed before concat --- .../Onboarding/ServerRules/MastodonServerRulesViewModel.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mastodon/Scene/Onboarding/ServerRules/MastodonServerRulesViewModel.swift b/Mastodon/Scene/Onboarding/ServerRules/MastodonServerRulesViewModel.swift index c6a37e85..5936a2c0 100644 --- a/Mastodon/Scene/Onboarding/ServerRules/MastodonServerRulesViewModel.swift +++ b/Mastodon/Scene/Onboarding/ServerRules/MastodonServerRulesViewModel.swift @@ -38,7 +38,7 @@ final class MastodonServerRulesViewModel { let separatorString = Array(repeating: " ", count: 4).joined() for (i, rule) in rules.enumerated() { guard i < 50 else { - return NSAttributedString(string: "\(i)" + separatorString + rule.text + "\n\n") + return NSAttributedString(string: "\(i)" + separatorString + rule.text.trimmingCharacters(in: .whitespacesAndNewlines) + "\n\n") } let imageName = String(i + 1) + ".circle.fill" let image = UIImage(systemName: imageName, withConfiguration: configuration)! @@ -47,7 +47,7 @@ final class MastodonServerRulesViewModel { let imageAttribute = NSMutableAttributedString(attachment: attachment) imageAttribute.addAttributes([NSAttributedString.Key.baselineOffset : -1.5], range: NSRange(location: 0, length: imageAttribute.length)) - let ruleString = NSAttributedString(string: separatorString + rule.text + "\n\n") + let ruleString = NSAttributedString(string: separatorString + rule.text.trimmingCharacters(in: .whitespacesAndNewlines) + "\n\n") attributedString.append(imageAttribute) attributedString.append(ruleString) } From 3114dd943161775b2e0d0d0c798b293fb5d317a4 Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 4 Aug 2021 15:29:47 +0800 Subject: [PATCH 5/9] chore: set default poll duration to 1 Day --- Mastodon/Diffiable/Item/ComposeStatusPollItem.swift | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Mastodon/Diffiable/Item/ComposeStatusPollItem.swift b/Mastodon/Diffiable/Item/ComposeStatusPollItem.swift index a6d9a36e..0b4abf23 100644 --- a/Mastodon/Diffiable/Item/ComposeStatusPollItem.swift +++ b/Mastodon/Diffiable/Item/ComposeStatusPollItem.swift @@ -59,8 +59,7 @@ extension ComposeStatusPollItem { final class PollExpiresOptionAttribute: Equatable, Hashable { private let id = UUID() - let expiresOption = CurrentValueSubject(.thirtyMinutes) - + let expiresOption = CurrentValueSubject(.oneDay) static func == (lhs: PollExpiresOptionAttribute, rhs: PollExpiresOptionAttribute) -> Bool { return lhs.id == rhs.id && From 0186be609f641ee6d2eb977d06a975a5657b6bc1 Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 4 Aug 2021 15:32:11 +0800 Subject: [PATCH 6/9] chore: remove paragraph spacing for post editor. resolve #261 --- .../CollectionViewCell/ComposeStatusContentTableViewCell.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mastodon/Scene/Compose/CollectionViewCell/ComposeStatusContentTableViewCell.swift b/Mastodon/Scene/Compose/CollectionViewCell/ComposeStatusContentTableViewCell.swift index ffeae767..88584011 100644 --- a/Mastodon/Scene/Compose/CollectionViewCell/ComposeStatusContentTableViewCell.swift +++ b/Mastodon/Scene/Compose/CollectionViewCell/ComposeStatusContentTableViewCell.swift @@ -43,7 +43,7 @@ final class ComposeStatusContentTableViewCell: UITableViewCell { metaText.paragraphStyle = { let style = NSMutableParagraphStyle() style.lineSpacing = 5 - style.paragraphSpacing = 8 + style.paragraphSpacing = 0 return style }() metaText.textAttributes = [ From 9a8653f39cfe2318ccfd113b2a21439c843a841f Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 4 Aug 2021 15:47:29 +0800 Subject: [PATCH 7/9] fix: auto completion title label not display custom emoji issue --- .../Section/Compose/AutoCompleteSection.swift | 22 +++++++++++++------ .../MastodonSDK/Mastodon+Entity+Account.swift | 8 +++++++ Mastodon/Extension/MetaLabel.swift | 4 ++++ .../Cell/AutoCompleteTableViewCell.swift | 8 +++---- 4 files changed, 30 insertions(+), 12 deletions(-) diff --git a/Mastodon/Diffiable/Section/Compose/AutoCompleteSection.swift b/Mastodon/Diffiable/Section/Compose/AutoCompleteSection.swift index c5e8891a..ed205b13 100644 --- a/Mastodon/Diffiable/Section/Compose/AutoCompleteSection.swift +++ b/Mastodon/Diffiable/Section/Compose/AutoCompleteSection.swift @@ -7,6 +7,7 @@ import UIKit import MastodonSDK +import MastodonMeta enum AutoCompleteSection: Equatable, Hashable { case main @@ -48,7 +49,8 @@ extension AutoCompleteSection { extension AutoCompleteSection { private static func configureHashtag(cell: AutoCompleteTableViewCell, hashtag: Mastodon.Entity.Tag) { - cell.titleLabel.text = "#" + hashtag.name + let metaContent = PlaintextMetaContent(string: "#" + hashtag.name) + cell.titleLabel.configure(content: metaContent) cell.subtitleLabel.text = { let count = (hashtag.history ?? []) .sorted(by: { $0.day > $1.day }) @@ -61,23 +63,29 @@ extension AutoCompleteSection { } private static func configureHashtag(cell: AutoCompleteTableViewCell, hashtagName: String) { - cell.titleLabel.text = "#" + hashtagName + let metaContent = PlaintextMetaContent(string: "#" + hashtagName) + cell.titleLabel.configure(content: metaContent) cell.subtitleLabel.text = " " cell.avatarImageView.isHidden = true } private static func configureAccount(cell: AutoCompleteTableViewCell, account: Mastodon.Entity.Account) { - cell.titleLabel.text = { - guard !account.displayName.isEmpty else { return account.username } - return account.displayName - }() + let mastodonContent = MastodonContent(content: account.displayNameWithFallback, emojis: account.emojiMeta) + do { + let metaContent = try MastodonMetaContent.convert(document: mastodonContent) + cell.titleLabel.configure(content: metaContent) + } catch { + let metaContent = PlaintextMetaContent(string: account.displayNameWithFallback) + cell.titleLabel.configure(content: metaContent) + } cell.subtitleLabel.text = "@" + account.acct cell.avatarImageView.isHidden = false cell.configure(with: AvatarConfigurableViewConfiguration(avatarImageURL: URL(string: account.avatar))) } private static func configureEmoji(cell: AutoCompleteTableViewCell, emoji: Mastodon.Entity.Emoji, isFirst: Bool) { - cell.titleLabel.text = ":" + emoji.shortcode + ":" + let metaContent = PlaintextMetaContent(string: ":" + emoji.shortcode + ":") + cell.titleLabel.configure(content: metaContent) // FIXME: handle spacer enter to complete emoji // cell.subtitleLabel.text = isFirst ? L10n.Scene.Compose.AutoComplete.spaceToAdd : " " cell.subtitleLabel.text = " " diff --git a/Mastodon/Extension/MastodonSDK/Mastodon+Entity+Account.swift b/Mastodon/Extension/MastodonSDK/Mastodon+Entity+Account.swift index 6aad350c..09bbb3d8 100644 --- a/Mastodon/Extension/MastodonSDK/Mastodon+Entity+Account.swift +++ b/Mastodon/Extension/MastodonSDK/Mastodon+Entity+Account.swift @@ -19,6 +19,14 @@ extension Mastodon.Entity.Account: Hashable { } } +extension Mastodon.Entity.Account { + + var displayNameWithFallback: String { + return !displayName.isEmpty ? displayName : username + } + +} + extension Mastodon.Entity.Account { public func avatarImageURL() -> URL? { let string = UserDefaults.shared.preferredStaticAvatar ? avatarStatic ?? avatar : avatar diff --git a/Mastodon/Extension/MetaLabel.swift b/Mastodon/Extension/MetaLabel.swift index baac9379..8163a10c 100644 --- a/Mastodon/Extension/MetaLabel.swift +++ b/Mastodon/Extension/MetaLabel.swift @@ -19,6 +19,7 @@ extension MetaLabel { case recommendAccountName case titleView case settingTableFooter + case autoCompletion } convenience init(style: Style) { @@ -70,6 +71,9 @@ extension MetaLabel { numberOfLines = 0 textContainer.maximumNumberOfLines = 0 paragraphStyle.alignment = .center + case .autoCompletion: + font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 17, weight: .semibold), maximumPointSize: 22) + textColor = Asset.Colors.brandBlue.color } self.font = font diff --git a/Mastodon/Scene/Compose/AutoComplete/Cell/AutoCompleteTableViewCell.swift b/Mastodon/Scene/Compose/AutoComplete/Cell/AutoCompleteTableViewCell.swift index 8fa5d864..7492753f 100644 --- a/Mastodon/Scene/Compose/AutoComplete/Cell/AutoCompleteTableViewCell.swift +++ b/Mastodon/Scene/Compose/AutoComplete/Cell/AutoCompleteTableViewCell.swift @@ -7,6 +7,7 @@ import UIKit import FLAnimatedImage +import MetaTextKit final class AutoCompleteTableViewCell: UITableViewCell { @@ -30,11 +31,8 @@ final class AutoCompleteTableViewCell: UITableViewCell { let avatarImageView = FLAnimatedImageView() - let titleLabel: UILabel = { - let label = UILabel() - label.font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 17, weight: .semibold), maximumPointSize: 22) - label.textColor = Asset.Colors.brandBlue.color - label.text = "Title" + let titleLabel: MetaLabel = { + let label = MetaLabel(style: .autoCompletion) return label }() From 7806816213b5250fa7c4910860987b3ea01d055d Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 4 Aug 2021 16:24:19 +0800 Subject: [PATCH 8/9] fix: some label trimmed under zoomed display mode issue --- .../Section/Status/NotificationSection.swift | 6 ++-- Mastodon/Extension/UIView.swift | 6 ++++ .../NotificationStatusTableViewCell.swift | 28 +++++++++++++++++-- .../ProfileStatusDashboardMeterView.swift | 4 +++ .../View/ProfileStatusDashboardView.swift | 2 +- .../SearchRecommendCollectionHeader.swift | 2 ++ .../Cell/SettingsToggleTableViewCell.swift | 1 + 7 files changed, 43 insertions(+), 6 deletions(-) diff --git a/Mastodon/Diffiable/Section/Status/NotificationSection.swift b/Mastodon/Diffiable/Section/Status/NotificationSection.swift index 3113a446..b0afd700 100644 --- a/Mastodon/Diffiable/Section/Status/NotificationSection.swift +++ b/Mastodon/Diffiable/Section/Status/NotificationSection.swift @@ -78,12 +78,14 @@ extension NotificationSection { } let createAt = notification.createAt let actionText = notification.notificationType.actionText - cell.actionLabel.text = actionText + " · " + createAt.timeAgoSinceNow + cell.actionLabel.text = actionText + cell.timestampLabel.text = createAt.timeAgoSinceNow AppContext.shared.timestampUpdatePublisher .receive(on: DispatchQueue.main) .sink { [weak cell] _ in guard let cell = cell else { return } - cell.actionLabel.text = actionText + " · " + createAt.timeAgoSinceNow + cell.actionLabel.text = actionText + cell.timestampLabel.text = createAt.timeAgoSinceNow } .store(in: &cell.disposeBag) diff --git a/Mastodon/Extension/UIView.swift b/Mastodon/Extension/UIView.swift index 85d8112c..0f43dced 100644 --- a/Mastodon/Extension/UIView.swift +++ b/Mastodon/Extension/UIView.swift @@ -67,3 +67,9 @@ extension UIView { return self } } + +extension UIView { + static var isZoomedMode: Bool { + return UIScreen.main.scale != UIScreen.main.nativeScale + } +} diff --git a/Mastodon/Scene/Notification/TableViewCell/NotificationStatusTableViewCell.swift b/Mastodon/Scene/Notification/TableViewCell/NotificationStatusTableViewCell.swift index 65e4dbcd..804fc081 100644 --- a/Mastodon/Scene/Notification/TableViewCell/NotificationStatusTableViewCell.swift +++ b/Mastodon/Scene/Notification/TableViewCell/NotificationStatusTableViewCell.swift @@ -56,6 +56,19 @@ final class NotificationStatusTableViewCell: UITableViewCell, StatusCell { label.lineBreakMode = .byTruncatingTail return label }() + let dotLabel: UILabel = { + let label = UILabel() + label.textColor = Asset.Colors.Label.secondary.color + label.font = UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 15, weight: .regular), maximumPointSize: 20) + label.text = "·" + return label + }() + let timestampLabel: UILabel = { + let label = UILabel() + label.textColor = Asset.Colors.Label.secondary.color + label.font = UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 15, weight: .regular), maximumPointSize: 20) + return label + }() let nameLabel = MetaLabel(style: .notificationName) @@ -170,12 +183,21 @@ extension NotificationStatusTableViewCell { actionStackView.addArrangedSubview(nameLabel) actionStackView.addArrangedSubview(actionLabel) - nameLabel.setContentHuggingPriority(.required - 1, for: .horizontal) + actionStackView.addArrangedSubview(dotLabel) + actionStackView.addArrangedSubview(timestampLabel) + let timestampPaddingView = UIView() + actionStackView.addArrangedSubview(timestampPaddingView) + nameLabel.setContentHuggingPriority(.required - 3, for: .horizontal) nameLabel.setContentHuggingPriority(.required - 1, for: .vertical) - nameLabel.setContentCompressionResistancePriority(.required - 1, for: .horizontal) + nameLabel.setContentCompressionResistancePriority(.required - 3, for: .horizontal) nameLabel.setContentCompressionResistancePriority(.required - 1, for: .vertical) actionLabel.setContentHuggingPriority(.defaultLow, for: .horizontal) - + dotLabel.setContentHuggingPriority(.required - 2, for: .horizontal) + dotLabel.setContentCompressionResistancePriority(.required - 2, for: .horizontal) + timestampLabel.setContentHuggingPriority(.required - 1, for: .horizontal) + timestampLabel.setContentCompressionResistancePriority(.required - 1, for: .horizontal) + timestampPaddingView.setContentHuggingPriority(.defaultLow, for: .horizontal) + // follow request contentStackView.addArrangedSubview(buttonStackView) buttonStackView.addArrangedSubview(acceptButton) diff --git a/Mastodon/Scene/Profile/Header/View/ProfileStatusDashboardMeterView.swift b/Mastodon/Scene/Profile/Header/View/ProfileStatusDashboardMeterView.swift index 4355fdc3..0f32f330 100644 --- a/Mastodon/Scene/Profile/Header/View/ProfileStatusDashboardMeterView.swift +++ b/Mastodon/Scene/Profile/Header/View/ProfileStatusDashboardMeterView.swift @@ -29,6 +29,10 @@ final class ProfileStatusDashboardMeterView: UIView { label.textColor = Asset.Colors.Label.primary.color label.text = L10n.Scene.Profile.Dashboard.posts label.textAlignment = .center + if UIView.isZoomedMode { + label.adjustsFontSizeToFitWidth = true + label.minimumScaleFactor = 0.8 + } return label }() diff --git a/Mastodon/Scene/Profile/Header/View/ProfileStatusDashboardView.swift b/Mastodon/Scene/Profile/Header/View/ProfileStatusDashboardView.swift index 38c093d1..0360421a 100644 --- a/Mastodon/Scene/Profile/Header/View/ProfileStatusDashboardView.swift +++ b/Mastodon/Scene/Profile/Header/View/ProfileStatusDashboardView.swift @@ -47,7 +47,7 @@ extension ProfileStatusDashboardView { containerStackView.heightAnchor.constraint(equalToConstant: 44).priority(.defaultHigh), ]) - let spacing: CGFloat = 16 + let spacing: CGFloat = UIView.isZoomedMode ? 4 : 16 containerStackView.spacing = spacing containerStackView.axis = .horizontal containerStackView.distribution = .fillEqually diff --git a/Mastodon/Scene/Search/Search/View/SearchRecommendCollectionHeader.swift b/Mastodon/Scene/Search/Search/View/SearchRecommendCollectionHeader.swift index 3db8c280..6c67580f 100644 --- a/Mastodon/Scene/Search/Search/View/SearchRecommendCollectionHeader.swift +++ b/Mastodon/Scene/Search/Search/View/SearchRecommendCollectionHeader.swift @@ -29,6 +29,8 @@ class SearchRecommendCollectionHeader: UIView { let button = HighlightDimmableButton(type: .custom) button.setTitleColor(Asset.Colors.brandBlue.color, for: .normal) button.setTitle(L10n.Scene.Search.Recommend.buttonText, for: .normal) + button.titleLabel?.adjustsFontSizeToFitWidth = true + button.titleLabel?.minimumScaleFactor = 0.8 return button }() diff --git a/Mastodon/Scene/Settings/View/Cell/SettingsToggleTableViewCell.swift b/Mastodon/Scene/Settings/View/Cell/SettingsToggleTableViewCell.swift index 2bc70e65..18c9e515 100644 --- a/Mastodon/Scene/Settings/View/Cell/SettingsToggleTableViewCell.swift +++ b/Mastodon/Scene/Settings/View/Cell/SettingsToggleTableViewCell.swift @@ -44,6 +44,7 @@ class SettingsToggleTableViewCell: UITableViewCell { private func setupUI() { selectionStyle = .none accessoryView = switchButton + textLabel?.numberOfLines = 0 switchButton.addTarget(self, action: #selector(switchValueDidChange(sender:)), for: .valueChanged) } From f43b36dddad068fa8047af087911759f0b98c243 Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 4 Aug 2021 17:06:46 +0800 Subject: [PATCH 9/9] fix: animate emoji label break VoiceOver issue --- .../Section/Status/StatusSection.swift | 37 +++++++++++-------- .../Scene/Settings/View/AppearanceView.swift | 14 +++++++ 2 files changed, 35 insertions(+), 16 deletions(-) diff --git a/Mastodon/Diffiable/Section/Status/StatusSection.swift b/Mastodon/Diffiable/Section/Status/StatusSection.swift index c6cde80f..0958ec73 100644 --- a/Mastodon/Diffiable/Section/Status/StatusSection.swift +++ b/Mastodon/Diffiable/Section/Status/StatusSection.swift @@ -106,21 +106,7 @@ extension StatusSection { ) cell.delegate = statusTableViewCellDelegate cell.isAccessibilityElement = true - // FIXME: - cell.accessibilityLabel = { - var accessibilityViews: [UIView?] = [] - if !cell.statusView.headerContainerView.isHidden { - accessibilityViews.append(cell.statusView.headerInfoLabel) - } - accessibilityViews.append(contentsOf: [ - cell.statusView.nameMetaLabel, - cell.statusView.dateLabel, - cell.statusView.contentMetaText.textView, - ]) - return accessibilityViews - .compactMap { $0?.accessibilityLabel } - .joined(separator: " ") - }() + StatusSection.configureStatusAccessibilityLabel(cell: cell) return cell case .status(let objectID, let attribute), .root(let objectID, let attribute), @@ -182,7 +168,7 @@ extension StatusSection { cell.accessibilityElements = accessibilityElements default: cell.isAccessibilityElement = true - cell.accessibilityElements = nil + StatusSection.configureStatusAccessibilityLabel(cell: cell) } return cell case .leafBottomLoader: @@ -1116,6 +1102,25 @@ extension StatusSection { .store(in: &cell.disposeBag) self.setupStatusMoreButtonMenu(cell: cell, dependency: dependency, status: status) } + + static func configureStatusAccessibilityLabel(cell: StatusTableViewCell) { + // FIXME: + cell.accessibilityLabel = { + var accessibilityViews: [UIView?] = [] + if !cell.statusView.headerContainerView.isHidden { + accessibilityViews.append(cell.statusView.headerInfoLabel) + } + accessibilityViews.append(contentsOf: [ + cell.statusView.nameMetaLabel, + cell.statusView.dateLabel, + cell.statusView.contentMetaText.textView, + ]) + return accessibilityViews + .compactMap { $0?.accessibilityLabel } + .joined(separator: " ") + }() + cell.statusView.actionToolbarContainer.isUserInteractionEnabled = !UIAccessibility.isVoiceOverRunning + } } diff --git a/Mastodon/Scene/Settings/View/AppearanceView.swift b/Mastodon/Scene/Settings/View/AppearanceView.swift index e761d46e..fd08fd43 100644 --- a/Mastodon/Scene/Settings/View/AppearanceView.swift +++ b/Mastodon/Scene/Settings/View/AppearanceView.swift @@ -61,6 +61,20 @@ class AppearanceView: UIView { imageView.image = image titleLabel.text = title } + + override var isAccessibilityElement: Bool { + get { return true } + set { } + + } + override var accessibilityLabel: String? { + get { + return [titleLabel.text, checkBox.accessibilityLabel] + .compactMap { $0 } + .joined(separator: ", ") + } + set { } + } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented")