// // FeedItemViewController.swift // ReviewsFeed // // Created by Dmitrii Ivanov on 21/07/2020. // Copyright © 2020 ING. All rights reserved. // import ReviewsUIKit import SwiftUI import UIKit final class FeedItemViewController: UIViewController { // MARK: Constants private let item: Review // MARK: Properties private lazy var appVersionController = { UIHostingController(rootView: FakeLabel( systemIcon: .Icon.info, title: item.rating.appVersion )) }() private lazy var authorController = { UIHostingController(rootView: FakeLabel( systemIcon: .Icon.person, title: item.author )) }() private lazy var starRatingController = { UIHostingController(rootView: StarRating( item.rating.stars, of: .Rating.total )) }() // MARK: Outlets private lazy var appVersionView = { guard let view = appVersionController.view else { fatalError("The StarRating component must be initialised") } view.translatesAutoresizingMaskIntoConstraints = false return view }() private lazy var authorView = { guard let view = authorController.view else { fatalError("The StarRating component must be initialised") } view.translatesAutoresizingMaskIntoConstraints = false return view }() private lazy var commentLabel = { let label = UILabel() label.font = UIFont.preferredFont(forTextStyle: .body) label.numberOfLines = 0 label.translatesAutoresizingMaskIntoConstraints = false label.text = item.comment return label }() private lazy var ratingView = { let stack = UIStackView() stack.axis = .horizontal stack.backgroundColor = .clear stack.distribution = .fillProportionally stack.translatesAutoresizingMaskIntoConstraints = false stack.addArrangedSubview(starRatingView) stack.addArrangedSubview(appVersionView) return stack }() private lazy var scrollView = { let scroll = UIScrollView() scroll.backgroundColor = .clear scroll.showsVerticalScrollIndicator = true scroll.translatesAutoresizingMaskIntoConstraints = false return scroll }() private lazy var stackView = { let stack = UIStackView() stack.axis = .vertical stack.alignment = .leading stack.backgroundColor = .clear stack.distribution = .fill stack.spacing = 16 stack.translatesAutoresizingMaskIntoConstraints = false return stack }() private lazy var starRatingView = { guard let view = starRatingController.view else { fatalError("The StarRating component must be initialised") } view.translatesAutoresizingMaskIntoConstraints = false return view }() private lazy var titleLabel = { let label = UILabel() label.font = UIFont.preferredFont(forTextStyle: .headline) label.numberOfLines = 0 label.translatesAutoresizingMaskIntoConstraints = false label.text = item.title return label }() // MARK: Initialisers init(_ item: Review) { self.item = item super.init(nibName: nil, bundle: nil) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } // MARK: UIViewController override func viewDidLoad() { super.viewDidLoad() addChild(appVersionController) addChild(authorController) addChild(starRatingController) setView() setNavigationBar() setLayout() appVersionController.didMove(toParent: self) authorController.didMove(toParent: self) starRatingController.didMove(toParent: self) } } // MARK: - Helpers private extension FeedItemViewController { // MARK: Functions func setLayout() { let scrollContentGuide = scrollView.contentLayoutGuide let scrollFrameGuide = scrollView.frameLayoutGuide NSLayoutConstraint.activate([ scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor), scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor), scrollView.topAnchor.constraint(equalTo: view.topAnchor), scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor), stackView.bottomAnchor.constraint(equalTo: scrollContentGuide.bottomAnchor, constant: -16), stackView.leadingAnchor.constraint(equalTo: scrollContentGuide.leadingAnchor), stackView.topAnchor.constraint(equalTo: scrollContentGuide.topAnchor, constant: 8), stackView.trailingAnchor.constraint(equalTo: scrollContentGuide.trailingAnchor), stackView.leadingAnchor.constraint(equalTo: scrollFrameGuide.leadingAnchor), stackView.trailingAnchor.constraint(equalTo: scrollFrameGuide.trailingAnchor), authorView.leadingAnchor.constraint(equalTo: stackView.leadingAnchor, constant: 16), ratingView.leadingAnchor.constraint(equalTo: stackView.leadingAnchor, constant: 16), titleLabel.leadingAnchor.constraint(equalTo: stackView.leadingAnchor, constant: 16), titleLabel.trailingAnchor.constraint(equalTo: stackView.trailingAnchor, constant: -16), commentLabel.leadingAnchor.constraint(equalTo: stackView.leadingAnchor, constant: 16), commentLabel.trailingAnchor.constraint(equalTo: stackView.trailingAnchor, constant: -16), ]) } func setNavigationBar() { navigationController?.navigationBar.prefersLargeTitles = true navigationController?.navigationBar.isTranslucent = true navigationItem.title = "# \(String(item.id))" } func setView() { view.backgroundColor = .systemBackground view.addSubview(scrollView) scrollView.addSubview(stackView) stackView.addArrangedSubview(authorView) stackView.addArrangedSubview(ratingView) stackView.addArrangedSubview(titleLabel) stackView.addArrangedSubview(commentLabel) } } // MARK: - Previews @available(iOS 17.0, *) #Preview("Feed Item with a review") { UINavigationController(rootViewController: FeedItemViewController(.init( author: "Some author name here...", comment: "Some long, explanatory review comment goes here...", id: 1, rating: .init(stars: 3, appVersion: "v1.0.0"), title: "Some review title goes here..." ))) }