ContactTrickStateModel.swift 6.0 KB

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