Skip to content

Instantly share code, notes, and snippets.

@albaqawi
Created August 9, 2017 19:25
Show Gist options
  • Select an option

  • Save albaqawi/d2d6433dcbb5059edc4e967aea2d3622 to your computer and use it in GitHub Desktop.

Select an option

Save albaqawi/d2d6433dcbb5059edc4e967aea2d3622 to your computer and use it in GitHub Desktop.
to debug AppDetailController.swift
//
// 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