diff --git a/AppStoreClone.xcodeproj/project.pbxproj b/AppStoreClone.xcodeproj/project.pbxproj index dd2bb76..54f7e65 100644 --- a/AppStoreClone.xcodeproj/project.pbxproj +++ b/AppStoreClone.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + DE61C2401F8E060F00AE564C /* UILabel+FontLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE61C23F1F8E060F00AE564C /* UILabel+FontLayout.swift */; }; F68726328846CEED2119C295 /* Pods_AppStoreClone.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF0671D9ED588DEDA4879E66 /* Pods_AppStoreClone.framework */; }; F70D31EA1EF5EE4400DC3326 /* GradientView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70D31E91EF5EE4400DC3326 /* GradientView.swift */; }; F70D31ED1EF6090400DC3326 /* WorldPremiereCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70D31EB1EF6090400DC3326 /* WorldPremiereCell.swift */; }; @@ -39,6 +40,7 @@ 7969423CEC4E6739F6E8EED0 /* Pods-AppStoreClone.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AppStoreClone.debug.xcconfig"; path = "Pods/Target Support Files/Pods-AppStoreClone/Pods-AppStoreClone.debug.xcconfig"; sourceTree = ""; }; BD89E3096EF2B1D912C836DA /* Pods-AppStoreClone.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AppStoreClone.release.xcconfig"; path = "Pods/Target Support Files/Pods-AppStoreClone/Pods-AppStoreClone.release.xcconfig"; sourceTree = ""; }; BF0671D9ED588DEDA4879E66 /* Pods_AppStoreClone.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_AppStoreClone.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + DE61C23F1F8E060F00AE564C /* UILabel+FontLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UILabel+FontLayout.swift"; sourceTree = ""; }; F70D31E91EF5EE4400DC3326 /* GradientView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GradientView.swift; sourceTree = ""; }; F70D31EB1EF6090400DC3326 /* WorldPremiereCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WorldPremiereCell.swift; path = CollectionViewCells/WorldPremiereCell.swift; sourceTree = ""; }; F70D31EC1EF6090400DC3326 /* WorldPremiereCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = WorldPremiereCell.xib; path = CollectionViewCells/WorldPremiereCell.xib; sourceTree = ""; }; @@ -176,6 +178,7 @@ F7F0F1661EF5EB3900D73E20 /* UIView+Constraints.swift */, F70D31F21EF60B5700DC3326 /* Reusable.swift */, F70D31F01EF60B3100DC3326 /* UICollectionView+Reusable.swift */, + DE61C23F1F8E060F00AE564C /* UILabel+FontLayout.swift */, ); name = Utility; sourceTree = ""; @@ -324,6 +327,7 @@ F70D32031EF62E3D00DC3326 /* AppOfTheDayCell.swift in Sources */, F7F0F14F1EF5EA1C00D73E20 /* AppDelegate.swift in Sources */, F7C44AA61EF70CF700E8E658 /* StoryDetailViewController.swift in Sources */, + DE61C2401F8E060F00AE564C /* UILabel+FontLayout.swift in Sources */, F70D320B1EF6532300DC3326 /* PresentStoryViewAnimationController.swift in Sources */, F7F0F1631EF5EAEF00D73E20 /* BaseView.swift in Sources */, ); diff --git a/AppStoreClone/Base.lproj/Main.storyboard b/AppStoreClone/Base.lproj/Main.storyboard index 2194a0a..211e285 100644 --- a/AppStoreClone/Base.lproj/Main.storyboard +++ b/AppStoreClone/Base.lproj/Main.storyboard @@ -1,11 +1,11 @@ - + - + @@ -75,23 +75,36 @@ - + - + - + @@ -130,7 +157,7 @@ - + diff --git a/AppStoreClone/CollectionViewCells/AppOfTheDayCell.swift b/AppStoreClone/CollectionViewCells/AppOfTheDayCell.swift index 8b3754c..361962b 100644 --- a/AppStoreClone/CollectionViewCells/AppOfTheDayCell.swift +++ b/AppStoreClone/CollectionViewCells/AppOfTheDayCell.swift @@ -15,8 +15,12 @@ internal class AppOfTheDayCell: BaseRoundedCardCell { @IBOutlet private weak var imageView: UIImageView! @IBOutlet private weak var iconImageView: UIImageView! + @IBOutlet weak var titleLabel: InsetLabel! + @IBOutlet weak var appNameLabel: UILabel! + @IBOutlet weak var appSummaryLabel: UILabel! @IBOutlet private weak var getButtonView: UIView! + @IBOutlet weak var buttonLabel: UILabel! // MARK: - Factory Method @@ -31,8 +35,11 @@ internal class AppOfTheDayCell: BaseRoundedCardCell { super.awakeFromNib() imageView.layer.cornerRadius = 14.0 - iconImageView.layer.cornerRadius = 14.0 + iconImageView.layer.cornerRadius = 19.0 getButtonView.layer.cornerRadius = getButtonView.bounds.height/2 + titleLabel.attributedText = NSMutableAttributedString(string: "APP\nOF THE\nDAY") + titleLabel.setLineHeight(lineHeight: 44.0, lineSpacing: 0.0) + titleLabel.font = UIFont.systemFont(ofSize: 55.0, weight: UIFontWeightHeavy) } } diff --git a/AppStoreClone/CollectionViewCells/AppOfTheDayCell.xib b/AppStoreClone/CollectionViewCells/AppOfTheDayCell.xib index 21b7ee3..d3bf7b5 100644 --- a/AppStoreClone/CollectionViewCells/AppOfTheDayCell.xib +++ b/AppStoreClone/CollectionViewCells/AppOfTheDayCell.xib @@ -1,109 +1,142 @@ - + - + - + - + - + - + - - + - - + + + - + + + + - - + + + + - - - - + - + + + + - - - - - + + - + + + + + - + diff --git a/AppStoreClone/CollectionViewCells/BaseRoundedCardCell.swift b/AppStoreClone/CollectionViewCells/BaseRoundedCardCell.swift index 6c465a4..63081a8 100644 --- a/AppStoreClone/CollectionViewCells/BaseRoundedCardCell.swift +++ b/AppStoreClone/CollectionViewCells/BaseRoundedCardCell.swift @@ -11,7 +11,7 @@ import CoreMotion internal class BaseRoundedCardCell: UICollectionViewCell { - internal static let cellHeight: CGFloat = 470.0 + internal static let cellHeight: CGFloat = 413.0 private static let kInnerMargin: CGFloat = 20.0 @@ -68,10 +68,10 @@ internal class BaseRoundedCardCell: UICollectionViewCell { if let shadowView = shadowView { let shadowPath = UIBezierPath(roundedRect: shadowView.bounds, cornerRadius: 14.0) shadowView.layer.masksToBounds = false - shadowView.layer.shadowRadius = 8.0 + shadowView.layer.shadowRadius = 14.0 shadowView.layer.shadowColor = UIColor.black.cgColor shadowView.layer.shadowOffset = CGSize(width: width, height: height) - shadowView.layer.shadowOpacity = 0.35 + shadowView.layer.shadowOpacity = 0.22 shadowView.layer.shadowPath = shadowPath.cgPath } } @@ -81,7 +81,7 @@ internal class BaseRoundedCardCell: UICollectionViewCell { private func configureGestureRecognizer() { // Long Press Gesture Recognizer longPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPressGesture(gestureRecognizer:))) - longPressGestureRecognizer?.minimumPressDuration = 0.1 + longPressGestureRecognizer?.minimumPressDuration = 0.2 addGestureRecognizer(longPressGestureRecognizer!) } diff --git a/AppStoreClone/CollectionViewCells/WorldPremiereCell.swift b/AppStoreClone/CollectionViewCells/WorldPremiereCell.swift index 9a1d09c..b6372e0 100644 --- a/AppStoreClone/CollectionViewCells/WorldPremiereCell.swift +++ b/AppStoreClone/CollectionViewCells/WorldPremiereCell.swift @@ -13,6 +13,9 @@ internal class WorldPremiereCell: BaseRoundedCardCell { /// Image View @IBOutlet private weak var imageView: UIImageView! + @IBOutlet weak var typeLabel: UILabel! + @IBOutlet weak var titleLabel: UILabel! + @IBOutlet weak var summaryLabel: UILabel! // MARK: - Factory Method @@ -27,6 +30,8 @@ internal class WorldPremiereCell: BaseRoundedCardCell { super.awakeFromNib() imageView.layer.cornerRadius = 14.0 + titleLabel.attributedText = NSMutableAttributedString(string: "The Art of\nthe Impossible") + titleLabel.font = UIFont.systemFont(ofSize: 28.0, weight: UIFontWeightSemibold) } } diff --git a/AppStoreClone/CollectionViewCells/WorldPremiereCell.xib b/AppStoreClone/CollectionViewCells/WorldPremiereCell.xib index 5777c29..ae8681c 100644 --- a/AppStoreClone/CollectionViewCells/WorldPremiereCell.xib +++ b/AppStoreClone/CollectionViewCells/WorldPremiereCell.xib @@ -1,11 +1,11 @@ - + - + @@ -23,22 +23,55 @@ - + @@ -46,7 +79,7 @@ - + @@ -56,11 +89,14 @@ - + + + + diff --git a/AppStoreClone/DismissStoryViewAnimationController.swift b/AppStoreClone/DismissStoryViewAnimationController.swift index 9044f68..e81f5c0 100644 --- a/AppStoreClone/DismissStoryViewAnimationController.swift +++ b/AppStoreClone/DismissStoryViewAnimationController.swift @@ -33,7 +33,7 @@ internal class DismissStoryViewAnimationController: NSObject, UIViewControllerAn UIView.animate(withDuration: duration, animations: { fromViewController.positionContainer(left: 20.0, right: 20.0, - top: self.selectedCardFrame.origin.y + 20.0, + top: toViewController.collectionView.convert(self.selectedCardFrame, to: toViewController.collectionView.superview).origin.y + 20.0, bottom: 0.0) fromViewController.setHeaderHeight(self.selectedCardFrame.size.height - 40.0) fromViewController.configureRoundedCorners(shouldRound: true) diff --git a/AppStoreClone/PresentStoryViewAnimationController.swift b/AppStoreClone/PresentStoryViewAnimationController.swift index 00eed9b..b84bca4 100644 --- a/AppStoreClone/PresentStoryViewAnimationController.swift +++ b/AppStoreClone/PresentStoryViewAnimationController.swift @@ -26,7 +26,7 @@ internal class PresentStoryViewAnimationController: NSObject, UIViewControllerAn containerView.addSubview(toViewController.view) toViewController.positionContainer(left: 20.0, right: 20.0, - top: selectedCardFrame.origin.y + 20.0, + top: fromViewController.collectionView.convert(selectedCardFrame, to: fromViewController.collectionView.superview).origin.y + 20.0, bottom: 0.0) toViewController.setHeaderHeight(self.selectedCardFrame.size.height - 40.0) toViewController.configureRoundedCorners(shouldRound: true) diff --git a/AppStoreClone/UILabel+FontLayout.swift b/AppStoreClone/UILabel+FontLayout.swift new file mode 100644 index 0000000..aae919b --- /dev/null +++ b/AppStoreClone/UILabel+FontLayout.swift @@ -0,0 +1,110 @@ +// +// UILabel+FontLayout.swift +// AppStoreClone +// +// Created by Yannis De Cleene on 10/10/17. +// Copyright © 2017 Phill Farrugia. All rights reserved. +// + +import UIKit + +@IBDesignable +extension UILabel { + @IBInspectable + public var kerning:CGFloat { + set{ + if let currentAttibutedText = self.attributedText { + let attribString = NSMutableAttributedString(attributedString: currentAttibutedText) + attribString.addAttributes([NSKernAttributeName:newValue], range:NSMakeRange(0, currentAttibutedText.length)) + self.attributedText = attribString + } + } get { + var kerning:CGFloat = 0 + if let attributedText = self.attributedText { + attributedText.enumerateAttribute(NSKernAttributeName, + in: NSMakeRange(0, attributedText.length), + options: .init(rawValue: 0)) { (value, range, stop) in + kerning = value as? CGFloat ?? 0 + } + } + return kerning + } + } + + @IBInspectable + public var lineHeight:CGFloat { + set{ + if let currentAttibutedText = self.attributedText { + let attribString = NSMutableAttributedString(attributedString: currentAttibutedText) + let style = NSMutableParagraphStyle() + + style.lineSpacing = lineHeight + attribString.addAttributes([NSParagraphStyleAttributeName:style], range:NSMakeRange(0, currentAttibutedText.length)) + self.attributedText = attribString + } + } get { + var lineHeight:CGFloat = 0 + if let attributedText = self.attributedText { + attributedText.enumerateAttribute(NSParagraphStyleAttributeName, + in: NSMakeRange(0, attributedText.length), + options: .init(rawValue: 0)) { (value, range, stop) in + lineHeight = value as? CGFloat ?? 0 + } + } + return lineHeight + } + } + + func setLineHeight(lineHeight: CGFloat, lineSpacing: CGFloat) { + let text = self.text + if let text = text { + let attributeString = NSMutableAttributedString(string: text) + let style = NSMutableParagraphStyle() + + style.maximumLineHeight = lineHeight + style.lineSpacing = lineSpacing + attributeString.addAttribute(NSParagraphStyleAttributeName, value: style, range: NSMakeRange(0, text.count)) + self.attributedText = attributeString + } + } +} + +@IBDesignable class InsetLabel: UILabel { + @IBInspectable var topInset: CGFloat = 0.0 + @IBInspectable var leftInset: CGFloat = 0.0 + @IBInspectable var bottomInset: CGFloat = 0.0 + @IBInspectable var rightInset: CGFloat = 0.0 + + var insets: UIEdgeInsets { + get { + return UIEdgeInsetsMake(topInset, leftInset, bottomInset, rightInset) + } + set { + topInset = newValue.top + leftInset = newValue.left + bottomInset = newValue.bottom + rightInset = newValue.right + } + } + + override func drawText(in rect: CGRect) { + super.drawText(in: UIEdgeInsetsInsetRect(rect, insets)) + } + + override func sizeThatFits(_ size: CGSize) -> CGSize { + var adjSize = super.sizeThatFits(size) + adjSize.width += leftInset + rightInset + adjSize.height += topInset + bottomInset + + return adjSize + } + + override var intrinsicContentSize: CGSize { + var contentSize = super.intrinsicContentSize + contentSize.width += leftInset + rightInset + contentSize.height += topInset + bottomInset + + return contentSize + } +} +