Advertisement
lcolli98

AllCoursesViewController

Mar 7th, 2020
581
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Swift 12.95 KB | None | 0 0
  1. //
  2. //  AllCoursesViewController.swift
  3. //  AeroBuddy
  4. //
  5. //  Created by Luke Collister on 01/09/2019.
  6. //  Copyright © 2019 Luke Collister. All rights reserved.
  7. //
  8.  
  9. import UIKit
  10. import StoreKit
  11.  
  12. class AllCoursesViewController: UITableViewController, SKProductsRequestDelegate, SKPaymentTransactionObserver, CourseCellDelegate {
  13.  
  14.     // MARK: - Variable Declarations
  15.     var tempData = [Course]()
  16.  
  17.     var allCourses = [Course]()
  18.     var ownedCourses = [Course]()
  19.     var displayCourses = [Course]()
  20.     var mycourse: Course!
  21.    
  22.     let workingDG = DispatchGroup()
  23.    
  24.     var productsSet = Set<String>()
  25.  
  26.    
  27.     // MARK: - IAP Methods
  28.     var product_identifier: String?
  29.    
  30.     func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
  31.         let count: Int = response.products.count
  32.         if (count > 0) {
  33.             let validProduct: SKProduct = response.products[0] as SKProduct
  34.             print(validProduct.localizedTitle)
  35.             print(validProduct.localizedDescription)
  36.             print(validProduct.price)
  37.             buyProduct(product: validProduct)
  38.         } else {
  39.             print("nothing")
  40.         }
  41.     }
  42.    
  43.     func buyProduct(product: SKProduct) {
  44.         print("Sending the Payment Request to Apple")
  45.         let payment = SKPayment(product: product)
  46.         SKPaymentQueue.default().add(payment)
  47.     }
  48.  
  49.     func request(_ request: SKRequest, didFailWithError error: Error) {
  50.         print("Error Fetching product information")
  51.     }
  52.  
  53.     func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
  54.         print("Received Payment Transaction Response from Apple")
  55.        
  56.         print("Transactions: ", transactions)
  57.  
  58.         for transaction: AnyObject in transactions {
  59.             if let trans:SKPaymentTransaction = transaction as? SKPaymentTransaction {
  60.                 switch trans.transactionState {
  61.                 case .purchased:
  62.                     print("Product Purchased")
  63.                     SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
  64.                     // Handle the purchase
  65.                     UserDefaults.standard.set(true , forKey: "purchased")
  66.                     // Get the receipt if it's available
  67.                     if let appStoreReceiptURL = Bundle.main.appStoreReceiptURL, FileManager.default.fileExists(atPath: appStoreReceiptURL.path) {
  68.  
  69.                         do {
  70.                             let receiptData = try Data(contentsOf: appStoreReceiptURL, options: .alwaysMapped)
  71.                             print("RECEIPT DATA: ", receiptData)
  72.  
  73.                             let receiptString = receiptData.base64EncodedString(options: [])
  74.                             print("RECEIPT STRING: ", receiptString)
  75.  
  76.                             // Read receiptData
  77.                             // Create POST request
  78.                             let url = URL(string: "http://fe01.kilosierracharlie.me/verifypayment")!
  79.                             var request = URLRequest(url: url)
  80.                             request.httpMethod = "POST"
  81.                             request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
  82.                             let parameters: [String: Any] = [
  83.                                 "receipt": receiptString
  84.                             ]
  85.                             request.httpBody = parameters.percentEncoded()
  86.  
  87.                             // Send the data
  88.                             print("Before URLSession")
  89.                             let task = URLSession.shared.dataTask(with: request) { data, response, error in
  90.                                 guard let data = data, error == nil else {
  91.                                     print(error?.localizedDescription ?? "No data")
  92.                                     print("No data could be sent to the server. Please contact us.")
  93.                                     return
  94.                                 }
  95.                                 let responseJSON = try? JSONSerialization.jsonObject(with: data, options: [])
  96.                                 if let responseJSON = responseJSON as? [String: Any] {
  97.                                     print(responseJSON)
  98.                                     //TO DO: Refresh if error false, else throw error
  99.                                 }
  100.                                 print("DATA: ", data)
  101.                             }
  102.                             print("Here")
  103.                             task.resume()
  104.                         }
  105.                         catch {
  106.                             print("Couldn't read receipt data with error: " + error.localizedDescription)
  107.                         }
  108.                     }
  109.                     break;
  110.                    
  111.                 case .failed:
  112.                     print("Purchased Failed")
  113.                     SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
  114.                     break;
  115.  
  116.                 case .restored:
  117.                     print("Already Purchased")
  118.                     SKPaymentQueue.default().restoreCompletedTransactions()
  119.  
  120.                     // Handle the purchase
  121.                     UserDefaults.standard.set(true , forKey: "purchased")
  122.                     //adView.hidden = true
  123.                     break;
  124.                 default:
  125.                     print("In default")
  126.                     break;
  127.                 }
  128.             }
  129.         }
  130.     }
  131.    
  132.    
  133.    
  134.     // MARK: - Default Methods
  135.     override func viewDidLoad() {
  136.         super.viewDidLoad()
  137.        
  138.         // Set Activity Indicator and show
  139.         let activityIndicator = MyIndicator(frame: CGRect(x: UIScreen.main.bounds.size.width/2 - 75, y: UIScreen.main.bounds.size.height/2 - 150, width: 150, height: 150), image: UIImage(named: "LOADING.png")!)
  140.         view.addSubview(activityIndicator)
  141.         activityIndicator.startAnimating()
  142.        
  143.         // Clear the arrays in case of refresh
  144.         displayCourses.removeAll()
  145.         ownedCourses.removeAll()
  146.         allCourses.removeAll()
  147.         self.tableView.reloadData()
  148.        
  149.         // Provide an empty backBarButton to hide the 'Back' text present by default in the back button.
  150.         self.navigationItem.setHidesBackButton(true, animated:true)
  151.        
  152.         // Add a right navigation bar button to allow refreshing of JSON
  153.         navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(systemName: "arrow.clockwise"), style: .plain, target: self, action: #selector(viewDidLoad))
  154.        
  155.         // IAP Code
  156.         SKPaymentQueue.default().add(self)
  157.            
  158.         // Display the content
  159.         DispatchQueue.global(qos: .background).async {
  160.             self.workingDG.enter()
  161.             self.getAllCourses(endpoint: "courses")
  162.             self.workingDG.enter()
  163.             self.getAllCourses(endpoint: "courses/my")
  164.            
  165.             self.workingDG.notify(queue: .main) {
  166.                 for i in 0 ..< self.ownedCourses.count {
  167.                     self.ownedCourses[i].owned = true
  168.                 }
  169.  
  170.                 var idArray = [Int]()
  171.                 for course in self.ownedCourses {
  172.                     idArray.append(course.id)
  173.                 }
  174.                 for course in self.allCourses {
  175.                     course.owned = idArray.contains(course.id)
  176.                     self.displayCourses.append(course)
  177.                 }
  178.                 self.tableView.reloadData()
  179.  
  180.                 // Stop the activity indicator
  181.                 DispatchQueue.main.async {
  182.                     activityIndicator.stopAnimating()
  183.                 }
  184.             }
  185.         }
  186.     }
  187.  
  188.    
  189.     // MARK: - JSON Methods
  190.     func getAllCourses(endpoint: String) {
  191.         let url = URL(string: "\(ServHandler.connectProtocol)://\(ServHandler.baseURL)/\(endpoint)")
  192.         let task = URLSession.shared.dataTask(with: url!) {(data, response, error) in
  193.             guard error == nil else {
  194.                 print("Error!")
  195.                 return
  196.             }
  197.             guard let content = data else {
  198.                 print("There is no data!")
  199.                 return
  200.             }
  201.  
  202.             let decoder = JSONDecoder()
  203.             do {
  204.                 for course in try decoder.decode([Course].self, from: content) {
  205.                     if (endpoint == "courses") {
  206.                         course.product_identifier = "com.aerobuddy.course.\(course.id)"
  207.                         self.allCourses.append(course)
  208.                     }
  209.                     else {
  210.                         self.ownedCourses.append(course)
  211.                     }
  212.                 }
  213.                 self.workingDG.leave()
  214.                 return
  215.             }
  216.             catch {
  217.                 print(error.localizedDescription)
  218.                 print(error)
  219.                 return
  220.             }
  221.         }
  222.         task.resume()
  223.     }
  224.  
  225.    
  226.     // MARK: - UITableViewMethods
  227.     override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
  228.         return self.displayCourses.count
  229.     }
  230.    
  231.    
  232.     override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
  233.         let cell = tableView.dequeueReusableCell(withIdentifier: "CourseCell", for: indexPath) as! CourseCell
  234.         cell.course = displayCourses[indexPath.row]
  235.         if (cell.course?.owned == false) {
  236.             cell.backgroundColor = UIColor(red: 90/255, green: 90/255, blue: 90/255, alpha: 1)
  237.         } else {
  238.             //cell.backgroundColor = default
  239.         }
  240.         cell.delegate = self
  241.         return cell
  242.     }
  243.  
  244.  
  245.     // When the cell is pressed
  246.     override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
  247.         // Determine which Course was selected
  248.         let selectedCourse = displayCourses[indexPath.row]
  249.         mycourse = selectedCourse
  250.         print("Selected course: ", displayCourses[indexPath.row])
  251.        
  252.         // Load the subjects for this course
  253.         performSegue(withIdentifier: "courseToSubjectSegue", sender: self)
  254.     }
  255.    
  256.    
  257.     func cellButtonTapped(cell: CourseCell) {
  258.         // Trigger an alert to buy the course
  259.         let alert = UIAlertController(title: "Purchase Course?", message: "You do not own this course. Do you wish to purchase it? Pressing \"Yes\" will purchase *all* subjects and topics within the course.", preferredStyle: .alert)
  260.  
  261.         // Add the course product identifier to the set
  262.         let buttonPosition: CGPoint = cell.convert(CGPoint.zero, to: self.tableView)
  263.         let indexPath = self.tableView.indexPathForRow(at: buttonPosition)
  264.         productsSet.insert(displayCourses[indexPath!.row].product_identifier!)
  265.         print("PRODUCTS SET: ", productsSet)
  266.  
  267.         // Yes option
  268.         alert.addAction(UIAlertAction(title: "Yes", style: .default, handler: { action in
  269.            // IAP Code Here
  270.            if (SKPaymentQueue.canMakePayments())
  271.            {
  272.                let productsRequest: SKProductsRequest = SKProductsRequest(productIdentifiers: self.productsSet)
  273.                productsRequest.delegate = self
  274.                productsRequest.start()
  275.                print("Fetching Products")
  276.            } else {
  277.                print("Can't make purchases")
  278.            }
  279.         }))
  280.         // No option
  281.         alert.addAction(UIAlertAction(title: "No", style: .cancel, handler: { action in
  282.             self.productsSet.removeAll()
  283.         }))
  284.  
  285.         self.present(alert, animated: true)
  286.         print("The course with product identifier ", productsSet, " was selected!")
  287.     }
  288.    
  289.    
  290.     // MARK: - Segue Methods
  291.     override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
  292.         if segue.identifier == "courseToSubjectSegue" {
  293.             if let destinationVC = segue.destination as? SubjectsViewController {
  294.                 destinationVC.courseVar = mycourse
  295.             }
  296.         }
  297.     }
  298. }
  299.  
  300.  
  301. // MARK: - Extensions
  302. extension Dictionary {
  303.     func percentEncoded() -> Data? {
  304.         return map { key, value in
  305.             let escapedKey = "\(key)".addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed) ?? ""
  306.             let escapedValue = "\(value)".addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed) ?? ""
  307.             print("In percentEncoded function")
  308.             return escapedKey + "=" + escapedValue
  309.         }
  310.         .joined(separator: "&")
  311.         .data(using: .utf8)
  312.     }
  313. }
  314.  
  315. extension CharacterSet {
  316.     static let urlQueryValueAllowed: CharacterSet = {
  317.         let generalDelimitersToEncode = ":#[]@" // does not include "?" or "/" due to RFC 3986 - Section 3.4
  318.         let subDelimitersToEncode = "!$&'()*+,;="
  319.  
  320.         var allowed = CharacterSet.urlQueryAllowed
  321.         allowed.remove(charactersIn: "\(generalDelimitersToEncode)\(subDelimitersToEncode)")
  322.         print("In CharacterSet function")
  323.         return allowed
  324.     }()
  325. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement