Skip to content

Commit

Permalink
New catalog container view (#824)
Browse files Browse the repository at this point in the history
* Add header view

* Add container view
  • Loading branch information
ivan-magda authored Nov 16, 2020
1 parent 84e428e commit 0b8ba4f
Show file tree
Hide file tree
Showing 5 changed files with 308 additions and 3 deletions.
30 changes: 27 additions & 3 deletions Stepic.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,8 @@
2C73719224EBFF6C00ED24C3 /* FillBlanksTextCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C73719124EBFF6C00ED24C3 /* FillBlanksTextCollectionViewCell.swift */; };
2C73719424EBFF9100ED24C3 /* FillBlanksInputCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C73719324EBFF9100ED24C3 /* FillBlanksInputCollectionViewCell.swift */; };
2C73719624EBFFA700ED24C3 /* FillBlanksSelectCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C73719524EBFFA700ED24C3 /* FillBlanksSelectCollectionViewCell.swift */; };
2C73B0DF25628EF500EA217D /* NewExploreBlockContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C73B0DE25628EF500EA217D /* NewExploreBlockContainerView.swift */; };
2C73B0EB25628FE600EA217D /* NewExploreBlockHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C73B0EA25628FE600EA217D /* NewExploreBlockHeaderView.swift */; };
2C73E24124D0117400340052 /* NewProfileSocialProfilesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C73E24024D0117400340052 /* NewProfileSocialProfilesViewModel.swift */; };
2C73E24624D029F900340052 /* NewProfileSocialProfilesItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C73E24524D029F900340052 /* NewProfileSocialProfilesItemView.swift */; };
2C746642245613E900BB0800 /* UserCoursesNetworkService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C746641245613E900BB0800 /* UserCoursesNetworkService.swift */; };
Expand Down Expand Up @@ -2070,6 +2072,8 @@
2C73719124EBFF6C00ED24C3 /* FillBlanksTextCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FillBlanksTextCollectionViewCell.swift; sourceTree = "<group>"; };
2C73719324EBFF9100ED24C3 /* FillBlanksInputCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FillBlanksInputCollectionViewCell.swift; sourceTree = "<group>"; };
2C73719524EBFFA700ED24C3 /* FillBlanksSelectCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FillBlanksSelectCollectionViewCell.swift; sourceTree = "<group>"; };
2C73B0DE25628EF500EA217D /* NewExploreBlockContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewExploreBlockContainerView.swift; sourceTree = "<group>"; };
2C73B0EA25628FE600EA217D /* NewExploreBlockHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewExploreBlockHeaderView.swift; sourceTree = "<group>"; };
2C73E24024D0117400340052 /* NewProfileSocialProfilesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewProfileSocialProfilesViewModel.swift; sourceTree = "<group>"; };
2C73E24524D029F900340052 /* NewProfileSocialProfilesItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewProfileSocialProfilesItemView.swift; sourceTree = "<group>"; };
2C7466402456065F00BB0800 /* Model_user_courses_actions_v51.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Model_user_courses_actions_v51.xcdatamodel; sourceTree = "<group>"; };
Expand Down Expand Up @@ -3558,6 +3562,24 @@
path = Cells;
sourceTree = "<group>";
};
2C73B0D725628ECD00EA217D /* ExploreBlockContainerView */ = {
isa = PBXGroup;
children = (
62E984D999BE6BB5F6A64AE1 /* ExploreBlockContainerView.swift */,
2C73B0DE25628EF500EA217D /* NewExploreBlockContainerView.swift */,
);
path = ExploreBlockContainerView;
sourceTree = "<group>";
};
2C73B0E625628FD300EA217D /* ExploreBlockHeaderView */ = {
isa = PBXGroup;
children = (
62E98AA14C7255A86152B53B /* ExploreBlockHeaderView.swift */,
2C73B0EA25628FE600EA217D /* NewExploreBlockHeaderView.swift */,
);
path = ExploreBlockHeaderView;
sourceTree = "<group>";
};
2C73E24224D029BB00340052 /* Views */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -6503,7 +6525,6 @@
2C381BEE25505EC90084AD90 /* CourseListFilterBarButtonItem.swift */,
62E9856B0B8FB44A5492EF67 /* CourseRatingView.swift */,
62E983C44270B73F5F3508F2 /* DownloadControlView.swift */,
62E984D999BE6BB5F6A64AE1 /* ExploreBlockContainerView.swift */,
62E9802EAA7E12A5C9B4F800 /* HighlightFakeButton.swift */,
62E9869C9474DB9208F1E5FC /* ImageButton.swift */,
62E98CA36176671DDF744499 /* PaddingLabel.swift */,
Expand All @@ -6519,6 +6540,7 @@
2C06E09A2241045800AF4DA2 /* TableInputTextView.swift */,
62E988C4DC97F14EAC09BC41 /* TabSegmentedControlView.swift */,
2CFF8FFE242A22DF00FD7311 /* ContinueLastStepView */,
2C73B0D725628ECD00EA217D /* ExploreBlockContainerView */,
2C11C9F024EFC80400A4647B /* Layouts */,
62E989892C62C2BC2B1A3741 /* TabBar */,
);
Expand Down Expand Up @@ -7238,10 +7260,10 @@
isa = PBXGroup;
children = (
62E984A1DC4A18EBC5E68559 /* CourseListContainerViewFactory.swift */,
62E98AA14C7255A86152B53B /* ExploreBlockHeaderView.swift */,
62E9892AAAD4FAA927DCFC57 /* ExploreBlockPlaceholderView.swift */,
62E98664A22248D073D6BAE2 /* ExploreStoriesContainerView.swift */,
62E98101487588BB70A5C1A7 /* ExploreSearchBar.swift */,
62E98664A22248D073D6BAE2 /* ExploreStoriesContainerView.swift */,
2C73B0E625628FD300EA217D /* ExploreBlockHeaderView */,
);
path = View;
sourceTree = "<group>";
Expand Down Expand Up @@ -8901,6 +8923,7 @@
62E98573951C2334AD8C7A63 /* CourseInfoTabSyllabusOutputProtocol.swift in Sources */,
62E98FB9AFF029A44C3A1AAE /* CourseInfoTabSyllabusProvider.swift in Sources */,
62E9845D5434AFA93E756A34 /* SyllabusDownloadsService.swift in Sources */,
2C73B0EB25628FE600EA217D /* NewExploreBlockHeaderView.swift in Sources */,
2C2CBF08253EFC8800799344 /* TableQuizViewModel.swift in Sources */,
62E98085679CBCEB8A59042A /* SyllabusDownloadsServiceDelegate.swift in Sources */,
62E98A140CF77BBA4BD65407 /* CourseInfoTabSyllabusTableViewDataSource.swift in Sources */,
Expand All @@ -8926,6 +8949,7 @@
62E98DB7B229DDCA1A904C07 /* CourseListNetworkService.swift in Sources */,
62E98D98F89C2FFE4BF2884F /* CourseListPersistenceService.swift in Sources */,
62E986FC9E7027C70B69D572 /* CourseListPersistenceStorage.swift in Sources */,
2C73B0DF25628EF500EA217D /* NewExploreBlockContainerView.swift in Sources */,
62E9845BF91D84AC7ECF7B12 /* CourseListProvider.swift in Sources */,
2C73719224EBFF6C00ED24C3 /* FillBlanksTextCollectionViewCell.swift in Sources */,
62E9894FD7F3558CF9DAAD9A /* CourseListTypes.swift in Sources */,
Expand Down
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)
}
}
}
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)
}
}
}
}

0 comments on commit 0b8ba4f

Please sign in to comment.