From 33653911c38615c0cc5a46bcded5a36c3b43267f Mon Sep 17 00:00:00 2001 From: Nathan Mattes Date: Fri, 5 Apr 2024 17:06:54 +0200 Subject: [PATCH] Basic animation to show/hide :pill: (IOS-234) --- .../HomeTimelineViewController.swift | 66 ++++++++++++++++--- .../HomeTimeline/TimelineStatusPill.swift | 14 ++-- 2 files changed, 64 insertions(+), 16 deletions(-) diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift index da8a1c747..8a7cf920a 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift @@ -100,6 +100,9 @@ final class HomeTimelineViewController: UIViewController, NeedsDependency, Media let refreshControl = RefreshControl() let timelinePill = TimelineStatusPill() + var timelinePillCenterXAnchor: NSLayoutConstraint? + var timelinePillVisibleTopAnchor: NSLayoutConstraint? + var timelinePillHiddenTopAnchor: NSLayoutConstraint? private func generateTimeSelectorMenu() -> UIMenu { @@ -299,17 +302,24 @@ extension HomeTimelineViewController { } .store(in: &disposeBag) -// timelinePill.translatesAutoresizingMaskIntoConstraints = false -// view.addSubview(timelinePill) -// -// // has to up updated and animated -// timelinePill.update(with: .postSent) -// NSLayoutConstraint.activate([ -// timelinePill.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 8), -// timelinePill.centerXAnchor.constraint(equalTo: view.centerXAnchor), -// ]) + timelinePill.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(timelinePill) + + let timelinePillCenterXAnchor = timelinePill.centerXAnchor.constraint(equalTo: view.centerXAnchor) + let timelinePillVisibleTopAnchor = timelinePill.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 8) + let timelinePillHiddenTopAnchor = view.safeAreaLayoutGuide.topAnchor.constraint(equalTo: timelinePill.bottomAnchor, constant: 8) + + NSLayoutConstraint.activate([ + timelinePillHiddenTopAnchor, timelinePillCenterXAnchor + ]) + + timelinePill.addTarget(self, action: #selector(HomeTimelineViewController.timelinePillPressed(_:)), for: .touchUpInside) + + self.timelinePillCenterXAnchor = timelinePillCenterXAnchor + self.timelinePillVisibleTopAnchor = timelinePillVisibleTopAnchor + self.timelinePillHiddenTopAnchor = timelinePillHiddenTopAnchor } - + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) @@ -459,6 +469,42 @@ extension HomeTimelineViewController { } } + @objc private func timelinePillPressed(_ sender: TimelineStatusPill) { + guard let reason = sender.reason else { return } + switch reason { + case .newPosts: + print("Bring me to the new posts and disappear") + case .postSent: + print("Bring me to my post and disappear") + case .offline: + print("Just disappear") + } + + hideTimelinePill() + } + + private func showTimelinePill() { + guard let timelinePillHiddenTopAnchor, let timelinePillVisibleTopAnchor else { return } + + NSLayoutConstraint.deactivate([timelinePillHiddenTopAnchor]) + NSLayoutConstraint.activate([timelinePillVisibleTopAnchor]) + + UIView.animate(withDuration: 0.4) { + self.view.layoutIfNeeded() + } + } + + private func hideTimelinePill() { + guard let timelinePillHiddenTopAnchor, let timelinePillVisibleTopAnchor else { return } + + NSLayoutConstraint.deactivate([timelinePillVisibleTopAnchor]) + NSLayoutConstraint.activate([timelinePillHiddenTopAnchor]) + + UIView.animate(withDuration: 0.4, animations: { + self.view.layoutIfNeeded() + }) + } + } // MARK: - UIScrollViewDelegate extension HomeTimelineViewController { diff --git a/Mastodon/Scene/HomeTimeline/TimelineStatusPill.swift b/Mastodon/Scene/HomeTimeline/TimelineStatusPill.swift index e24c512f9..1d24fe674 100644 --- a/Mastodon/Scene/HomeTimeline/TimelineStatusPill.swift +++ b/Mastodon/Scene/HomeTimeline/TimelineStatusPill.swift @@ -5,32 +5,34 @@ import MastodonAsset class TimelineStatusPill: UIButton { - func update(with state: State) { + var reason: Reason? + + func update(with reason: Reason) { + self.reason = reason var configuration = UIButton.Configuration.filled() - configuration.attributedTitle = AttributedString( - state.title, attributes: AttributeContainer( + reason.title, attributes: AttributeContainer( [ .font: UIFontMetrics(forTextStyle: .subheadline).scaledFont(for: .systemFont(ofSize: 15, weight: .bold)), .foregroundColor: UIColor.white ] )) - let image = state.image? + let image = reason.image? .withConfiguration(UIImage.SymbolConfiguration(paletteColors: [.white])) .withConfiguration(UIImage.SymbolConfiguration(textStyle: .subheadline)) .withConfiguration(UIImage.SymbolConfiguration(pointSize: 12, weight: .bold, scale: .medium)) configuration.image = image configuration.imagePadding = 8 - configuration.baseBackgroundColor = state.backgroundColor + configuration.baseBackgroundColor = reason.backgroundColor configuration.cornerStyle = .capsule self.configuration = configuration } - public enum State { + public enum Reason { case newPosts case postSent case offline