From ec6e12d2ebaac69a273387820287b3ba90741e07 Mon Sep 17 00:00:00 2001 From: Andrew McKnight Date: Thu, 17 Jul 2025 11:36:10 -0800 Subject: [PATCH 1/3] wip refactoring to extract database code --- EmpowerPlant.xcodeproj/project.pbxproj | 4 + .../xcschemes/EmpowerPlant.xcscheme | 5 + EmpowerPlant/AppDelegate.swift | 51 ------- EmpowerPlant/CoreDataController.swift | 129 ++++++++++++++++++ EmpowerPlant/EmpowerPlantViewController.swift | 118 ++-------------- EmpowerPlant/SceneDelegate.swift | 35 ----- EmpowerPlant/Utils.swift | 2 +- 7 files changed, 151 insertions(+), 193 deletions(-) create mode 100644 EmpowerPlant/CoreDataController.swift diff --git a/EmpowerPlant.xcodeproj/project.pbxproj b/EmpowerPlant.xcodeproj/project.pbxproj index c4fa347..e9275be 100644 --- a/EmpowerPlant.xcodeproj/project.pbxproj +++ b/EmpowerPlant.xcodeproj/project.pbxproj @@ -10,6 +10,7 @@ 843BD60F2AD08CE900B0098F /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843BD60E2AD08CE900B0098F /* Utils.swift */; }; 843BD6272AD7798C00B0098F /* jwt-deep-field.png in Resources */ = {isa = PBXBuildFile; fileRef = 843BD6262AD7798C00B0098F /* jwt-deep-field.png */; }; 846BEA1C2ABE611A0032F77F /* mobydick.txt in Resources */ = {isa = PBXBuildFile; fileRef = 846BEA1B2ABE611A0032F77F /* mobydick.txt */; }; + 846D3F642E297C3E00D4E7E3 /* CoreDataController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846D3F632E297C3E00D4E7E3 /* CoreDataController.swift */; }; 848716A32AD8C3CD00756467 /* BigInt in Frameworks */ = {isa = PBXBuildFile; productRef = 848716A22AD8C3CD00756467 /* BigInt */; }; 848716B72ADFAA2000756467 /* Sentry in Frameworks */ = {isa = PBXBuildFile; productRef = 848716B62ADFAA2000756467 /* Sentry */; }; 8B21663C29D3F8C80009C890 /* RandomErrors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B21663B29D3F8C80009C890 /* RandomErrors.swift */; }; @@ -44,6 +45,7 @@ 843BD6262AD7798C00B0098F /* jwt-deep-field.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "jwt-deep-field.png"; sourceTree = ""; }; 846BEA1A2ABE46880032F77F /* upload-symbols.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "upload-symbols.sh"; sourceTree = ""; }; 846BEA1B2ABE611A0032F77F /* mobydick.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = mobydick.txt; sourceTree = ""; }; + 846D3F632E297C3E00D4E7E3 /* CoreDataController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreDataController.swift; sourceTree = ""; }; 8474F0482ACCE2D800F21E06 /* deploy_project.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = deploy_project.sh; sourceTree = ""; }; 8474F04D2ACE54F300F21E06 /* .github */ = {isa = PBXFileReference; lastKnownFileType = folder; path = .github; sourceTree = ""; }; 848A45262BBFC79E006AAAEC /* .codecov.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = .codecov.yml; sourceTree = ""; }; @@ -130,6 +132,7 @@ 843BD60E2AD08CE900B0098F /* Utils.swift */, D15FCDA727E00F0D00258BF3 /* Model.xcdatamodeld */, D17C73CB27D82EB8006650AF /* EmpowerPlantViewController.swift */, + 846D3F632E297C3E00D4E7E3 /* CoreDataController.swift */, 846BEA1B2ABE611A0032F77F /* mobydick.txt */, D19EBE6E2805ED52007022DC /* ShoppingCart.swift */, D17C73CE27D82ED1006650AF /* CartViewController.swift */, @@ -285,6 +288,7 @@ files = ( D17C73CC27D82EB8006650AF /* EmpowerPlantViewController.swift in Sources */, D17C73D227D83321006650AF /* ListAppViewController.swift in Sources */, + 846D3F642E297C3E00D4E7E3 /* CoreDataController.swift in Sources */, D15EDF14282BF80400FC13D6 /* Product+CoreDataClass.swift in Sources */, D15FCDA927E00F0D00258BF3 /* Model.xcdatamodeld in Sources */, D17C73CF27D82ED1006650AF /* CartViewController.swift in Sources */, diff --git a/EmpowerPlant.xcodeproj/xcshareddata/xcschemes/EmpowerPlant.xcscheme b/EmpowerPlant.xcodeproj/xcshareddata/xcschemes/EmpowerPlant.xcscheme index 4ba5417..03bb956 100644 --- a/EmpowerPlant.xcodeproj/xcshareddata/xcschemes/EmpowerPlant.xcscheme +++ b/EmpowerPlant.xcodeproj/xcshareddata/xcschemes/EmpowerPlant.xcscheme @@ -91,6 +91,11 @@ value = "$(USER)" isEnabled = "YES"> + + Bool { // the Sentry default is to enable swizzling. we'll use that as our default as well. we check for the launch arg to disable swizzling; if it's provided, then we'll disable swizzling. if it's absent, then swizzling will be enabled. @@ -65,53 +62,5 @@ class AppDelegate: UIResponder, UIApplicationDelegate { // Use this method to select a configuration to create the new scene with. return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) } - - func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { - // Called when the user discards a scene session. - // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. - // Use this method to release any resources that were specific to the discarded scenes, as they will not return. - } - - lazy var persistentContainer: NSPersistentContainer = { - /* - The persistent container for the application. This implementation - creates and returns a container, having loaded the store for the - application to it. This property is optional since there are legitimate - error conditions that could cause the creation of the store to fail. - */ - let container = NSPersistentContainer(name: "Model") - container.loadPersistentStores(completionHandler: { (storeDescription, error) in - if let error = error as NSError? { - // Replace this implementation with code to handle the error appropriately. - // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. - - /* - Typical reasons for an error here include: - * The parent directory does not exist, cannot be created, or disallows writing. - * The persistent store is not accessible, due to permissions or data protection when the device is locked. - * The device is out of space. - * The store could not be migrated to the current model version. - Check the error message to determine what the actual problem was. - */ - fatalError("Unresolved error \(error), \(error.userInfo)") - } - }) - return container - }() - - // MARK: - Core Data Saving support - - func saveContext () { - let context = persistentContainer.viewContext - if context.hasChanges { - do { - try context.save() - } catch { - // TODO: error - } - } - } - - } diff --git a/EmpowerPlant/CoreDataController.swift b/EmpowerPlant/CoreDataController.swift new file mode 100644 index 0000000..0a87c17 --- /dev/null +++ b/EmpowerPlant/CoreDataController.swift @@ -0,0 +1,129 @@ +// +// CoreDataController.swift +// EmpowerPlant +// +// Created by Andrew McKnight on 7/17/25. +// + +import Foundation +import CoreData + +struct ProductMap: Decodable { + let id: Int + let title: String + let description: String + let descriptionfull: String + let img: String + let imgcropped: String + let price: Int + // reviews: [{id: 4, productid: 4, rating: 4, customerid: null, description: null, created: String},...] +} + +class CoreDataController { + static let shared = CoreDataController() + + lazy var context = persistentContainer.viewContext + + lazy var persistentContainer: NSPersistentContainer = { + /* + The persistent container for the application. This implementation + creates and returns a container, having loaded the store for the + application to it. This property is optional since there are legitimate + error conditions that could cause the creation of the store to fail. + */ + let container = NSPersistentContainer(name: "Model") + container.loadPersistentStores(completionHandler: { (storeDescription, error) in + if let error = error as NSError? { + // Replace this implementation with code to handle the error appropriately. + // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. + + /* + Typical reasons for an error here include: + * The parent directory does not exist, cannot be created, or disallows writing. + * The persistent store is not accessible, due to permissions or data protection when the device is locked. + * The device is out of space. + * The store could not be migrated to the current model version. + Check the error message to determine what the actual problem was. + */ + fatalError("Unresolved error \(error), \(error.userInfo)") + } + }) + return container + }() + + // MARK: CRUD Operations + + func createProduct(productId: String, title: String, productDescription: String, productDescriptionFull: String, img: String, imgCropped: String, price: String) { + let newProduct = Product(context: context) + + newProduct.productId = productId + newProduct.title = title + newProduct.productDescription = productDescription + newProduct.productDescriptionFull = productDescriptionFull + newProduct.img = img + newProduct.imgCropped = imgCropped + newProduct.price = price + } + + func createProduct(product: ProductMap) { + createProduct(productId: String(product.id), title: product.title, productDescription: product.description, productDescriptionFull: product.descriptionfull, img: product.img, imgCropped: product.imgcropped, price: String(product.price)) + } + + func getAllProducts() throws -> [Product] { + let request: NSFetchRequest = Product.fetchRequest() + return try context.fetch(request) + } + + func deleteProduct(product: Product) { + context.delete(product) + do { + try context.save() + } + catch { + // TODO: error + } + } + + func saveContext () { + let context = persistentContainer.viewContext + if context.hasChanges { + do { + try context.save() + } catch { + // TODO: error + } + } + } + + func generateDBItems(total: Int) { + let itemsPerBatch = 1_000 + let batches = total / itemsPerBatch + DispatchQueue.global(qos: .utility).async { + for i in 0.. If Not -> insert the products from response into Core Data - 3 get products from DB (so we get db.query span) and reload the table with this data - */ - getAllProductsFromServer() getAllProductsFromDb() readCurrentDirectory() @@ -54,7 +41,6 @@ class EmpowerPlantViewController: UIViewController { processProducts() checkRelease() - NotificationCenter.default.addObserver(forName: modifiedDBNotificationName, object: nil, queue: nil) { _ in self.getAllProductsFromDb() } @@ -125,13 +111,10 @@ class EmpowerPlantViewController: UIViewController { } func fibonacciSeries(num: Int) -> Int{ - // The value of 0th and 1st number of the fibonacci series are 0 and 1 var n1 = 0 var n2 = 1 - - // To store the result + var nR = 0 - // Adding two previous numbers to find ith number of the series for _ in 0.. clearDb") // self.products was already set by viewDidLoad() // self.products = try context.fetch(Product.fetchRequest()) for product in self.products { - deleteProduct(product: product) + CoreDataController.shared.deleteProduct(product: product) } refreshTable() } @@ -187,10 +161,9 @@ class EmpowerPlantViewController: UIViewController { image: UIImage(systemName: "cart"), style: .plain, target: self, - action: #selector(goToCart) // addToDb + action: #selector(goToCart) ) self.navigationItem.rightBarButtonItem?.accessibilityIdentifier = "Cart" - //self.navigationItem.rightBarButtonItem?.badgeValue = "\(1)" self.navigationItem.leftBarButtonItems = [UIBarButtonItem( image: UIImage(systemName: "ellipsis"), @@ -228,69 +201,16 @@ class EmpowerPlantViewController: UIViewController { if totalItems == 0 { totalItems = defaultTotalItems } - var itemsPerBatch = 1_000 - let batches = totalItems / itemsPerBatch - - let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext - DispatchQueue.global(qos: .utility).async { - for i in 0.. UITableViewCell { let model = products[indexPath.row] let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) - // 'model' has all available attributes here, if needed in the future (e.g. UI development) cell.textLabel?.text = model.title return cell } @@ -403,7 +310,6 @@ extension EmpowerPlantViewController: UITableViewDataSource { // MARK: UITableViewDelegate extension EmpowerPlantViewController: UITableViewDelegate { - // Code that executes on Click'ing table row, adds the product item to shopping cart func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let product = products[indexPath.row] diff --git a/EmpowerPlant/SceneDelegate.swift b/EmpowerPlant/SceneDelegate.swift index a8cffd1..6cae4b0 100644 --- a/EmpowerPlant/SceneDelegate.swift +++ b/EmpowerPlant/SceneDelegate.swift @@ -8,45 +8,10 @@ import UIKit class SceneDelegate: UIResponder, UIWindowSceneDelegate { - var window: UIWindow? - func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { - // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. - // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. - // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). guard let _ = (scene as? UIWindowScene) else { return } } - - func sceneDidDisconnect(_ scene: UIScene) { - // Called as the scene is being released by the system. - // This occurs shortly after the scene enters the background, or when its session is discarded. - // Release any resources associated with this scene that can be re-created the next time the scene connects. - // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). - } - - func sceneDidBecomeActive(_ scene: UIScene) { - // Called when the scene has moved from an inactive state to an active state. - // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. - } - - func sceneWillResignActive(_ scene: UIScene) { - // Called when the scene will move from an active state to an inactive state. - // This may occur due to temporary interruptions (ex. an incoming phone call). - } - - func sceneWillEnterForeground(_ scene: UIScene) { - // Called as the scene transitions from the background to the foreground. - // Use this method to undo the changes made on entering the background. - } - - func sceneDidEnterBackground(_ scene: UIScene) { - // Called as the scene transitions from the foreground to the background. - // Use this method to save data, release shared resources, and store enough scene-specific state information - // to restore the scene back to its current state. - } - - } diff --git a/EmpowerPlant/Utils.swift b/EmpowerPlant/Utils.swift index 4b67294..5e0d727 100644 --- a/EmpowerPlant/Utils.swift +++ b/EmpowerPlant/Utils.swift @@ -10,7 +10,7 @@ import UIKit public let modifiedDBNotificationName = Notification.Name("io.sentry.empowerplants.newly-generated-db-items-available") public func wipeDB() { - guard let url = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.persistentStoreCoordinator.persistentStores.first?.url else { + guard let url = CoreDataController.shared.persistentContainer.persistentStoreCoordinator.persistentStores.first?.url else { // TODO: error return } From e8082414328d50bdfb5edc18f1c8879bb34f7234 Mon Sep 17 00:00:00 2001 From: Andrew McKnight Date: Thu, 17 Jul 2025 15:28:41 -0800 Subject: [PATCH 2/3] more refactors --- EmpowerPlant.xcodeproj/project.pbxproj | 12 ++-- .../xcshareddata/swiftpm/Package.resolved | 6 +- EmpowerPlant/AppDelegate.swift | 1 - EmpowerPlant/CoreDataController.swift | 16 ++++++ EmpowerPlant/ListAppViewController.swift | 2 - EmpowerPlant/Product+CoreDataClass.swift | 55 ------------------- EmpowerPlant/Product+CoreDataProperties.swift | 14 ----- EmpowerPlant/Product.swift | 31 +++++++++++ EmpowerPlant/ShoppingCart.swift | 1 - EmpowerPlant/Utils.swift | 16 ------ 10 files changed, 54 insertions(+), 100 deletions(-) delete mode 100644 EmpowerPlant/Product+CoreDataClass.swift create mode 100644 EmpowerPlant/Product.swift diff --git a/EmpowerPlant.xcodeproj/project.pbxproj b/EmpowerPlant.xcodeproj/project.pbxproj index e9275be..ad1dabb 100644 --- a/EmpowerPlant.xcodeproj/project.pbxproj +++ b/EmpowerPlant.xcodeproj/project.pbxproj @@ -15,8 +15,7 @@ 848716B72ADFAA2000756467 /* Sentry in Frameworks */ = {isa = PBXBuildFile; productRef = 848716B62ADFAA2000756467 /* Sentry */; }; 8B21663C29D3F8C80009C890 /* RandomErrors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B21663B29D3F8C80009C890 /* RandomErrors.swift */; }; 8BA3AB382A20212C00BE1EA8 /* CartViewControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BA3AB372A20212C00BE1EA8 /* CartViewControllerTests.swift */; }; - D15EDF12282BF7FB00FC13D6 /* Product+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = D15EDF11282BF7FB00FC13D6 /* Product+CoreDataProperties.swift */; }; - D15EDF14282BF80400FC13D6 /* Product+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = D15EDF13282BF80400FC13D6 /* Product+CoreDataClass.swift */; }; + D15EDF14282BF80400FC13D6 /* Product.swift in Sources */ = {isa = PBXBuildFile; fileRef = D15EDF13282BF80400FC13D6 /* Product.swift */; }; D15FCDA927E00F0D00258BF3 /* Model.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = D15FCDA727E00F0D00258BF3 /* Model.xcdatamodeld */; }; D17C73B327D8291D006650AF /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D17C73B227D8291D006650AF /* AppDelegate.swift */; }; D17C73B527D8291D006650AF /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D17C73B427D8291D006650AF /* SceneDelegate.swift */; }; @@ -57,8 +56,7 @@ 84A2641E2AA926A300A62A88 /* .env */ = {isa = PBXFileReference; lastKnownFileType = text; path = .env; sourceTree = ""; }; 8B21663B29D3F8C80009C890 /* RandomErrors.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RandomErrors.swift; sourceTree = ""; }; 8BA3AB372A20212C00BE1EA8 /* CartViewControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CartViewControllerTests.swift; sourceTree = ""; }; - D15EDF11282BF7FB00FC13D6 /* Product+CoreDataProperties.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Product+CoreDataProperties.swift"; sourceTree = ""; }; - D15EDF13282BF80400FC13D6 /* Product+CoreDataClass.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Product+CoreDataClass.swift"; sourceTree = ""; }; + D15EDF13282BF80400FC13D6 /* Product.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Product.swift; sourceTree = ""; }; D15FCDA827E00F0D00258BF3 /* Model.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Model.xcdatamodel; sourceTree = ""; }; D17C73B227D8291D006650AF /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; D17C73B427D8291D006650AF /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; @@ -126,8 +124,7 @@ D17C73B227D8291D006650AF /* AppDelegate.swift */, D17C73B427D8291D006650AF /* SceneDelegate.swift */, D17C73B827D8291D006650AF /* Main.storyboard */, - D15EDF13282BF80400FC13D6 /* Product+CoreDataClass.swift */, - D15EDF11282BF7FB00FC13D6 /* Product+CoreDataProperties.swift */, + D15EDF13282BF80400FC13D6 /* Product.swift */, D17C73D127D83321006650AF /* ListAppViewController.swift */, 843BD60E2AD08CE900B0098F /* Utils.swift */, D15FCDA727E00F0D00258BF3 /* Model.xcdatamodeld */, @@ -289,7 +286,7 @@ D17C73CC27D82EB8006650AF /* EmpowerPlantViewController.swift in Sources */, D17C73D227D83321006650AF /* ListAppViewController.swift in Sources */, 846D3F642E297C3E00D4E7E3 /* CoreDataController.swift in Sources */, - D15EDF14282BF80400FC13D6 /* Product+CoreDataClass.swift in Sources */, + D15EDF14282BF80400FC13D6 /* Product.swift in Sources */, D15FCDA927E00F0D00258BF3 /* Model.xcdatamodeld in Sources */, D17C73CF27D82ED1006650AF /* CartViewController.swift in Sources */, 8B21663C29D3F8C80009C890 /* RandomErrors.swift in Sources */, @@ -297,7 +294,6 @@ 843BD60F2AD08CE900B0098F /* Utils.swift in Sources */, D17C73B327D8291D006650AF /* AppDelegate.swift in Sources */, D17C73B527D8291D006650AF /* SceneDelegate.swift in Sources */, - D15EDF12282BF7FB00FC13D6 /* Product+CoreDataProperties.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/EmpowerPlant.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/EmpowerPlant.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index eba9ba5..bd822f8 100644 --- a/EmpowerPlant.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/EmpowerPlant.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -15,10 +15,10 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/getsentry/sentry-cocoa", "state" : { - "revision" : "21223d1c864db0561d91f48d80f269a363a1625d", - "version" : "8.47.0" + "revision" : "930b78a63f47549c81e6e63c9172584f7d3dfdd6", + "version" : "8.52.1" } } ], - "version" : 2 + "version" : 3 } diff --git a/EmpowerPlant/AppDelegate.swift b/EmpowerPlant/AppDelegate.swift index 3b3ee6f..23c71e8 100644 --- a/EmpowerPlant/AppDelegate.swift +++ b/EmpowerPlant/AppDelegate.swift @@ -7,7 +7,6 @@ import UIKit import Sentry -import CoreData @main class AppDelegate: UIResponder, UIApplicationDelegate { diff --git a/EmpowerPlant/CoreDataController.swift b/EmpowerPlant/CoreDataController.swift index 0a87c17..cfef46a 100644 --- a/EmpowerPlant/CoreDataController.swift +++ b/EmpowerPlant/CoreDataController.swift @@ -127,3 +127,19 @@ class CoreDataController { } } } + +public let modifiedDBNotificationName = Notification.Name("io.sentry.empowerplants.newly-generated-db-items-available") + +public func wipeDB() { + guard let url = CoreDataController.shared.persistentContainer.persistentStoreCoordinator.persistentStores.first?.url else { + // TODO: error + return + } + + do { + try FileManager.default.removeItem(at: url) + } catch { + // TODO: error + return + } +} diff --git a/EmpowerPlant/ListAppViewController.swift b/EmpowerPlant/ListAppViewController.swift index a9b6fdb..45da308 100644 --- a/EmpowerPlant/ListAppViewController.swift +++ b/EmpowerPlant/ListAppViewController.swift @@ -10,8 +10,6 @@ import Sentry import UIKit class ListAppViewController: UIViewController { - - @IBOutlet weak var dsnTextField: UITextField! @IBOutlet weak var anrFullyBlockingButton: UIButton! @IBOutlet weak var anrFillingRunLoopButton: UIButton! diff --git a/EmpowerPlant/Product+CoreDataClass.swift b/EmpowerPlant/Product+CoreDataClass.swift deleted file mode 100644 index 43d565d..0000000 --- a/EmpowerPlant/Product+CoreDataClass.swift +++ /dev/null @@ -1,55 +0,0 @@ -// -// Product+CoreDataClass.swift -// -// -// Created by William Capozzoli on 3/14/22. -// -// - -import Foundation -import CoreData - -@objc(Product) -public class Product: NSManagedObject { - required convenience public init(from decoder: Decoder) throws { - self.init() - } -} - - -// TODO: Deprecate this soon -// This was all the boilerplate needed for mapping the HTTP Response directly into a Product CoreData Class, -// in addition to changes needed in XCode settings for the Product Entity -// enum CodingKeys: String, CodingKey { -// case title -// case shortdescription -// case longdescription -// case parent -// } - -// enum CodingKeys: CodingKey { -// case title -// } -// guard let context = decoder.userInfo[CodingUserInfoKey.context!] as? NSManagedObjectContext else { -// print("failed contextget"); -// throw ManagedObjectError.decodeContextError -// -// } -// guard let entity = NSEntityDescription.entity(forEntityName: "Product", in: context) else { -// print("failed entity init"); -// throw ManagedObjectError.decodeEntityError -// -// } -// -// -// self.init(entity: entity, insertInto: context) - -//enum ManagedObjectError: Error { -// case decodeContextError -// case decodeEntityError -//} -// -//extension CodingUserInfoKey { -// static let context = CodingUserInfoKey(rawValue: "context") -//} -// diff --git a/EmpowerPlant/Product+CoreDataProperties.swift b/EmpowerPlant/Product+CoreDataProperties.swift index 214b73c..84156b4 100644 --- a/EmpowerPlant/Product+CoreDataProperties.swift +++ b/EmpowerPlant/Product+CoreDataProperties.swift @@ -12,18 +12,4 @@ import CoreData extension Product { - @nonobjc public class func fetchRequest() -> NSFetchRequest { - let fr = NSFetchRequest(entityName: "Product") - fr.sortDescriptors = [.init(key: "title", ascending: true)] - return fr - } - -// @NSManaged public var text: String? - @NSManaged public var title: String? - @NSManaged public var productDescription: String? - @NSManaged public var productDescriptionFull: String? - @NSManaged public var productId: String? - @NSManaged public var img: String? - @NSManaged public var imgCropped: String? - @NSManaged public var price: String? } diff --git a/EmpowerPlant/Product.swift b/EmpowerPlant/Product.swift new file mode 100644 index 0000000..6da2ed0 --- /dev/null +++ b/EmpowerPlant/Product.swift @@ -0,0 +1,31 @@ +// +// Product+CoreDataClass.swift +// +// +// Created by William Capozzoli on 3/14/22. +// +// + +import Foundation +import CoreData + +@objc(Product) +public class Product: NSManagedObject { + @NSManaged public var title: String? + @NSManaged public var productDescription: String? + @NSManaged public var productDescriptionFull: String? + @NSManaged public var productId: String? + @NSManaged public var img: String? + @NSManaged public var imgCropped: String? + @NSManaged public var price: String? + + required convenience public init(from decoder: Decoder) throws { + self.init() + } + + @nonobjc public class func fetchRequest() -> NSFetchRequest { + let fr = NSFetchRequest(entityName: "Product") + fr.sortDescriptors = [.init(key: "title", ascending: true)] + return fr + } +} diff --git a/EmpowerPlant/ShoppingCart.swift b/EmpowerPlant/ShoppingCart.swift index d50c764..093768d 100644 --- a/EmpowerPlant/ShoppingCart.swift +++ b/EmpowerPlant/ShoppingCart.swift @@ -7,7 +7,6 @@ import Foundation - class ShoppingCart { //creates the instance and guarantees that it's unique diff --git a/EmpowerPlant/Utils.swift b/EmpowerPlant/Utils.swift index 5e0d727..47266e6 100644 --- a/EmpowerPlant/Utils.swift +++ b/EmpowerPlant/Utils.swift @@ -7,22 +7,6 @@ import UIKit -public let modifiedDBNotificationName = Notification.Name("io.sentry.empowerplants.newly-generated-db-items-available") - -public func wipeDB() { - guard let url = CoreDataController.shared.persistentContainer.persistentStoreCoordinator.persistentStores.first?.url else { - // TODO: error - return - } - - do { - try FileManager.default.removeItem(at: url) - } catch { - // TODO: error - return - } -} - /** Add a delay based on current version. */ public func checkRelease() { guard let versionString = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String else { From 9e1a17c1a12aef71ba5cb94ae1f3011ec96f69a2 Mon Sep 17 00:00:00 2001 From: Andrew McKnight Date: Thu, 17 Jul 2025 15:52:34 -0800 Subject: [PATCH 3/3] remove unused function; just directly call function in same class --- EmpowerPlant/EmpowerPlantViewController.swift | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/EmpowerPlant/EmpowerPlantViewController.swift b/EmpowerPlant/EmpowerPlantViewController.swift index 8c3edef..bad3b97 100644 --- a/EmpowerPlant/EmpowerPlantViewController.swift +++ b/EmpowerPlant/EmpowerPlantViewController.swift @@ -144,18 +144,6 @@ class EmpowerPlantViewController: UIViewController { self.present(alert, animated: true, completion: nil) } - // TODO: merge this and and wipeDB - @objc - func clearDb() { - print("> clearDb") - // self.products was already set by viewDidLoad() - // self.products = try context.fetch(Product.fetchRequest()) - for product in self.products { - CoreDataController.shared.deleteProduct(product: product) - } - refreshTable() - } - private func configureNavigationItems() { self.navigationItem.rightBarButtonItem = UIBarButtonItem( image: UIImage(systemName: "cart"), @@ -180,7 +168,7 @@ class EmpowerPlantViewController: UIViewController { })) actionSheet.addAction(UIAlertAction(title: "Clear DB", style: .default, handler: { _ in wipeDB() - NotificationCenter.default.post(name: modifiedDBNotificationName, object: nil) + self.getAllProductsFromDb() })) actionSheet.addAction(UIAlertAction(title: "Cancel", style: .destructive)) present(actionSheet, animated: true)