Created
August 9, 2017 19:25
-
-
Save albaqawi/d2d6433dcbb5059edc4e967aea2d3622 to your computer and use it in GitHub Desktop.
to debug AppDetailController.swift
This file contains hidden or 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
| // | |
| // AppDetailController.swift | |
| // THOAGbusiness | |
| // | |
| // Created by ALBAQAWI on 8/7/17. | |
| // Copyright © 2017 THOAG. All rights reserved. | |
| // | |
| import Foundation | |
| import UIKit | |
| import SwiftyJSON | |
| import Alamofire | |
| class AppDetailController: UICollectionViewController, UICollectionViewDelegateFlowLayout { | |
| var app:App? { | |
| didSet{ | |
| // pay attention HERE we are inside the app decliartion within AppDetailController | |
| navigationItem.title = app?.name | |
| navigationItem.leftBarButtonItem?.title = "" | |
| if app?.screenshots != nil { | |
| return | |
| } | |
| if let id = app?.id { | |
| let urlString = "https://api.letsbuildthatapp.com/appstore/appdetail?id=\(id)" | |
| URLSession.shared.dataTask(with: URL(string: urlString)!, completionHandler: { (data, response, error) -> Void in | |
| if error != nil { | |
| print(error!) | |
| return | |
| } | |
| do { | |
| if data != nil { | |
| let jsonData = JSON(data: data!) | |
| print(jsonData) | |
| print("the jsonData results: \(jsonData["Id"].int!) - \(jsonData["Name"].string!)") | |
| let appDetails = App() | |
| if jsonData["Id"] != nil { | |
| appDetails.id = jsonData["Id"].int! | |
| } | |
| if jsonData["Name"] != nil { | |
| appDetails.name = jsonData["Name"].string | |
| } | |
| if jsonData["Category"] != nil { | |
| appDetails.category = jsonData["Category"].string | |
| } | |
| if jsonData["Price"] != nil { | |
| appDetails.price = jsonData["Price"].double | |
| } | |
| if jsonData["ImageName"] != nil { | |
| appDetails.imageName = jsonData["ImageName"].string | |
| } | |
| if let tempScreenshots = jsonData["Screenshots"].arrayObject as? [String] { | |
| // for screenShot in tempScreenshots { | |
| appDetails.screenshots = tempScreenshots | |
| //} | |
| } | |
| if jsonData["description"] != nil { | |
| appDetails.appDiscription = jsonData["description"].string | |
| } | |
| } | |
| self.app = appDetails | |
| DispatchQueue.global(qos: .background).async { | |
| // Background Thread, once all data and actions returned reload data | |
| self.collectionView?.reloadData() | |
| } | |
| } | |
| } catch let err { | |
| print(err) | |
| } | |
| }).resume() | |
| } | |
| } | |
| } | |
| private let headerId = "headerId" | |
| private let cellId = "cellId" | |
| private let descriptionCellId = "descriptionCellId" | |
| override func viewDidLoad() { | |
| super.viewDidLoad() | |
| // making scrolling up and down possible | |
| collectionView?.alwaysBounceVertical = true | |
| collectionView?.backgroundColor = UIColor.white | |
| //Registration section to allow the mapping of he headerId to the proper C.View. this is important for the override functions below | |
| collectionView?.register(AppDetailHeader.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: headerId) | |
| collectionView?.register(ScreenShotsCell.self, forCellWithReuseIdentifier: cellId) | |
| collectionView?.register(AppDetailDescriptionCell.self, forCellWithReuseIdentifier: descriptionCellId) | |
| } | |
| override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { | |
| if indexPath.item == 1 { | |
| let cell = collectionView.dequeueReusableCell(withReuseIdentifier: descriptionCellId, for: indexPath) as! AppDetailDescriptionCell | |
| cell.textView.attributedText = descriptionAttributedText() | |
| return cell | |
| } | |
| let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! ScreenShotsCell | |
| cell.app = app | |
| return cell | |
| } | |
| private func descriptionAttributedText() -> NSAttributedString { | |
| let attributedText = NSMutableAttributedString(string: "Description\n", attributes: [NSFontAttributeName: UIFont.systemFont(ofSize: 14)]) | |
| if let desc = app?.appDiscription { | |
| print(desc) | |
| //Mutable means you can modify it or mutate it! if we use wo mutable class we will only be able to read | |
| let style = NSMutableParagraphStyle() | |
| style.lineSpacing = 10 | |
| let range = NSMakeRange(0, attributedText.string.characters.count) | |
| attributedText.addAttribute(NSParagraphStyleAttributeName, value: style, range: range) | |
| attributedText.append(NSAttributedString(string: desc, attributes: [NSFontAttributeName: UIFont.systemFont(ofSize: 11), NSForegroundColorAttributeName: UIColor.darkGray])) | |
| } | |
| return attributedText | |
| } | |
| // THIS is first func in EP5 after ScreenSotsClass declaration, to set the sections | |
| override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { | |
| return 2 | |
| } | |
| func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { | |
| return CGSize(width: view.frame.height, height: 200) | |
| } | |
| override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { | |
| let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: headerId, for: indexPath) as! AppDetailHeader | |
| //here we are assigning the app retrived from main screen to the header and assigning it to the AppDetailHeader / app variable | |
| //as a results all components set are displayed clearly on header | |
| header.app = app | |
| return header | |
| } | |
| // we start setting sizes to see the items on the screen | |
| func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { | |
| return CGSize(width: view.frame.width, height: 170) | |
| } | |
| } | |
| class AppDetailDescriptionCell: BaseCell { | |
| let textView: UITextView = { | |
| let tv = UITextView() | |
| //tv.backgroundColor = UIColor.red | |
| tv.text = "SAMPLE DESCRIPTION" | |
| return tv | |
| }() | |
| let dividerLineView: UIView = { | |
| let view = UIView() | |
| view.backgroundColor = UIColor(white: 0.4, alpha: 0.4) | |
| return view | |
| }() | |
| override func setupViews() { | |
| super.setupViews() | |
| addSubview(textView) | |
| addSubview(dividerLineView) | |
| addConstraintsWithFormat("H:|-8-[v0]-8-|", views: textView) | |
| addConstraintsWithFormat("H:|-14-[v0]|", views: dividerLineView) | |
| addConstraintsWithFormat("V:|-4-[v0]-4-[v1(1)]|", views: textView, dividerLineView) | |
| // addSubview(dividerLineView) | |
| // addSubview(textView) | |
| // | |
| // addConstraintsWithFormat("H:|-8-[v0]-8-|", views: textView) | |
| // addConstraintsWithFormat("V:|-4-[v0]-4-|", views: textView) | |
| // //backgroundColor = UIColor.blue | |
| } | |
| } | |
| class AppDetailHeader: BaseCell { | |
| var app:App? { | |
| didSet{ | |
| //didSet will allow us to display the values to on the AppDetailsHeader from the passed on app! | |
| //we safely unwrap the values of a app cell incate no crashes | |
| if let imageName = app?.imageName{ | |
| imageView.image = UIImage(named: imageName) | |
| } | |
| if let name = app?.name{ | |
| nameLabel.text = name | |
| } | |
| if let price = app?.price { | |
| print(price) | |
| buyButton.setTitle("SR\(String(format:"%.2f",price))", for: .normal) | |
| } | |
| } | |
| } | |
| //set image placeholder | |
| let imageView: UIImageView = { | |
| let iv = UIImageView() | |
| iv.layer.cornerRadius = 16 | |
| iv.layer.masksToBounds = true | |
| iv.contentMode = .scaleAspectFill | |
| return iv | |
| }() | |
| //for the segmented controll | |
| let segmentedControl: UISegmentedControl = { | |
| let sc = UISegmentedControl(items: ["Details","Reviews","Related","Bids"]) | |
| sc.tintColor = UIColor.darkGray | |
| sc.selectedSegmentIndex = 0 | |
| return sc | |
| }() | |
| let buyButton: UIButton = { | |
| let button = UIButton(type: .system) | |
| button.setTitle("BUY", for: .normal) | |
| button.layer.borderColor = UIColor(colorLiteralRed: 0, green: 129/255, blue: 250/255, alpha: 1).cgColor | |
| button.layer.borderWidth = 1 | |
| button.layer.cornerRadius = 5 | |
| button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 14) | |
| return button | |
| }() | |
| let nameLabel: UILabel = { | |
| let label = UILabel() | |
| //this will be default if there is no name on app | |
| label.text = "App Name" | |
| label.font = UIFont.systemFont(ofSize: 16) | |
| return label | |
| }() | |
| let dividerLineView: UIView = { | |
| let view = UIView() | |
| view.backgroundColor = UIColor(white: 0.4, alpha: 0.4) | |
| return view | |
| }() | |
| override func setupViews(){ | |
| //setupViews of UICollectionViewController | |
| super.setupViews() | |
| //verify header is loaded on screen | |
| //backgroundColor = UIColor.blue | |
| addSubview(imageView) | |
| addSubview(segmentedControl) | |
| addSubview(nameLabel) | |
| addSubview(buyButton) | |
| addSubview(dividerLineView) | |
| //verify that imageview is loaded correctly | |
| //imageView.backgroundColor = UIColor.yellow | |
| imageView.translatesAutoresizingMaskIntoConstraints = false | |
| // very interesting to set up the label with image together | |
| addConstraintsWithFormat("H:|-14-[v0(100)]-8-[v1]|", views: imageView, nameLabel) | |
| addConstraintsWithFormat("V:|-14-[v0(100)]|", views: imageView) | |
| addConstraintsWithFormat("V:|-14-[v0(20)]|", views: nameLabel) | |
| addConstraintsWithFormat("H:|-14-[v0]-14-|", views: segmentedControl) | |
| addConstraintsWithFormat("V:[v0(34)]-8-|", views: segmentedControl) | |
| addConstraintsWithFormat("H:[v0(60)]-14-|", views: buyButton) | |
| addConstraintsWithFormat("V:[v0(32)]-56-|", views: buyButton) | |
| addConstraintsWithFormat("H:|[v0]|", views: dividerLineView) | |
| addConstraintsWithFormat("V:[v0(1)]|", views: dividerLineView) | |
| } | |
| } | |
| // helper function to void the long hand function call of addConstraints...... | |
| extension UIView { | |
| func addConstraintsWithFormat(_ format: String, views: UIView...) { | |
| var viewsDictionary = [String: UIView]() | |
| for (index, view) in views.enumerated() { | |
| let key = "v\(index)" | |
| viewsDictionary[key] = view | |
| view.translatesAutoresizingMaskIntoConstraints = false | |
| } | |
| addConstraints(NSLayoutConstraint.constraints(withVisualFormat: format, options: NSLayoutFormatOptions(), metrics: nil, views: viewsDictionary)) | |
| } | |
| } | |
| //this is the base cell that allows us to set the inits without repetition | |
| class BaseCell: UICollectionViewCell { | |
| override init(frame:CGRect) { | |
| super.init(frame: frame) | |
| setupViews() | |
| } | |
| required init?(coder aDecoder: NSCoder) { | |
| fatalError("init(decoder:) has not been implimented") | |
| } | |
| func setupViews() { | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment