ContactTrickStateModel.swift 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. import ConnectIQ
  2. import CoreData
  3. import SwiftUI
  4. extension ContactTrick {
  5. @Observable final class StateModel: BaseStateModel<Provider> {
  6. @ObservationIgnored @Injected() var contactTrickStorage: ContactTrickStorage!
  7. @ObservationIgnored @Injected() var contactTrickManager: ContactTrickManager!
  8. var contactTrickEntries = [ContactTrickEntry]()
  9. var units: GlucoseUnits = .mmolL
  10. // Help Sheet
  11. var isHelpSheetPresented: Bool = false
  12. var helpSheetDetent = PresentationDetent.large
  13. var previewState: ContactTrickState {
  14. ContactTrickState(
  15. glucose: self.units == .mmolL ? "6,8" : "127",
  16. trend: "↗︎",
  17. delta: units == .mmolL ? "+0,3" : "+7",
  18. lastLoopDate: .now,
  19. iob: 6.1,
  20. iobText: "6,1",
  21. cob: 27.0,
  22. cobText: "27",
  23. eventualBG: units == .mmolL ? "8,9" : "163",
  24. maxIOB: 12.0,
  25. maxCOB: 120.0
  26. )
  27. }
  28. /// Subscribes to updates and initializes data fetching.
  29. override func subscribe() {
  30. units = settingsManager.settings.units
  31. Task {
  32. /// Initial fetch to fill the ContactTrickEntry array
  33. await fetchContactTrickEntriesAndUpdateUI()
  34. }
  35. }
  36. /// Fetches all ContactTrickEntries from Core Data.
  37. func fetchContactTrickEntriesAndUpdateUI() async {
  38. let entries = await contactTrickStorage.fetchContactTrickEntries()
  39. await MainActor.run {
  40. self.contactTrickEntries = entries
  41. }
  42. }
  43. /// Creates a new contact in Apple Contacts and saves it to Core Data.
  44. /// - Parameters:
  45. /// - entry: The ContactTrickEntry to be saved.
  46. /// - name: The name of the contact.
  47. func createAndSaveContactTrick(entry: ContactTrickEntry, name: String) async {
  48. // 1. Check for contact access permissions.
  49. let hasAccess = await contactTrickManager.requestAccess()
  50. guard hasAccess else {
  51. debugPrint("\(DebuggingIdentifiers.failed) No access to contacts.")
  52. return
  53. }
  54. // 2. Create the contact and retrieve its `identifier`.
  55. guard let contactId = await contactTrickManager.createContact(name: name) else {
  56. debugPrint("\(DebuggingIdentifiers.failed) Failed to create contact.")
  57. return
  58. }
  59. // 3. Update the entry with the `contactId`.
  60. var updatedEntry = entry
  61. updatedEntry.contactId = contactId
  62. updatedEntry.name = name
  63. // 4. Save the contact to Core Data.
  64. await addContactTrickEntry(updatedEntry)
  65. // 5. Update ContactTrickState and set the image for the newly created contact
  66. await contactTrickManager.updateContactTrickState()
  67. await contactTrickManager.setImageForContact(contactId: contactId)
  68. }
  69. /// Adds a ContactTrickEntry to Core Data.
  70. /// - Parameter entry: The ContactTrickEntry to be saved.
  71. func addContactTrickEntry(_ entry: ContactTrickEntry) async {
  72. await contactTrickStorage.storeContactTrickEntry(entry)
  73. await fetchContactTrickEntriesAndUpdateUI()
  74. }
  75. /// Deletes a contact from Apple Contacts and Core Data.
  76. /// - Parameter entry: The ContactTrickEntry representing the contact to be deleted.
  77. func deleteContact(entry: ContactTrickEntry) async {
  78. guard let contactId = entry.contactId else {
  79. debugPrint("\(DebuggingIdentifiers.failed) Contact does not have a valid ID.")
  80. return
  81. }
  82. // 1. Attempt to delete the contact from Apple Contacts.
  83. let contactDeleted = await contactTrickManager.deleteContact(withIdentifier: contactId)
  84. if contactDeleted {
  85. debugPrint("\(DebuggingIdentifiers.succeeded) Contact successfully deleted from Apple Contacts: \(contactId)")
  86. } else {
  87. debugPrint("\(DebuggingIdentifiers.failed) Failed to delete contact from Apple Contacts. Check if it exists.")
  88. }
  89. // 2. Delete the entry from Core Data.
  90. if let objectID = entry.managedObjectID {
  91. await deleteContactTrick(objectID: objectID)
  92. }
  93. }
  94. /// Deletes a Core Data entry.
  95. /// - Parameter objectID: The Managed Object ID of the entry to be deleted.
  96. func deleteContactTrick(objectID: NSManagedObjectID) async {
  97. await contactTrickStorage.deleteContactTrickEntry(objectID)
  98. await fetchContactTrickEntriesAndUpdateUI()
  99. }
  100. /// Updates a contact in Apple Contacts and Core Data.
  101. /// - Parameters:
  102. /// - entry: The ContactTrickEntry to be updated.
  103. func updateContact(with entry: ContactTrickEntry) async {
  104. guard let contactId = entry.contactId else {
  105. debugPrint("\(DebuggingIdentifiers.failed) Contact does not have a valid ID.")
  106. return
  107. }
  108. // 1. Update the entry in Core Data.
  109. await updateContactTrick(entry)
  110. // 2. Update the contact in Apple Contacts.
  111. /// Update name
  112. let contactUpdated = await contactTrickManager
  113. .updateContact(withIdentifier: contactId, newName: entry.name) // TODO: - Probably not needed anymore
  114. guard contactUpdated else {
  115. debugPrint("\(DebuggingIdentifiers.failed) Failed to update contact.")
  116. return
  117. }
  118. /// Update state and image
  119. await contactTrickManager.updateContactTrickState()
  120. await contactTrickManager.setImageForContact(contactId: contactId)
  121. }
  122. /// Updates a Core Data entry.
  123. /// - Parameter entry: The updated ContactTrickEntry.
  124. func updateContactTrick(_ entry: ContactTrickEntry) async {
  125. await contactTrickStorage.updateContactTrickEntry(entry)
  126. await fetchContactTrickEntriesAndUpdateUI()
  127. }
  128. }
  129. }