From 6b6a2c381de252c6297aaf96e2cf4741b466a8d4 Mon Sep 17 00:00:00 2001 From: Satindar Dhillon Date: Thu, 29 Sep 2022 08:39:31 -0700 Subject: [PATCH 1/5] delete link from view context rather than background context --- .../Views/WebReader/WebReaderContainer.swift | 9 ++++- .../DataService/Mutations/RemoveLink.swift | 37 +++++++++++-------- 2 files changed, 29 insertions(+), 17 deletions(-) diff --git a/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderContainer.swift b/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderContainer.swift index 3624aec4b..fdf356573 100644 --- a/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderContainer.swift +++ b/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderContainer.swift @@ -185,9 +185,16 @@ struct WebReaderContainerView: View { .alert("Are you sure?", isPresented: $showDeleteConfirmation) { Button("Remove Link", role: .destructive) { Snackbar.show(message: "Link removed") - dataService.removeLink(objectID: item.objectID) + #if os(iOS) + let itemID = item.unwrappedID + dataService.viewContext.performAndWait { + item.remove(inContext: dataService.viewContext) + } + dataService.syncLinkDeletion(itemID: itemID, objectID: nil) presentationMode.wrappedValue.dismiss() + #else + dataService.removeLink(objectID: item.objectID) #endif } Button("Cancel", role: .cancel, action: {}) diff --git a/apple/OmnivoreKit/Sources/Services/DataService/Mutations/RemoveLink.swift b/apple/OmnivoreKit/Sources/Services/DataService/Mutations/RemoveLink.swift index d6a3e3894..ee8184b4a 100644 --- a/apple/OmnivoreKit/Sources/Services/DataService/Mutations/RemoveLink.swift +++ b/apple/OmnivoreKit/Sources/Services/DataService/Mutations/RemoveLink.swift @@ -3,8 +3,8 @@ import Foundation import Models import SwiftGraphQL -extension DataService { - public func removeLink(objectID: NSManagedObjectID) { +public extension DataService { + func removeLink(objectID: NSManagedObjectID) { // Update CoreData backgroundContext.perform { [weak self] in guard let self = self else { return } @@ -16,7 +16,10 @@ extension DataService { } } - func syncLinkDeletion(itemID: String, objectID: NSManagedObjectID) { + // TODO: this doesn't really work since we usually delete from core data first + // and then sync the deletion with the server. So we have no way to recored a failed + // delete call to the server as it is now... + func syncLinkDeletion(itemID: String, objectID: NSManagedObjectID?) { enum MutationResult { case success(linkId: String) case error(errorCode: Enums.SetBookmarkArticleErrorCode) @@ -53,21 +56,23 @@ extension DataService { let data = try? result.get() let isSyncSuccess = data != nil - context.perform { - guard let linkedItem = context.object(with: objectID) as? LinkedItem else { return } + if let objectID = objectID { + context.perform { + guard let linkedItem = context.object(with: objectID) as? LinkedItem else { return } - if isSyncSuccess { - linkedItem.remove(inContext: context) - } else { - linkedItem.serverSyncStatus = Int64(ServerSyncStatus.needsDeletion.rawValue) - } + if isSyncSuccess { + linkedItem.remove(inContext: context) + } else { + linkedItem.serverSyncStatus = Int64(ServerSyncStatus.needsDeletion.rawValue) + } - do { - try context.save() - logger.debug("LinkedItem deleted succesfully") - } catch { - context.rollback() - logger.debug("Failed to delete LinkedItem: \(error.localizedDescription)") + do { + try context.save() + logger.debug("LinkedItem deleted succesfully") + } catch { + context.rollback() + logger.debug("Failed to delete LinkedItem: \(error.localizedDescription)") + } } } } From 96ed76e56289ecea6103ec45af58f13202c8ad65 Mon Sep 17 00:00:00 2001 From: Satindar Dhillon Date: Thu, 29 Sep 2022 11:30:31 -0700 Subject: [PATCH 2/5] make sure coredata is updated before popping delted item --- .../Views/WebReader/WebReaderContainer.swift | 9 +-- .../DataService/Mutations/RemoveLink.swift | 61 +++++++++++-------- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderContainer.swift b/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderContainer.swift index fdf356573..377b7e0fe 100644 --- a/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderContainer.swift +++ b/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderContainer.swift @@ -185,16 +185,9 @@ struct WebReaderContainerView: View { .alert("Are you sure?", isPresented: $showDeleteConfirmation) { Button("Remove Link", role: .destructive) { Snackbar.show(message: "Link removed") - + dataService.removeLink(objectID: item.objectID, useViewContext: true) #if os(iOS) - let itemID = item.unwrappedID - dataService.viewContext.performAndWait { - item.remove(inContext: dataService.viewContext) - } - dataService.syncLinkDeletion(itemID: itemID, objectID: nil) presentationMode.wrappedValue.dismiss() - #else - dataService.removeLink(objectID: item.objectID) #endif } Button("Cancel", role: .cancel, action: {}) diff --git a/apple/OmnivoreKit/Sources/Services/DataService/Mutations/RemoveLink.swift b/apple/OmnivoreKit/Sources/Services/DataService/Mutations/RemoveLink.swift index ee8184b4a..2df31817e 100644 --- a/apple/OmnivoreKit/Sources/Services/DataService/Mutations/RemoveLink.swift +++ b/apple/OmnivoreKit/Sources/Services/DataService/Mutations/RemoveLink.swift @@ -4,22 +4,31 @@ import Models import SwiftGraphQL public extension DataService { - func removeLink(objectID: NSManagedObjectID) { - // Update CoreData - backgroundContext.perform { [weak self] in - guard let self = self else { return } - guard let linkedItem = self.backgroundContext.object(with: objectID) as? LinkedItem else { return } - linkedItem.remove(inContext: self.backgroundContext) + func removeLink(objectID: NSManagedObjectID, useViewContext: Bool = false) { + let context = useViewContext ? viewContext : backgroundContext - // Send update to server - self.syncLinkDeletion(itemID: linkedItem.unwrappedID, objectID: objectID) + // Update CoreData + context.performAndWait { + guard let linkedItem = context.object(with: objectID) as? LinkedItem else { return } + linkedItem.serverSyncStatus = Int64(ServerSyncStatus.needsDeletion.rawValue) + + do { + try context.save() + logger.debug("LinkedItem succesfully marked for deletion") + } catch { + context.rollback() + logger.debug("Failed to mark LinkedItem for deletion: \(error.localizedDescription)") + } + } + + // Send update to server + backgroundContext.perform { [weak self] in + guard let linkedItem = self?.backgroundContext.object(with: objectID) as? LinkedItem else { return } + self?.syncLinkDeletion(itemID: linkedItem.unwrappedID, objectID: objectID) } } - // TODO: this doesn't really work since we usually delete from core data first - // and then sync the deletion with the server. So we have no way to recored a failed - // delete call to the server as it is now... - func syncLinkDeletion(itemID: String, objectID: NSManagedObjectID?) { + func syncLinkDeletion(itemID: String, objectID: NSManagedObjectID) { enum MutationResult { case success(linkId: String) case error(errorCode: Enums.SetBookmarkArticleErrorCode) @@ -56,23 +65,21 @@ public extension DataService { let data = try? result.get() let isSyncSuccess = data != nil - if let objectID = objectID { - context.perform { - guard let linkedItem = context.object(with: objectID) as? LinkedItem else { return } + context.perform { + guard let linkedItem = context.object(with: objectID) as? LinkedItem else { return } - if isSyncSuccess { - linkedItem.remove(inContext: context) - } else { - linkedItem.serverSyncStatus = Int64(ServerSyncStatus.needsDeletion.rawValue) - } + if isSyncSuccess { + linkedItem.remove(inContext: context) + } else { + linkedItem.serverSyncStatus = Int64(ServerSyncStatus.needsDeletion.rawValue) + } - do { - try context.save() - logger.debug("LinkedItem deleted succesfully") - } catch { - context.rollback() - logger.debug("Failed to delete LinkedItem: \(error.localizedDescription)") - } + do { + try context.save() + logger.debug("LinkedItem deleted succesfully") + } catch { + context.rollback() + logger.debug("Failed to delete LinkedItem: \(error.localizedDescription)") } } } From 157edb0ae3db4c9186666b590e92399bbfbaa458 Mon Sep 17 00:00:00 2001 From: Satindar Dhillon Date: Thu, 29 Sep 2022 13:42:09 -0700 Subject: [PATCH 3/5] use viewContext to remove item from home feed --- .../OmnivoreKit/Sources/App/Views/Home/HomeFeedViewModel.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewModel.swift b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewModel.swift index 543d23727..fe9b98f5f 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewModel.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewModel.swift @@ -233,7 +233,7 @@ import Views func removeLink(dataService: DataService, objectID: NSManagedObjectID) { Snackbar.show(message: "Link removed") - dataService.removeLink(objectID: objectID) + dataService.removeLink(objectID: objectID, useViewContext: true) } func snoozeUntil(dataService: DataService, linkId: String, until: Date, successMessage: String?) async { From 924592ab6baf49bfe60cae4d59c07bdb2c21923f Mon Sep 17 00:00:00 2001 From: Satindar Dhillon Date: Thu, 29 Sep 2022 20:24:43 -0700 Subject: [PATCH 4/5] mark highlights and labels for deletion before server sync --- .../App/Views/Home/HomeFeedViewModel.swift | 2 +- .../Views/WebReader/WebReaderContainer.swift | 2 +- .../Mutations/DeleteHighlight.swift | 24 +++++++++++++------ .../Mutations/RemoveLabelPublisher.swift | 19 ++++++++++----- .../DataService/Mutations/RemoveLink.swift | 12 ++++------ 5 files changed, 37 insertions(+), 22 deletions(-) diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewModel.swift b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewModel.swift index fe9b98f5f..543d23727 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewModel.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewModel.swift @@ -233,7 +233,7 @@ import Views func removeLink(dataService: DataService, objectID: NSManagedObjectID) { Snackbar.show(message: "Link removed") - dataService.removeLink(objectID: objectID, useViewContext: true) + dataService.removeLink(objectID: objectID) } func snoozeUntil(dataService: DataService, linkId: String, until: Date, successMessage: String?) async { diff --git a/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderContainer.swift b/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderContainer.swift index 377b7e0fe..3624aec4b 100644 --- a/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderContainer.swift +++ b/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderContainer.swift @@ -185,7 +185,7 @@ struct WebReaderContainerView: View { .alert("Are you sure?", isPresented: $showDeleteConfirmation) { Button("Remove Link", role: .destructive) { Snackbar.show(message: "Link removed") - dataService.removeLink(objectID: item.objectID, useViewContext: true) + dataService.removeLink(objectID: item.objectID) #if os(iOS) presentationMode.wrappedValue.dismiss() #endif diff --git a/apple/OmnivoreKit/Sources/Services/DataService/Mutations/DeleteHighlight.swift b/apple/OmnivoreKit/Sources/Services/DataService/Mutations/DeleteHighlight.swift index ff9a95b87..286e0524b 100644 --- a/apple/OmnivoreKit/Sources/Services/DataService/Mutations/DeleteHighlight.swift +++ b/apple/OmnivoreKit/Sources/Services/DataService/Mutations/DeleteHighlight.swift @@ -5,20 +5,30 @@ import SwiftGraphQL public extension DataService { func deleteHighlight(highlightID: String) { - if let highlight = Highlight.lookup(byID: highlightID, inContext: backgroundContext) { + if let highlight = Highlight.lookup(byID: highlightID, inContext: viewContext) { deleteHighlight(objectID: highlight.objectID) } } private func deleteHighlight(objectID: NSManagedObjectID) { // Update CoreData - backgroundContext.perform { [weak self] in - guard let self = self else { return } - guard let highlight = self.backgroundContext.object(with: objectID) as? Highlight else { return } - highlight.remove(inContext: self.backgroundContext) + viewContext.performAndWait { + guard let highlight = viewContext.object(with: objectID) as? Highlight else { return } + highlight.serverSyncStatus = Int64(ServerSyncStatus.needsDeletion.rawValue) - // Send update to server - self.syncHighlightDeletion(highlightID: highlight.unwrappedID, objectID: objectID) + do { + try viewContext.save() + logger.debug("Highlight succesfully marked for deletion") + } catch { + viewContext.rollback() + logger.debug("Failed to mark Highlight for deletion: \(error.localizedDescription)") + } + } + + // Send update to server + backgroundContext.perform { [weak self] in + guard let highlight = self?.backgroundContext.object(with: objectID) as? Highlight else { return } + self?.syncHighlightDeletion(highlightID: highlight.unwrappedID, objectID: objectID) } } diff --git a/apple/OmnivoreKit/Sources/Services/DataService/Mutations/RemoveLabelPublisher.swift b/apple/OmnivoreKit/Sources/Services/DataService/Mutations/RemoveLabelPublisher.swift index fc7c02c2b..9df043f40 100644 --- a/apple/OmnivoreKit/Sources/Services/DataService/Mutations/RemoveLabelPublisher.swift +++ b/apple/OmnivoreKit/Sources/Services/DataService/Mutations/RemoveLabelPublisher.swift @@ -5,14 +5,21 @@ import SwiftGraphQL extension DataService { public func removeLabel(labelID: String, name: String) { // Update CoreData - backgroundContext.perform { [weak self] in - guard let self = self else { return } - guard let label = LinkedItemLabel.lookup(byID: labelID, inContext: self.backgroundContext) else { return } - label.remove(inContext: self.backgroundContext) + viewContext.performAndWait { + guard let label = LinkedItemLabel.lookup(byID: labelID, inContext: self.viewContext) else { return } + label.serverSyncStatus = Int64(ServerSyncStatus.needsDeletion.rawValue) - // Send update to server - self.syncLabelDeletion(labelID: labelID, labelName: name) + do { + try viewContext.save() + logger.debug("Label succesfully marked for deletion") + } catch { + viewContext.rollback() + logger.debug("Failed to mark Label for deletion: \(error.localizedDescription)") + } } + + // Send update to server + syncLabelDeletion(labelID: labelID, labelName: name) } func syncLabelDeletion(labelID: String, labelName _: String) { diff --git a/apple/OmnivoreKit/Sources/Services/DataService/Mutations/RemoveLink.swift b/apple/OmnivoreKit/Sources/Services/DataService/Mutations/RemoveLink.swift index 2df31817e..5fd1bbfca 100644 --- a/apple/OmnivoreKit/Sources/Services/DataService/Mutations/RemoveLink.swift +++ b/apple/OmnivoreKit/Sources/Services/DataService/Mutations/RemoveLink.swift @@ -4,19 +4,17 @@ import Models import SwiftGraphQL public extension DataService { - func removeLink(objectID: NSManagedObjectID, useViewContext: Bool = false) { - let context = useViewContext ? viewContext : backgroundContext - + func removeLink(objectID: NSManagedObjectID) { // Update CoreData - context.performAndWait { - guard let linkedItem = context.object(with: objectID) as? LinkedItem else { return } + viewContext.performAndWait { + guard let linkedItem = viewContext.object(with: objectID) as? LinkedItem else { return } linkedItem.serverSyncStatus = Int64(ServerSyncStatus.needsDeletion.rawValue) do { - try context.save() + try viewContext.save() logger.debug("LinkedItem succesfully marked for deletion") } catch { - context.rollback() + viewContext.rollback() logger.debug("Failed to mark LinkedItem for deletion: \(error.localizedDescription)") } } From 26cc06e2a8f5d2750e8ef1dc119adc60ae173f89 Mon Sep 17 00:00:00 2001 From: Satindar Dhillon Date: Thu, 29 Sep 2022 20:36:18 -0700 Subject: [PATCH 5/5] bump ios to v 1.15.0 --- apple/Omnivore.xcodeproj/project.pbxproj | 36 ++++++++++++------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/apple/Omnivore.xcodeproj/project.pbxproj b/apple/Omnivore.xcodeproj/project.pbxproj index 7b20a9b8c..24594bc28 100644 --- a/apple/Omnivore.xcodeproj/project.pbxproj +++ b/apple/Omnivore.xcodeproj/project.pbxproj @@ -1233,7 +1233,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 70; + CURRENT_PROJECT_VERSION = 75; DEVELOPMENT_TEAM = QJF2XZ86HB; ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = InfoPlists/ShareExtensionMac.plist; @@ -1243,7 +1243,7 @@ "@executable_path/../../../../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 12.0; - MARKETING_VERSION = 1.14.0; + MARKETING_VERSION = 1.15.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "app.omnivore.app.ShareExtension-Mac"; @@ -1265,7 +1265,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 70; + CURRENT_PROJECT_VERSION = 75; DEVELOPMENT_TEAM = QJF2XZ86HB; ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = InfoPlists/ShareExtensionMac.plist; @@ -1275,7 +1275,7 @@ "@executable_path/../../../../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 12.0; - MARKETING_VERSION = 1.14.0; + MARKETING_VERSION = 1.15.0; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "app.omnivore.app.ShareExtension-Mac"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -1347,7 +1347,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 70; + CURRENT_PROJECT_VERSION = 75; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = QJF2XZ86HB; ENABLE_HARDENED_RUNTIME = YES; @@ -1358,7 +1358,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 12.0; - MARKETING_VERSION = 1.14.0; + MARKETING_VERSION = 1.15.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = app.omnivore.app; @@ -1381,7 +1381,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 70; + CURRENT_PROJECT_VERSION = 75; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = QJF2XZ86HB; ENABLE_HARDENED_RUNTIME = YES; @@ -1392,7 +1392,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 12.0; - MARKETING_VERSION = 1.14.0; + MARKETING_VERSION = 1.15.0; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = app.omnivore.app; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -1447,7 +1447,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.14.0; + MARKETING_VERSION = 1.15.0; PRODUCT_BUNDLE_IDENTIFIER = app.omnivore.app; PRODUCT_NAME = Omnivore; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1479,7 +1479,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.14.0; + MARKETING_VERSION = 1.15.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; OTHER_LDFLAGS = ( @@ -1518,7 +1518,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.14.0; + MARKETING_VERSION = 1.15.0; MTL_FAST_MATH = YES; OTHER_LDFLAGS = ( "-framework", @@ -1544,7 +1544,7 @@ CODE_SIGN_ENTITLEMENTS = "Entitlements/SafariExtension-Mac.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 70; + CURRENT_PROJECT_VERSION = 75; DEVELOPMENT_TEAM = QJF2XZ86HB; ENABLE_HARDENED_RUNTIME = YES; GENERATE_INFOPLIST_FILE = YES; @@ -1557,7 +1557,7 @@ "@executable_path/../../../../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 12.0; - MARKETING_VERSION = 1.14.0; + MARKETING_VERSION = 1.15.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; OTHER_LDFLAGS = ( @@ -1583,7 +1583,7 @@ CODE_SIGN_ENTITLEMENTS = "Entitlements/SafariExtension-Mac.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 70; + CURRENT_PROJECT_VERSION = 75; DEVELOPMENT_TEAM = QJF2XZ86HB; ENABLE_HARDENED_RUNTIME = YES; GENERATE_INFOPLIST_FILE = YES; @@ -1596,7 +1596,7 @@ "@executable_path/../../../../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 12.0; - MARKETING_VERSION = 1.14.0; + MARKETING_VERSION = 1.15.0; MTL_FAST_MATH = YES; OTHER_LDFLAGS = ( "-framework", @@ -1683,7 +1683,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.14.0; + MARKETING_VERSION = 1.15.0; PRODUCT_BUNDLE_IDENTIFIER = "app.omnivore.app.share-extension"; PRODUCT_NAME = ShareExtension; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1738,7 +1738,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.14.0; + MARKETING_VERSION = 1.15.0; PRODUCT_BUNDLE_IDENTIFIER = app.omnivore.app; PRODUCT_NAME = Omnivore; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1767,7 +1767,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.14.0; + MARKETING_VERSION = 1.15.0; PRODUCT_BUNDLE_IDENTIFIER = "app.omnivore.app.share-extension"; PRODUCT_NAME = ShareExtension; PROVISIONING_PROFILE_SPECIFIER = "";