Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //
- // AllCoursesViewController.swift
- // AeroBuddy
- //
- // Created by Luke Collister on 01/09/2019.
- // Copyright © 2019 Luke Collister. All rights reserved.
- //
- import UIKit
- import StoreKit
- class AllCoursesViewController: UITableViewController, SKProductsRequestDelegate, SKPaymentTransactionObserver, CourseCellDelegate {
- // MARK: - Variable Declarations
- var tempData = [Course]()
- var allCourses = [Course]()
- var ownedCourses = [Course]()
- var displayCourses = [Course]()
- var mycourse: Course!
- let workingDG = DispatchGroup()
- var productsSet = Set<String>()
- // MARK: - IAP Methods
- var product_identifier: String?
- func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
- let count: Int = response.products.count
- if (count > 0) {
- let validProduct: SKProduct = response.products[0] as SKProduct
- print(validProduct.localizedTitle)
- print(validProduct.localizedDescription)
- print(validProduct.price)
- buyProduct(product: validProduct)
- } else {
- print("nothing")
- }
- }
- func buyProduct(product: SKProduct) {
- print("Sending the Payment Request to Apple")
- let payment = SKPayment(product: product)
- SKPaymentQueue.default().add(payment)
- }
- func request(_ request: SKRequest, didFailWithError error: Error) {
- print("Error Fetching product information")
- }
- func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
- print("Received Payment Transaction Response from Apple")
- print("Transactions: ", transactions)
- for transaction: AnyObject in transactions {
- if let trans:SKPaymentTransaction = transaction as? SKPaymentTransaction {
- switch trans.transactionState {
- case .purchased:
- print("Product Purchased")
- SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
- // Handle the purchase
- UserDefaults.standard.set(true , forKey: "purchased")
- // Get the receipt if it's available
- if let appStoreReceiptURL = Bundle.main.appStoreReceiptURL, FileManager.default.fileExists(atPath: appStoreReceiptURL.path) {
- do {
- let receiptData = try Data(contentsOf: appStoreReceiptURL, options: .alwaysMapped)
- print("RECEIPT DATA: ", receiptData)
- let receiptString = receiptData.base64EncodedString(options: [])
- print("RECEIPT STRING: ", receiptString)
- // Read receiptData
- // Create POST request
- let url = URL(string: "http://fe01.kilosierracharlie.me/verifypayment")!
- var request = URLRequest(url: url)
- request.httpMethod = "POST"
- request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
- let parameters: [String: Any] = [
- "receipt": receiptString
- ]
- request.httpBody = parameters.percentEncoded()
- // Send the data
- print("Before URLSession")
- let task = URLSession.shared.dataTask(with: request) { data, response, error in
- guard let data = data, error == nil else {
- print(error?.localizedDescription ?? "No data")
- print("No data could be sent to the server. Please contact us.")
- return
- }
- let responseJSON = try? JSONSerialization.jsonObject(with: data, options: [])
- if let responseJSON = responseJSON as? [String: Any] {
- print(responseJSON)
- //TO DO: Refresh if error false, else throw error
- }
- print("DATA: ", data)
- }
- print("Here")
- task.resume()
- }
- catch {
- print("Couldn't read receipt data with error: " + error.localizedDescription)
- }
- }
- break;
- case .failed:
- print("Purchased Failed")
- SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
- break;
- case .restored:
- print("Already Purchased")
- SKPaymentQueue.default().restoreCompletedTransactions()
- // Handle the purchase
- UserDefaults.standard.set(true , forKey: "purchased")
- //adView.hidden = true
- break;
- default:
- print("In default")
- break;
- }
- }
- }
- }
- // MARK: - Default Methods
- override func viewDidLoad() {
- super.viewDidLoad()
- // Set Activity Indicator and show
- 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")!)
- view.addSubview(activityIndicator)
- activityIndicator.startAnimating()
- // Clear the arrays in case of refresh
- displayCourses.removeAll()
- ownedCourses.removeAll()
- allCourses.removeAll()
- self.tableView.reloadData()
- // Provide an empty backBarButton to hide the 'Back' text present by default in the back button.
- self.navigationItem.setHidesBackButton(true, animated:true)
- // Add a right navigation bar button to allow refreshing of JSON
- navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(systemName: "arrow.clockwise"), style: .plain, target: self, action: #selector(viewDidLoad))
- // IAP Code
- SKPaymentQueue.default().add(self)
- // Display the content
- DispatchQueue.global(qos: .background).async {
- self.workingDG.enter()
- self.getAllCourses(endpoint: "courses")
- self.workingDG.enter()
- self.getAllCourses(endpoint: "courses/my")
- self.workingDG.notify(queue: .main) {
- for i in 0 ..< self.ownedCourses.count {
- self.ownedCourses[i].owned = true
- }
- var idArray = [Int]()
- for course in self.ownedCourses {
- idArray.append(course.id)
- }
- for course in self.allCourses {
- course.owned = idArray.contains(course.id)
- self.displayCourses.append(course)
- }
- self.tableView.reloadData()
- // Stop the activity indicator
- DispatchQueue.main.async {
- activityIndicator.stopAnimating()
- }
- }
- }
- }
- // MARK: - JSON Methods
- func getAllCourses(endpoint: String) {
- let url = URL(string: "\(ServHandler.connectProtocol)://\(ServHandler.baseURL)/\(endpoint)")
- let task = URLSession.shared.dataTask(with: url!) {(data, response, error) in
- guard error == nil else {
- print("Error!")
- return
- }
- guard let content = data else {
- print("There is no data!")
- return
- }
- let decoder = JSONDecoder()
- do {
- for course in try decoder.decode([Course].self, from: content) {
- if (endpoint == "courses") {
- course.product_identifier = "com.aerobuddy.course.\(course.id)"
- self.allCourses.append(course)
- }
- else {
- self.ownedCourses.append(course)
- }
- }
- self.workingDG.leave()
- return
- }
- catch {
- print(error.localizedDescription)
- print(error)
- return
- }
- }
- task.resume()
- }
- // MARK: - UITableViewMethods
- override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
- return self.displayCourses.count
- }
- override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
- let cell = tableView.dequeueReusableCell(withIdentifier: "CourseCell", for: indexPath) as! CourseCell
- cell.course = displayCourses[indexPath.row]
- if (cell.course?.owned == false) {
- cell.backgroundColor = UIColor(red: 90/255, green: 90/255, blue: 90/255, alpha: 1)
- } else {
- //cell.backgroundColor = default
- }
- cell.delegate = self
- return cell
- }
- // When the cell is pressed
- override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
- // Determine which Course was selected
- let selectedCourse = displayCourses[indexPath.row]
- mycourse = selectedCourse
- print("Selected course: ", displayCourses[indexPath.row])
- // Load the subjects for this course
- performSegue(withIdentifier: "courseToSubjectSegue", sender: self)
- }
- func cellButtonTapped(cell: CourseCell) {
- // Trigger an alert to buy the course
- 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)
- // Add the course product identifier to the set
- let buttonPosition: CGPoint = cell.convert(CGPoint.zero, to: self.tableView)
- let indexPath = self.tableView.indexPathForRow(at: buttonPosition)
- productsSet.insert(displayCourses[indexPath!.row].product_identifier!)
- print("PRODUCTS SET: ", productsSet)
- // Yes option
- alert.addAction(UIAlertAction(title: "Yes", style: .default, handler: { action in
- // IAP Code Here
- if (SKPaymentQueue.canMakePayments())
- {
- let productsRequest: SKProductsRequest = SKProductsRequest(productIdentifiers: self.productsSet)
- productsRequest.delegate = self
- productsRequest.start()
- print("Fetching Products")
- } else {
- print("Can't make purchases")
- }
- }))
- // No option
- alert.addAction(UIAlertAction(title: "No", style: .cancel, handler: { action in
- self.productsSet.removeAll()
- }))
- self.present(alert, animated: true)
- print("The course with product identifier ", productsSet, " was selected!")
- }
- // MARK: - Segue Methods
- override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
- if segue.identifier == "courseToSubjectSegue" {
- if let destinationVC = segue.destination as? SubjectsViewController {
- destinationVC.courseVar = mycourse
- }
- }
- }
- }
- // MARK: - Extensions
- extension Dictionary {
- func percentEncoded() -> Data? {
- return map { key, value in
- let escapedKey = "\(key)".addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed) ?? ""
- let escapedValue = "\(value)".addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed) ?? ""
- print("In percentEncoded function")
- return escapedKey + "=" + escapedValue
- }
- .joined(separator: "&")
- .data(using: .utf8)
- }
- }
- extension CharacterSet {
- static let urlQueryValueAllowed: CharacterSet = {
- let generalDelimitersToEncode = ":#[]@" // does not include "?" or "/" due to RFC 3986 - Section 3.4
- let subDelimitersToEncode = "!$&'()*+,;="
- var allowed = CharacterSet.urlQueryAllowed
- allowed.remove(charactersIn: "\(generalDelimitersToEncode)\(subDelimitersToEncode)")
- print("In CharacterSet function")
- return allowed
- }()
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement