-
Notifications
You must be signed in to change notification settings - Fork 35
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
5 changed files
with
308 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
170 changes: 170 additions & 0 deletions
170
Stepic/Sources/Modules/Explore/View/ExploreBlockHeaderView/NewExploreBlockHeaderView.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
import SnapKit | ||
import UIKit | ||
|
||
protocol NewExploreBlockHeaderViewProtocol: ExploreBlockHeaderViewProtocol { | ||
var descriptionText: String? { get set } | ||
} | ||
|
||
extension NewExploreBlockHeaderView { | ||
struct Appearance { | ||
var titleLabelColor = UIColor.stepikSystemPrimaryText | ||
let titleLabelFont = Typography.title3Font | ||
|
||
let subtitleLabelFont = Typography.calloutFont | ||
let subtitleLabelColor = UIColor.stepikSystemSecondaryText | ||
|
||
let descriptionLabelFont = Typography.calloutFont | ||
let descriptionLabelColor = UIColor.stepikSystemSecondaryText | ||
|
||
let labelsSpacing: CGFloat = 8 | ||
|
||
var showAllButtonColor = UIColor.stepikSystemSecondaryText | ||
let showAllButtonFont = Typography.title3Font | ||
let showAllButtonInsets = LayoutInsets(left: 16) | ||
} | ||
} | ||
|
||
final class NewExploreBlockHeaderView: UIView, NewExploreBlockHeaderViewProtocol { | ||
let appearance: Appearance | ||
|
||
private let analytics: Analytics | ||
|
||
private lazy var titleLabel: UILabel = { | ||
let label = UILabel() | ||
label.font = self.appearance.titleLabelFont | ||
label.textColor = self.appearance.titleLabelColor | ||
label.numberOfLines = 1 | ||
return label | ||
}() | ||
|
||
private lazy var subtitleLabel: UILabel = { | ||
let label = UILabel() | ||
label.font = self.appearance.subtitleLabelFont | ||
label.textColor = self.appearance.subtitleLabelColor | ||
label.numberOfLines = 1 | ||
return label | ||
}() | ||
|
||
private lazy var descriptionLabel: UILabel = { | ||
let label = UILabel() | ||
label.font = self.appearance.descriptionLabelFont | ||
label.textColor = self.appearance.descriptionLabelColor | ||
label.numberOfLines = 0 | ||
return label | ||
}() | ||
|
||
private lazy var showAllButton: UIButton = { | ||
let button = UIButton(type: .system) | ||
button.tintColor = self.appearance.showAllButtonColor | ||
button.titleLabel?.font = self.appearance.showAllButtonFont | ||
button.contentHorizontalAlignment = .right | ||
button.addTarget(self, action: #selector(self.showAllButtonClicked), for: .touchUpInside) | ||
button.setTitle(NSLocalizedString("ShowAll", comment: ""), for: .normal) | ||
return button | ||
}() | ||
|
||
private lazy var labelsStackView: UIStackView = { | ||
let stackView = UIStackView() | ||
stackView.axis = .vertical | ||
stackView.spacing = self.appearance.labelsSpacing | ||
return stackView | ||
}() | ||
|
||
var titleText: String? { | ||
didSet { | ||
self.titleLabel.text = self.titleText | ||
self.titleLabel.isHidden = self.titleText?.isEmpty ?? true | ||
} | ||
} | ||
|
||
// TODO: Refactor rename to subtitleText | ||
var summaryText: String? { | ||
didSet { | ||
self.subtitleLabel.text = self.summaryText | ||
self.subtitleLabel.isHidden = self.summaryText?.isEmpty ?? true | ||
} | ||
} | ||
|
||
var descriptionText: String? { | ||
didSet { | ||
self.descriptionLabel.text = self.descriptionText | ||
self.descriptionLabel.isHidden = self.descriptionText?.isEmpty ?? true | ||
} | ||
} | ||
|
||
var shouldShowAllButton: Bool = true { | ||
didSet { | ||
// We should not only hidden button but resize cause there is no space | ||
if self.shouldShowAllButton { | ||
self.showAllButton.isHidden = false | ||
} else { | ||
self.showAllButton.isHidden = true | ||
self.showAllButton.snp.makeConstraints { make in | ||
make.width.equalTo(0) | ||
} | ||
} | ||
} | ||
} | ||
|
||
var onShowAllButtonClick: (() -> Void)? | ||
|
||
override var intrinsicContentSize: CGSize { | ||
let labelsStackViewIntrinsicContentSize = self.labelsStackView | ||
.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize) | ||
return CGSize( | ||
width: UIView.noIntrinsicMetric, | ||
height: labelsStackViewIntrinsicContentSize.height | ||
) | ||
} | ||
|
||
init( | ||
frame: CGRect = .zero, | ||
appearance: Appearance = Appearance(), | ||
analytics: Analytics = StepikAnalytics.shared | ||
) { | ||
self.appearance = appearance | ||
self.analytics = analytics | ||
super.init(frame: frame) | ||
|
||
self.addSubviews() | ||
self.makeConstraints() | ||
} | ||
|
||
@available(*, unavailable) | ||
required init?(coder aDecoder: NSCoder) { | ||
fatalError("init(coder:) has not been implemented") | ||
} | ||
|
||
@objc | ||
private func showAllButtonClicked() { | ||
self.analytics.send(.courseListShowAllTapped) | ||
self.onShowAllButtonClick?() | ||
} | ||
} | ||
|
||
extension NewExploreBlockHeaderView: ProgrammaticallyInitializableViewProtocol { | ||
func addSubviews() { | ||
self.addSubview(self.labelsStackView) | ||
self.labelsStackView.addArrangedSubview(self.titleLabel) | ||
self.labelsStackView.addArrangedSubview(self.subtitleLabel) | ||
self.labelsStackView.addArrangedSubview(self.descriptionLabel) | ||
|
||
self.addSubview(self.showAllButton) | ||
} | ||
|
||
func makeConstraints() { | ||
self.labelsStackView.translatesAutoresizingMaskIntoConstraints = false | ||
self.labelsStackView.snp.makeConstraints { make in | ||
make.top.left.bottom.equalToSuperview() | ||
} | ||
|
||
self.showAllButton.translatesAutoresizingMaskIntoConstraints = false | ||
self.showAllButton.snp.makeConstraints { make in | ||
make.leading | ||
.equalTo(self.labelsStackView.snp.trailing) | ||
.offset(self.appearance.showAllButtonInsets.left) | ||
make.right.equalToSuperview() | ||
make.centerY.equalTo(self.titleLabel.snp.centerY) | ||
} | ||
} | ||
} |
File renamed without changes.
111 changes: 111 additions & 0 deletions
111
Stepic/Sources/Views/ExploreBlockContainerView/NewExploreBlockContainerView.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
import SnapKit | ||
import UIKit | ||
|
||
extension NewExploreBlockContainerView { | ||
struct Appearance { | ||
var backgroundColor = UIColor.stepikBackground | ||
|
||
let headerViewInsets = UIEdgeInsets(top: 32, left: 20, bottom: 16, right: 20) | ||
var contentViewInsets = UIEdgeInsets(top: 16, left: 0, bottom: 0, right: 0) | ||
} | ||
} | ||
|
||
final class NewExploreBlockContainerView: UIView { | ||
let appearance: Appearance | ||
|
||
private let headerView: (UIView & NewExploreBlockHeaderViewProtocol)? | ||
private let contentView: UIView | ||
|
||
var onShowAllButtonClick: (() -> Void)? { | ||
didSet { | ||
self.headerView?.onShowAllButtonClick = self.onShowAllButtonClick | ||
} | ||
} | ||
|
||
override var intrinsicContentSize: CGSize { | ||
let headerViewHeight = self.headerView?.intrinsicContentSize.height ?? 0 | ||
let headerViewHeightWithInsets = headerViewHeight == 0 | ||
? 0 | ||
: (headerViewHeight + self.appearance.headerViewInsets.top) | ||
|
||
let contentViewHeight = self.contentView.intrinsicContentSize.height | ||
let contentViewHeightWithInsets = contentViewHeight | ||
+ self.appearance.contentViewInsets.top | ||
+ self.appearance.contentViewInsets.bottom | ||
|
||
let finalHeight = headerViewHeightWithInsets + contentViewHeightWithInsets | ||
|
||
return CGSize(width: UIView.noIntrinsicMetric, height: finalHeight) | ||
} | ||
|
||
init( | ||
frame: CGRect = .zero, | ||
headerView: (UIView & NewExploreBlockHeaderViewProtocol)?, | ||
contentView: UIView, | ||
appearance: Appearance = Appearance() | ||
) { | ||
self.appearance = appearance | ||
self.headerView = headerView | ||
self.contentView = contentView | ||
|
||
super.init(frame: frame) | ||
|
||
self.setupView() | ||
self.addSubviews() | ||
self.makeConstraints() | ||
} | ||
|
||
@available(*, unavailable) | ||
required init?(coder aDecoder: NSCoder) { | ||
fatalError("init(coder:) has not been implemented") | ||
} | ||
|
||
override func layoutSubviews() { | ||
super.layoutSubviews() | ||
self.invalidateIntrinsicContentSize() | ||
} | ||
} | ||
|
||
extension NewExploreBlockContainerView: ProgrammaticallyInitializableViewProtocol { | ||
func setupView() { | ||
self.backgroundColor = self.appearance.backgroundColor | ||
self.contentView.clipsToBounds = false | ||
} | ||
|
||
func addSubviews() { | ||
if let headerView = self.headerView { | ||
self.addSubview(headerView) | ||
} | ||
|
||
self.addSubview(self.contentView) | ||
} | ||
|
||
func makeConstraints() { | ||
if let headerView = self.headerView { | ||
headerView.translatesAutoresizingMaskIntoConstraints = false | ||
headerView.snp.makeConstraints { make in | ||
make.top.equalToSuperview().offset(self.appearance.headerViewInsets.top) | ||
make.leading.equalToSuperview().offset(self.appearance.headerViewInsets.left) | ||
make.trailing.equalToSuperview().offset(-self.appearance.headerViewInsets.right) | ||
} | ||
|
||
self.contentView.translatesAutoresizingMaskIntoConstraints = false | ||
self.contentView.snp.makeConstraints { make in | ||
make.top | ||
.equalTo(headerView.snp.bottom) | ||
.offset(self.appearance.contentViewInsets.top) | ||
make.leading.equalToSuperview().offset(self.appearance.contentViewInsets.left) | ||
make.bottom.equalToSuperview().offset(-self.appearance.contentViewInsets.bottom) | ||
make.trailing.equalToSuperview().offset(-self.appearance.contentViewInsets.right) | ||
} | ||
} else { | ||
self.contentView.translatesAutoresizingMaskIntoConstraints = false | ||
self.contentView.snp.makeConstraints { make in | ||
make.top.equalToSuperview().offset(self.appearance.contentViewInsets.top) | ||
make.leading.equalToSuperview().offset(self.appearance.contentViewInsets.left) | ||
make.bottom.equalToSuperview().offset(-self.appearance.contentViewInsets.bottom) | ||
make.trailing.equalToSuperview().offset(-self.appearance.contentViewInsets.right) | ||
} | ||
} | ||
} | ||
} |