From 5567bdd44721a81253c987a9285bfcdfa41597d4 Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 1 Jul 2021 19:18:41 +0800 Subject: [PATCH 1/3] fix: add tolerance for media preview dismiss gesture trigger --- .../xcschemes/xcschememanagement.plist | 2 +- .../MediaPreviewViewController.swift | 40 +++++++++---------- ...wViewControllerAnimatedTransitioning.swift | 18 ++++----- .../MediaPreviewTransitionController.swift | 2 +- .../MediaPreviewingViewController.swift | 2 +- 5 files changed, 32 insertions(+), 32 deletions(-) diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index fdbacc128..f1135b12e 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 - 27 + 20 Mastodon - ASDK.xcscheme_^#shared#^_ diff --git a/Mastodon/Scene/MediaPreview/MediaPreviewViewController.swift b/Mastodon/Scene/MediaPreview/MediaPreviewViewController.swift index c9cbf744a..a0afe1ccd 100644 --- a/Mastodon/Scene/MediaPreview/MediaPreviewViewController.swift +++ b/Mastodon/Scene/MediaPreview/MediaPreviewViewController.swift @@ -21,7 +21,7 @@ final class MediaPreviewViewController: UIViewController, NeedsDependency { var viewModel: MediaPreviewViewModel! let visualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .systemMaterial)) - let pagingViewConttroller = MediaPreviewPagingViewController() + let pagingViewController = MediaPreviewPagingViewController() let closeButtonBackground: UIVisualEffectView = { let backgroundView = UIVisualEffectView(effect: UIBlurEffect(style: .systemUltraThinMaterial)) @@ -57,16 +57,16 @@ extension MediaPreviewViewController { visualEffectView.frame = view.bounds view.addSubview(visualEffectView) - pagingViewConttroller.view.translatesAutoresizingMaskIntoConstraints = false - addChild(pagingViewConttroller) - visualEffectView.contentView.addSubview(pagingViewConttroller.view) + pagingViewController.view.translatesAutoresizingMaskIntoConstraints = false + addChild(pagingViewController) + visualEffectView.contentView.addSubview(pagingViewController.view) NSLayoutConstraint.activate([ - visualEffectView.topAnchor.constraint(equalTo: pagingViewConttroller.view.topAnchor), - visualEffectView.bottomAnchor.constraint(equalTo: pagingViewConttroller.view.bottomAnchor), - visualEffectView.leadingAnchor.constraint(equalTo: pagingViewConttroller.view.leadingAnchor), - visualEffectView.trailingAnchor.constraint(equalTo: pagingViewConttroller.view.trailingAnchor), + visualEffectView.topAnchor.constraint(equalTo: pagingViewController.view.topAnchor), + visualEffectView.bottomAnchor.constraint(equalTo: pagingViewController.view.bottomAnchor), + visualEffectView.leadingAnchor.constraint(equalTo: pagingViewController.view.leadingAnchor), + visualEffectView.trailingAnchor.constraint(equalTo: pagingViewController.view.trailingAnchor), ]) - pagingViewConttroller.didMove(toParent: self) + pagingViewController.didMove(toParent: self) closeButtonBackground.translatesAutoresizingMaskIntoConstraints = false view.addSubview(closeButtonBackground) @@ -90,9 +90,9 @@ extension MediaPreviewViewController { viewModel.mediaPreviewImageViewControllerDelegate = self - pagingViewConttroller.interPageSpacing = 10 - pagingViewConttroller.delegate = self - pagingViewConttroller.dataSource = viewModel + pagingViewController.interPageSpacing = 10 + pagingViewController.delegate = self + pagingViewController.dataSource = viewModel closeButton.addTarget(self, action: #selector(MediaPreviewViewController.closeButtonPressed(_:)), for: .touchUpInside) @@ -128,8 +128,8 @@ extension MediaPreviewViewController { // MARK: - MediaPreviewingViewController extension MediaPreviewViewController: MediaPreviewingViewController { - func isInteractiveDismissable() -> Bool { - if let mediaPreviewImageViewController = pagingViewConttroller.currentViewController as? MediaPreviewImageViewController { + func isInteractiveDismissible() -> Bool { + if let mediaPreviewImageViewController = pagingViewController.currentViewController as? MediaPreviewImageViewController { let previewImageView = mediaPreviewImageViewController.previewImageView // TODO: allow zooming pan dismiss guard previewImageView.zoomScale == previewImageView.minimumZoomScale else { @@ -138,12 +138,12 @@ extension MediaPreviewViewController: MediaPreviewingViewController { let safeAreaInsets = previewImageView.safeAreaInsets let statusBarFrameHeight = view.window?.windowScene?.statusBarManager?.statusBarFrame.height ?? 0 - let dismissable = previewImageView.contentOffset.y <= -(safeAreaInsets.top - statusBarFrameHeight) - os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: dismissable %s", ((#file as NSString).lastPathComponent), #line, #function, dismissable ? "true" : "false") - return dismissable + let dismissible = previewImageView.contentOffset.y <= -(safeAreaInsets.top - statusBarFrameHeight) + 3 // add 3pt tolerance + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: dismissible %s", ((#file as NSString).lastPathComponent), #line, #function, dismissible ? "true" : "false") + return dismissible } - os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: dismissable false", ((#file as NSString).lastPathComponent), #line, #function) + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: dismissible false", ((#file as NSString).lastPathComponent), #line, #function) return false } @@ -303,11 +303,11 @@ extension MediaPreviewViewController { } @objc private func showNextKeyCommandHandler(_ sender: UIKeyCommand) { - pagingViewConttroller.scrollToPage(.next, animated: true, completion: nil) + pagingViewController.scrollToPage(.next, animated: true, completion: nil) } @objc private func showPreviousKeyCommandHandler(_ sender: UIKeyCommand) { - pagingViewConttroller.scrollToPage(.previous, animated: true, completion: nil) + pagingViewController.scrollToPage(.previous, animated: true, completion: nil) } } diff --git a/Mastodon/Scene/Transition/MediaPreview/MediaHostToMediaPreviewViewControllerAnimatedTransitioning.swift b/Mastodon/Scene/Transition/MediaPreview/MediaHostToMediaPreviewViewControllerAnimatedTransitioning.swift index 50a518dc7..2daeba041 100644 --- a/Mastodon/Scene/Transition/MediaPreview/MediaHostToMediaPreviewViewControllerAnimatedTransitioning.swift +++ b/Mastodon/Scene/Transition/MediaPreview/MediaHostToMediaPreviewViewControllerAnimatedTransitioning.swift @@ -56,7 +56,7 @@ extension MediaHostToMediaPreviewViewControllerAnimatedTransitioning { toView.alpha = 0 transitionContext.containerView.addSubview(toView) // set to image hidden - toVC.pagingViewConttroller.view.alpha = 0 + toVC.pagingViewController.view.alpha = 0 // set from image hidden. update hidden when paging. seealso: `MediaPreviewViewController` transitionItem.source.updateAppearance(position: .start, index: toVC.viewModel.currentPage.value) @@ -98,7 +98,7 @@ extension MediaHostToMediaPreviewViewControllerAnimatedTransitioning { } animator.addCompletion { position in - toVC.pagingViewConttroller.view.alpha = 1 + toVC.pagingViewController.view.alpha = 1 transitionImageView.removeFromSuperview() UIView.animate(withDuration: 0.33, delay: 0, options: [.curveEaseInOut]) { toVC.closeButtonBackground.alpha = 1 @@ -112,8 +112,8 @@ extension MediaHostToMediaPreviewViewControllerAnimatedTransitioning { private func popTransition(using transitionContext: UIViewControllerContextTransitioning, curve: UIView.AnimationCurve = .easeInOut) -> UIViewPropertyAnimator { guard let fromVC = transitionContext.viewController(forKey: .from) as? MediaPreviewViewController, let fromView = transitionContext.view(forKey: .from), - let mediaPreviewImageViewController = fromVC.pagingViewConttroller.currentViewController as? MediaPreviewImageViewController, - let index = fromVC.pagingViewConttroller.currentIndex else { + let mediaPreviewImageViewController = fromVC.pagingViewController.currentViewController as? MediaPreviewImageViewController, + let index = fromVC.pagingViewController.currentIndex else { fatalError() } @@ -154,7 +154,7 @@ extension MediaHostToMediaPreviewViewControllerAnimatedTransitioning { transitionItem.targetFrame = targetFrame // disable interaction - fromVC.pagingViewConttroller.isUserInteractionEnabled = false + fromVC.pagingViewController.isUserInteractionEnabled = false let animator = popInteractiveTransitionAnimator @@ -246,8 +246,8 @@ extension MediaHostToMediaPreviewViewControllerAnimatedTransitioning { private func popInteractiveTransition(using transitionContext: UIViewControllerContextTransitioning) { guard let fromVC = transitionContext.viewController(forKey: .from) as? MediaPreviewViewController, let _ = transitionContext.view(forKey: .from), - let mediaPreviewImageViewController = fromVC.pagingViewConttroller.currentViewController as? MediaPreviewImageViewController, - let index = fromVC.pagingViewConttroller.currentIndex else { + let mediaPreviewImageViewController = fromVC.pagingViewController.currentViewController as? MediaPreviewImageViewController, + let index = fromVC.pagingViewController.currentIndex else { fatalError() } @@ -289,7 +289,7 @@ extension MediaHostToMediaPreviewViewControllerAnimatedTransitioning { transitionItem.targetFrame = targetFrame ?? snapshot.frame // disable interaction - fromVC.pagingViewConttroller.isUserInteractionEnabled = false + fromVC.pagingViewController.isUserInteractionEnabled = false let animator = popInteractiveTransitionAnimator @@ -315,7 +315,7 @@ extension MediaHostToMediaPreviewViewControllerAnimatedTransitioning { } animator.addCompletion { position in - fromVC.pagingViewConttroller.isUserInteractionEnabled = true + fromVC.pagingViewController.isUserInteractionEnabled = true fromVC.closeButtonBackground.alpha = position == .end ? 0 : 1 self.transitionItem.imageView?.isHidden = position == .end self.transitionItem.snapshotRaw?.alpha = position == .start ? 1.0 : 0.0 diff --git a/Mastodon/Scene/Transition/MediaPreview/MediaPreviewTransitionController.swift b/Mastodon/Scene/Transition/MediaPreview/MediaPreviewTransitionController.swift index 225a83209..bd5781b0b 100644 --- a/Mastodon/Scene/Transition/MediaPreview/MediaPreviewTransitionController.swift +++ b/Mastodon/Scene/Transition/MediaPreview/MediaPreviewTransitionController.swift @@ -56,7 +56,7 @@ extension MediaPreviewTransitionController: UIGestureRecognizerDelegate { func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { if gestureRecognizer === panGestureRecognizer { guard let mediaPreviewViewController = self.mediaPreviewViewController else { return false } - return mediaPreviewViewController.isInteractiveDismissable() + return mediaPreviewViewController.isInteractiveDismissible() } return false diff --git a/Mastodon/Scene/Transition/MediaPreview/MediaPreviewingViewController.swift b/Mastodon/Scene/Transition/MediaPreview/MediaPreviewingViewController.swift index 9c6e56d05..d74c99798 100644 --- a/Mastodon/Scene/Transition/MediaPreview/MediaPreviewingViewController.swift +++ b/Mastodon/Scene/Transition/MediaPreview/MediaPreviewingViewController.swift @@ -8,5 +8,5 @@ import Foundation protocol MediaPreviewingViewController: AnyObject { - func isInteractiveDismissable() -> Bool + func isInteractiveDismissible() -> Bool } From 8e58478290eeefede4fcc92e961c173a3062c4e0 Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 1 Jul 2021 20:23:36 +0800 Subject: [PATCH 2/3] fix: workaround text view not read in voice over issue --- Mastodon/Diffiable/Section/StatusSection.swift | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Mastodon/Diffiable/Section/StatusSection.swift b/Mastodon/Diffiable/Section/StatusSection.swift index ce9f07ae0..dd244eba0 100644 --- a/Mastodon/Diffiable/Section/StatusSection.swift +++ b/Mastodon/Diffiable/Section/StatusSection.swift @@ -99,6 +99,17 @@ extension StatusSection { ) cell.delegate = statusTableViewCellDelegate cell.isAccessibilityElement = true + // FIXME: + cell.accessibilityLabel = { + [ + cell.statusView.headerInfoLabel.accessibilityLabel, + cell.statusView.nameLabel.accessibilityLabel, + cell.statusView.dateLabel.accessibilityLabel, + cell.statusView.contentMetaText.textView.accessibilityLabel, + ] + .compactMap { $0 } + .joined(separator: " ") + }() return cell case .status(let objectID, let attribute), .root(let objectID, let attribute), @@ -566,11 +577,15 @@ extension StatusSection { ) let metaContent = try MastodonMetaContent.convert(document: content) cell.statusView.contentMetaText.configure(content: metaContent) + cell.statusView.contentMetaText.textView.accessibilityLabel = metaContent.trimmed } catch { cell.statusView.contentMetaText.textView.text = " " + cell.statusView.contentMetaText.textView.accessibilityLabel = "" assertionFailure() } + cell.statusView.contentMetaText.textView.accessibilityTraits = [.staticText] + cell.statusView.contentMetaText.textView.accessibilityElementsHidden = false cell.statusView.contentMetaText.textView.accessibilityLanguage = (status.reblog ?? status).language // set visibility From 7384b82ba3550d648b0fd83da2542f4df8195f40 Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 1 Jul 2021 20:24:58 +0800 Subject: [PATCH 3/3] chore: update version to 0.8.1 (26) --- Mastodon.xcodeproj/project.pbxproj | 32 +++++++++++++++--------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 682e2ea4a..86bf61f12 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -3847,7 +3847,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 25; + CURRENT_PROJECT_VERSION = 26; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -3855,7 +3855,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 0.8.0; + MARKETING_VERSION = 0.8.1; PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -3874,7 +3874,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 25; + CURRENT_PROJECT_VERSION = 26; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -3882,7 +3882,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 0.8.0; + MARKETING_VERSION = 0.8.1; PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -4202,7 +4202,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 25; + CURRENT_PROJECT_VERSION = 26; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4210,7 +4210,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 0.8.0; + MARKETING_VERSION = 0.8.1; PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -4316,7 +4316,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 25; + CURRENT_PROJECT_VERSION = 26; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4324,7 +4324,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 0.8.0; + MARKETING_VERSION = 0.8.1; PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.NotificationService; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -4435,7 +4435,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 25; + CURRENT_PROJECT_VERSION = 26; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4443,7 +4443,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 0.8.0; + MARKETING_VERSION = 0.8.1; PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -4549,7 +4549,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 25; + CURRENT_PROJECT_VERSION = 26; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4557,7 +4557,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 0.8.0; + MARKETING_VERSION = 0.8.1; PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.NotificationService; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -4603,7 +4603,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 25; + CURRENT_PROJECT_VERSION = 26; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4611,7 +4611,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 0.8.0; + MARKETING_VERSION = 0.8.1; PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.NotificationService; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -4626,7 +4626,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 25; + CURRENT_PROJECT_VERSION = 26; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4634,7 +4634,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 0.8.0; + MARKETING_VERSION = 0.8.1; PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.NotificationService; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES;