diff --git a/Mastodon/Scene/Compose/ComposeViewController.swift b/Mastodon/Scene/Compose/ComposeViewController.swift index a3c56b3e2..55ad0816c 100644 --- a/Mastodon/Scene/Compose/ComposeViewController.swift +++ b/Mastodon/Scene/Compose/ComposeViewController.swift @@ -860,20 +860,45 @@ extension ComposeViewController { let repliedToCellFrame = viewModel.repliedToCellFrame.value guard repliedToCellFrame != .zero else { return } - let throttle = viewModel.repliedToCellFrame.value.height - scrollView.adjustedContentInset.top - // print("\(throttle) - \(scrollView.contentOffset.y)") + + // try to find some patterns: + // print(""" + // repliedToCellFrame: \(viewModel.repliedToCellFrame.value.height) + // scrollView.contentOffset.y: \(scrollView.contentOffset.y) + // scrollView.contentSize.height: \(scrollView.contentSize.height) + // scrollView.frame: \(scrollView.frame) + // scrollView.adjustedContentInset.top: \(scrollView.adjustedContentInset.top) + // scrollView.adjustedContentInset.bottom: \(scrollView.adjustedContentInset.bottom) + // """) switch viewModel.collectionViewState.value { case .fold: - if scrollView.contentOffset.y < throttle { + os_log("%{public}s[%{public}ld], %{public}s: fold", ((#file as NSString).lastPathComponent), #line, #function) + guard velocity.y < 0 else { return } + let offsetY = scrollView.contentOffset.y + scrollView.adjustedContentInset.top + if offsetY < -44 { + tableView.contentInset.top = 0 + targetContentOffset.pointee = CGPoint(x: 0, y: -scrollView.adjustedContentInset.top) viewModel.collectionViewState.value = .expand } - os_log("%{public}s[%{public}ld], %{public}s: fold", ((#file as NSString).lastPathComponent), #line, #function) case .expand: - if scrollView.contentOffset.y > -44 { + os_log("%{public}s[%{public}ld], %{public}s: expand", ((#file as NSString).lastPathComponent), #line, #function) + guard velocity.y > 0 else { return } + // check if top across + let topOffset = (scrollView.contentOffset.y + scrollView.adjustedContentInset.top) - repliedToCellFrame.height + + // check if bottom bounce + let bottomOffsetY = scrollView.contentOffset.y + (scrollView.frame.height - scrollView.adjustedContentInset.bottom) + let bottomOffset = bottomOffsetY - scrollView.contentSize.height + + if topOffset > 44 { + // do not interrupt user scrolling + viewModel.collectionViewState.value = .fold + } else if bottomOffset > 44 { + tableView.contentInset.top = -repliedToCellFrame.height + targetContentOffset.pointee = CGPoint(x: 0, y: -repliedToCellFrame.height) viewModel.collectionViewState.value = .fold - os_log("%{public}s[%{public}ld], %{public}s: expand", ((#file as NSString).lastPathComponent), #line, #function) } } } @@ -910,7 +935,8 @@ extension ComposeViewController: UICollectionViewDelegate { extension ComposeViewController: UIAdaptivePresentationControllerDelegate { func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle { - return traitCollection.userInterfaceIdiom == .pad ? .formSheet : .automatic + return .fullScreen + //return traitCollection.userInterfaceIdiom == .pad ? .formSheet : .automatic } func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool { diff --git a/Mastodon/Scene/Compose/ComposeViewModel+Diffable.swift b/Mastodon/Scene/Compose/ComposeViewModel+Diffable.swift index fa38afcfe..59de0d60a 100644 --- a/Mastodon/Scene/Compose/ComposeViewModel+Diffable.swift +++ b/Mastodon/Scene/Compose/ComposeViewModel+Diffable.swift @@ -253,6 +253,8 @@ extension ComposeViewModel: UITableViewDataSource { cell.statusContentWarningEditorView.alpha = 0 UIView.animate(withDuration: 0.33, delay: 0, options: [.curveEaseOut]) { cell.statusContentWarningEditorView.alpha = 1 + tableView.beginUpdates() + tableView.endUpdates() } completion: { _ in // do nothing } diff --git a/Mastodon/Scene/Compose/ComposeViewModel.swift b/Mastodon/Scene/Compose/ComposeViewModel.swift index 15dd0ef3b..69b9836ac 100644 --- a/Mastodon/Scene/Compose/ComposeViewModel.swift +++ b/Mastodon/Scene/Compose/ComposeViewModel.swift @@ -29,7 +29,7 @@ final class ComposeViewModel: NSObject { let selectedStatusVisibility: CurrentValueSubject let activeAuthentication: CurrentValueSubject let activeAuthenticationBox: CurrentValueSubject - let traitCollectionDidChangePublisher = CurrentValueSubject(Void()) // use CurrentValueSubject to make intial event emit + let traitCollectionDidChangePublisher = CurrentValueSubject(Void()) // use CurrentValueSubject to make initial event emit let repliedToCellFrame = CurrentValueSubject(.zero) let autoCompleteRetryLayoutTimes = CurrentValueSubject(0) let autoCompleteInfo = CurrentValueSubject(nil) diff --git a/Mastodon/Scene/Compose/View/StatusContentWarningEditorView.swift b/Mastodon/Scene/Compose/View/StatusContentWarningEditorView.swift index e81dc8b23..1d7ae65e3 100644 --- a/Mastodon/Scene/Compose/View/StatusContentWarningEditorView.swift +++ b/Mastodon/Scene/Compose/View/StatusContentWarningEditorView.swift @@ -57,29 +57,43 @@ extension StatusContentWarningEditorView { containerBackgroundView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: 1024), containerBackgroundView.bottomAnchor.constraint(equalTo: bottomAnchor), ]) - - iconImageView.translatesAutoresizingMaskIntoConstraints = false - addSubview(iconImageView) + + let containerStackView = UIStackView() + containerStackView.axis = .horizontal + containerStackView.translatesAutoresizingMaskIntoConstraints = false + addSubview(containerStackView) NSLayoutConstraint.activate([ - iconImageView.centerYAnchor.constraint(equalTo: centerYAnchor), - iconImageView.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor), - iconImageView.widthAnchor.constraint(equalToConstant: StatusView.avatarImageSize.width).priority(.defaultHigh), // center alignment to avatar - ]) - iconImageView.setContentHuggingPriority(.required - 2, for: .horizontal) - - textView.translatesAutoresizingMaskIntoConstraints = false - addSubview(textView) - NSLayoutConstraint.activate([ - textView.centerYAnchor.constraint(equalTo: centerYAnchor), - textView.topAnchor.constraint(greaterThanOrEqualTo: topAnchor, constant: 6).priority(.required - 1), - textView.leadingAnchor.constraint(equalTo: iconImageView.trailingAnchor, constant: StatusView.avatarToLabelSpacing - 4), // align to name label. minus magic 4pt to remove addition inset - textView.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor), - bottomAnchor.constraint(greaterThanOrEqualTo: textView.bottomAnchor, constant: 6).priority(.required - 1), - //textView.heightAnchor.constraint(greaterThanOrEqualToConstant: 44).priority(.defaultHigh), + containerStackView.topAnchor.constraint(equalTo: topAnchor, constant: 6), + containerStackView.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor), + containerStackView.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor), + bottomAnchor.constraint(equalTo: containerStackView.bottomAnchor, constant: 6), ]) - textView.setContentHuggingPriority(.required - 1, for: .vertical) - textView.setContentCompressionResistancePriority(.required - 1, for: .vertical) + containerStackView.addArrangedSubview(iconImageView) + iconImageView.setContentHuggingPriority(.required - 1, for: .horizontal) + containerStackView.addArrangedSubview(textView) + +// iconImageView.translatesAutoresizingMaskIntoConstraints = false +// addSubview(iconImageView) +// NSLayoutConstraint.activate([ +// iconImageView.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor), +// iconImageView.widthAnchor.constraint(equalToConstant: StatusView.avatarImageSize.width).priority(.defaultHigh), // center alignment to avatar +// ]) +// iconImageView.setContentHuggingPriority(.required - 2, for: .horizontal) +// +// textView.translatesAutoresizingMaskIntoConstraints = false +// addSubview(textView) +// NSLayoutConstraint.activate([ +// textView.centerYAnchor.constraint(equalTo: centerYAnchor), +// textView.topAnchor.constraint(equalTo: topAnchor, constant: 6), +// textView.leadingAnchor.constraint(equalTo: iconImageView.trailingAnchor, constant: StatusView.avatarToLabelSpacing - 4), // align to name label. minus magic 4pt to remove addition inset +// textView.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor), +// bottomAnchor.constraint(equalTo: textView.bottomAnchor, constant: 6), +// textView.heightAnchor.constraint(greaterThanOrEqualToConstant: 44).priority(.defaultHigh), +// ]) +// +// textView.setContentHuggingPriority(.required - 1, for: .vertical) +// textView.setContentCompressionResistancePriority(.required - 1, for: .vertical) } }