diff --git a/App/Comments/CommentsViewController.swift b/App/Comments/CommentsViewController.swift index 3dbee3ab..61399122 100644 --- a/App/Comments/CommentsViewController.swift +++ b/App/Comments/CommentsViewController.swift @@ -15,6 +15,7 @@ import PromiseKit class CommentsViewController: UITableViewController { var swipeCellKitActions: SwipeCellKitActions? var navigationService: NavigationService? + var showPost: Bool = true private enum ActivityType { case comments @@ -35,6 +36,11 @@ class CommentsViewController: UITableViewController { override func viewDidLoad() { super.viewDidLoad() setupRefreshControl() + + if !showPost { + setupNavigation() + } + load() } @@ -164,7 +170,7 @@ extension CommentsViewController { override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { switch section { - case 0: return post == nil ? 0 : 1 + case 0: return post == nil || !showPost ? 0 : 1 default: return commentsController.visibleComments.count } } @@ -448,7 +454,11 @@ extension CommentsViewController: SwipeTableViewCellDelegate { } openURL(url: url) { if let safariViewController = SFSafariViewController.instance(for: url) { - present(safariViewController, animated: true) + present(safariViewController, animated: true) { + if let post = self.post { + _ = DraggableCommentsButton(for: safariViewController, and: post) + } + } } } setupHandoff(with: post, activityType: .link(url: url)) @@ -467,7 +477,11 @@ extension CommentsViewController: CommentDelegate { func linkTapped(_ url: URL, sender: UITextView) { openURL(url: url) { if let safariViewController = SFSafariViewController.instance(for: url) { - present(safariViewController, animated: true) + present(safariViewController, animated: true) { + if let post = self.post { + _ = DraggableCommentsButton(for: safariViewController, and: post) + } + } } } setupHandoff(with: post, activityType: .link(url: url)) @@ -544,3 +558,16 @@ extension CommentsViewController { } } } + +// MARK: - Navigation setup for presented controller +extension CommentsViewController { + private func setupNavigation() { + title = "Comments" + let doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(dismissSelf)) + navigationItem.leftBarButtonItem = doneButton + } + + @objc private func dismissSelf() { + dismiss(animated: true) + } +} diff --git a/App/Feed/FeedCollectionViewController.swift b/App/Feed/FeedCollectionViewController.swift index 60be3887..4fbefecf 100644 --- a/App/Feed/FeedCollectionViewController.swift +++ b/App/Feed/FeedCollectionViewController.swift @@ -148,7 +148,9 @@ extension FeedCollectionViewController: UICollectionViewDelegate { self.openURL(url: post.url) { if let svc = SFSafariViewController.instance(for: post.url) { - self.navigationController?.present(svc, animated: true) + self.navigationController?.present(svc, animated: true) { + _ = DraggableCommentsButton(for: svc, and: post) + } } } } @@ -170,7 +172,9 @@ extension FeedCollectionViewController: UICollectionViewDelegate { !post.url.absoluteString.starts(with: "item?id=") { // self job posts should show comments self.openURL(url: post.url) { if let svc = SFSafariViewController.instance(for: post.url) { - self.navigationController?.present(svc, animated: true) + self.navigationController?.present(svc, animated: true) { + _ = DraggableCommentsButton(for: svc, and: post) + } } } } else { @@ -222,7 +226,9 @@ extension FeedCollectionViewController: UICollectionViewDelegate { ) { _ in self.openURL(url: post.url) { if let svc = SFSafariViewController.instance(for: post.url) { - self.navigationController?.present(svc, animated: true) + self.navigationController?.present(svc, animated: true) { + _ = DraggableCommentsButton(for: svc, and: post) + } } } } diff --git a/App/Shared/DraggableCommentsButton.swift b/App/Shared/DraggableCommentsButton.swift new file mode 100644 index 00000000..1c911dfe --- /dev/null +++ b/App/Shared/DraggableCommentsButton.swift @@ -0,0 +1,135 @@ +// +// DraggableCommentsButton.swift +// Hackers +// +// Created by Stanislav Rassolenko on 7/2/24. +// Copyright © 2024 Glass Umbrella. All rights reserved. +// + +import Foundation +import UIKit + +class DraggableCommentsButton: UIButton { + private var post: Post + private var parentVc: UIViewController + + private lazy var countLabel: UILabel = { + let label = UILabel() + label.font = .systemFont(ofSize: 11) + label.text = String(post.commentsCount) + label.textColor = .white + label.backgroundColor = .red + label.cornerRadius = 12.5 + label.textAlignment = .center + label.adjustsFontSizeToFitWidth = true + label.translatesAutoresizingMaskIntoConstraints = false + return label + }() + + required init(for parent: UIViewController, and post: Post) { + self.parentVc = parent + self.post = post + super.init(frame: CGRect.zero) + commonInit() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func commonInit() { + setupLayout() + setupForParent() + setupCountLabel() + } + + private func setupLayout() { + layer.cornerRadius = 25 + backgroundColor = UIColor.lightGray.withAlphaComponent(0.6) + setImage(UIImage(systemName: "message"), for: .normal) + imageView?.contentMode = .scaleToFill + imageView?.tintColor = .white + isOpaque = true + translatesAutoresizingMaskIntoConstraints = false + + addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(dragHandler))) + } + + private func setupForParent() { + addTarget(self, action: #selector(buttonAction), for: .touchUpInside) + parentVc.view.addSubview(self) + constrainSelf() + parentVc.view.bringSubviewToFront(self) + layer.zPosition = parentVc.view.layer.zPosition + 1 + for subview in parentVc.view.subviews { + subview.isUserInteractionEnabled = false + } + isEnabled = true + isUserInteractionEnabled = true + } + + private func setupCountLabel() { + addSubview(countLabel) + constrainCountLabel() + } + + private func constrainCountLabel() { + countLabel.centerXAnchor.constraint(equalTo: trailingAnchor, constant: -5).isActive = true + countLabel.centerYAnchor.constraint(equalTo: bottomAnchor, constant: -5).isActive = true + countLabel.widthAnchor.constraint(equalToConstant: 25).isActive = true + countLabel.heightAnchor.constraint(equalToConstant: 25).isActive = true + } + + private func constrainSelf() { + topAnchor.constraint(equalTo: parentVc.view.safeAreaLayoutGuide.topAnchor, constant: (66)).isActive = true + trailingAnchor.constraint(equalTo: parentVc.view.trailingAnchor, constant: -16).isActive = true + heightAnchor.constraint(equalToConstant: 50).isActive = true + widthAnchor.constraint(equalToConstant: 50).isActive = true + } + + @objc private func buttonAction() { + let storyboard = UIStoryboard(name: "Main", bundle: nil) + let commentsVc = storyboard.instantiateViewController( + withIdentifier: "CommentsViewController" + ) as? CommentsViewController + + if let cvc = commentsVc { + cvc.postId = post.id + cvc.showPost = false + cvc.post = post + let navigationController = UINavigationController(rootViewController: cvc) + self.parentVc.present(navigationController, animated: true, completion: nil) + } + } + + @objc private func dragHandler(gesture: UIPanGestureRecognizer) { + let location = gesture.location(in: parentVc.view) + let draggedView = gesture.view + draggedView?.center = location + + if gesture.state == .ended { + if self.frame.midX >= (self.parentVc.view.layer.frame.width) / 2 { + self.positionViewWithAnimation { + self.center.x = (self.parentVc.view.layer.frame.width) - 40 + } + } else { + self.positionViewWithAnimation { + self.center.x = 40 + } + } + } + } + + private func positionViewWithAnimation(animation: @escaping () -> Void) { + UIView.animate( + withDuration: 0.5, + delay: 0, + usingSpringWithDamping: 1, + initialSpringVelocity: 1, + options: .curveEaseIn, + animations: animation, + completion: nil + ) + } +} + diff --git a/Hackers.xcodeproj/project.pbxproj b/Hackers.xcodeproj/project.pbxproj index 6caa4bc5..0f8ee448 100644 --- a/Hackers.xcodeproj/project.pbxproj +++ b/Hackers.xcodeproj/project.pbxproj @@ -90,6 +90,7 @@ 24F39F9B18AFB1150055F8DC /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 24F39F9A18AFB1150055F8DC /* Images.xcassets */; }; 24FF021D226C9BEA002EF8DD /* SwinjectStoryboardExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FF021C226C9BEA002EF8DD /* SwinjectStoryboardExtensions.swift */; }; 24FFFF5A23362C7800D009EF /* HackersKitExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFFF5923362C7800D009EF /* HackersKitExtensions.swift */; }; + 3AD2F1862C34131E0034C399 /* DraggableCommentsButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AD2F1852C34131E0034C399 /* DraggableCommentsButton.swift */; }; 698FE7B523EE5FE300F5828C /* Colors.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 698FE7B423EE5FE300F5828C /* Colors.xcassets */; }; 8B782E032A5AB01C00FD6B39 /* TextSelectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B782E022A5AB01C00FD6B39 /* TextSelectionViewController.swift */; }; /* End PBXBuildFile section */ @@ -219,6 +220,7 @@ 24F644FD24951D6400869504 /* Scanfile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Scanfile; sourceTree = ""; }; 24FF021C226C9BEA002EF8DD /* SwinjectStoryboardExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwinjectStoryboardExtensions.swift; sourceTree = ""; }; 24FFFF5923362C7800D009EF /* HackersKitExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HackersKitExtensions.swift; sourceTree = ""; }; + 3AD2F1852C34131E0034C399 /* DraggableCommentsButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraggableCommentsButton.swift; sourceTree = ""; }; 698FE7B423EE5FE300F5828C /* Colors.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Colors.xcassets; sourceTree = ""; }; 8B782E022A5AB01C00FD6B39 /* TextSelectionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextSelectionViewController.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -393,6 +395,7 @@ 2479E11422B69CF100D9F1A4 /* ThumbnailImageView.swift */, 24D1845824B336B60017E4F4 /* TitleButton.swift */, 2406B37A28ACF8C700CB396B /* UINotifications.swift */, + 3AD2F1852C34131E0034C399 /* DraggableCommentsButton.swift */, ); path = Shared; sourceTree = ""; @@ -868,6 +871,7 @@ 24191F8D1944C991003C0D98 /* CommentsController.swift in Sources */, 24CEAA9D1F8917D60050DEDF /* ReviewController.swift in Sources */, 2464D213209DEFB100C7F8FC /* UINavigationControllerExtensions.swift in Sources */, + 3AD2F1862C34131E0034C399 /* DraggableCommentsButton.swift in Sources */, 24B1A6A522B508A40051EAFD /* OnboardingService.swift in Sources */, 249B8F8A22A2C9B3002A9EC5 /* TableViewBackgroundView.swift in Sources */, 2486D7D727FB0A26007504C6 /* AuthenticationHelper.swift in Sources */,