diff --git a/apple/Omnivore.xcodeproj/project.pbxproj b/apple/Omnivore.xcodeproj/project.pbxproj index 69959bfc0..223e4eabc 100644 --- a/apple/Omnivore.xcodeproj/project.pbxproj +++ b/apple/Omnivore.xcodeproj/project.pbxproj @@ -1251,7 +1251,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 51; DEVELOPMENT_TEAM = QJF2XZ86HB; ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = InfoPlists/ShareExtensionMac.plist; @@ -1261,7 +1261,7 @@ "@executable_path/../../../../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 12.0; - MARKETING_VERSION = 1.6.0; + MARKETING_VERSION = 1.7.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "app.omnivore.app.ShareExtension-Mac"; @@ -1282,7 +1282,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 51; DEVELOPMENT_TEAM = QJF2XZ86HB; ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = InfoPlists/ShareExtensionMac.plist; @@ -1292,7 +1292,7 @@ "@executable_path/../../../../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 12.0; - MARKETING_VERSION = 1.6.0; + MARKETING_VERSION = 1.7.0; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "app.omnivore.app.ShareExtension-Mac"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -1363,7 +1363,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 51; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = QJF2XZ86HB; ENABLE_HARDENED_RUNTIME = YES; @@ -1374,7 +1374,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 12.0; - MARKETING_VERSION = 1.6.0; + MARKETING_VERSION = 1.7.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = app.omnivore.app; @@ -1397,7 +1397,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 51; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = QJF2XZ86HB; ENABLE_HARDENED_RUNTIME = YES; @@ -1408,7 +1408,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 12.0; - MARKETING_VERSION = 1.6.0; + MARKETING_VERSION = 1.7.0; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = app.omnivore.app; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -1463,7 +1463,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.6.0; + MARKETING_VERSION = 1.7.0; PRODUCT_BUNDLE_IDENTIFIER = app.omnivore.app; PRODUCT_NAME = Omnivore; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1495,7 +1495,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.6.0; + MARKETING_VERSION = 1.7.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; OTHER_LDFLAGS = ( @@ -1534,7 +1534,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.6.0; + MARKETING_VERSION = 1.7.0; MTL_FAST_MATH = YES; OTHER_LDFLAGS = ( "-framework", @@ -1560,7 +1560,7 @@ CODE_SIGN_ENTITLEMENTS = "Entitlements/SafariExtension-Mac.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 49; + CURRENT_PROJECT_VERSION = 51; DEVELOPMENT_TEAM = QJF2XZ86HB; ENABLE_HARDENED_RUNTIME = YES; GENERATE_INFOPLIST_FILE = YES; @@ -1573,7 +1573,7 @@ "@executable_path/../../../../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 12.0; - MARKETING_VERSION = 1.6.0; + MARKETING_VERSION = 1.7.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; OTHER_LDFLAGS = ( @@ -1598,7 +1598,7 @@ CODE_SIGN_ENTITLEMENTS = "Entitlements/SafariExtension-Mac.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 49; + CURRENT_PROJECT_VERSION = 51; DEVELOPMENT_TEAM = QJF2XZ86HB; ENABLE_HARDENED_RUNTIME = YES; GENERATE_INFOPLIST_FILE = YES; @@ -1611,7 +1611,7 @@ "@executable_path/../../../../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 12.0; - MARKETING_VERSION = 1.6.0; + MARKETING_VERSION = 1.7.0; MTL_FAST_MATH = YES; OTHER_LDFLAGS = ( "-framework", @@ -1696,7 +1696,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.6.0; + MARKETING_VERSION = 1.7.0; PRODUCT_BUNDLE_IDENTIFIER = "app.omnivore.app.share-extension"; PRODUCT_NAME = ShareExtension; SDKROOT = iphoneos; @@ -1750,7 +1750,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.6.0; + MARKETING_VERSION = 1.7.0; PRODUCT_BUNDLE_IDENTIFIER = app.omnivore.app; PRODUCT_NAME = Omnivore; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1778,7 +1778,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.6.0; + MARKETING_VERSION = 1.7.0; PRODUCT_BUNDLE_IDENTIFIER = "app.omnivore.app.share-extension"; PRODUCT_NAME = ShareExtension; SDKROOT = iphoneos; diff --git a/apple/OmnivoreKit/Sources/App/AppExtensions/Share/ShareExtensionScene.swift b/apple/OmnivoreKit/Sources/App/AppExtensions/Share/ShareExtensionScene.swift index acc01f73a..a51dbb871 100644 --- a/apple/OmnivoreKit/Sources/App/AppExtensions/Share/ShareExtensionScene.swift +++ b/apple/OmnivoreKit/Sources/App/AppExtensions/Share/ShareExtensionScene.swift @@ -79,13 +79,15 @@ final class ShareExtensionViewModel: ObservableObject { } .store(in: &subscriptions) - // Using viewerPublisher to get fast feedback for auth/network errors + // Check connection to get fast feedback for auth/network errors Task { - do { - _ = try await services.dataService.fetchViewer() - } catch { - debugText = "saveArticleError: \(error)" - status = .failed(error: .unknown(description: "")) + let hasConnectionAndValidToken = await services.dataService.hasConnectionAndValidToken() + + if !hasConnectionAndValidToken { + DispatchQueue.main.async { + self.debugText = "saveArticleError: No connection or invalid token." + self.status = .failed(error: .unknown(description: "")) + } } } } diff --git a/apple/OmnivoreKit/Sources/Models/AuthModels.swift b/apple/OmnivoreKit/Sources/Models/AuthModels.swift new file mode 100644 index 000000000..d6bb85af6 --- /dev/null +++ b/apple/OmnivoreKit/Sources/Models/AuthModels.swift @@ -0,0 +1,14 @@ +import Foundation + +public struct AuthVerification: Decodable { + public let authStatus: AuthStatus +} + +public enum AuthStatus: String, Decodable { + case authenticated = "AUTHENTICATED" + case unAuthenticated = "NOT_AUTHENTICATED" + + public var isAuthenticated: Bool { + self == .authenticated + } +} diff --git a/apple/OmnivoreKit/Sources/Models/CoreData/CoreDataModel.xcdatamodeld/CoreDataModel.xcdatamodel/contents b/apple/OmnivoreKit/Sources/Models/CoreData/CoreDataModel.xcdatamodeld/CoreDataModel.xcdatamodel/contents index 183be56df..3556a931c 100644 --- a/apple/OmnivoreKit/Sources/Models/CoreData/CoreDataModel.xcdatamodeld/CoreDataModel.xcdatamodel/contents +++ b/apple/OmnivoreKit/Sources/Models/CoreData/CoreDataModel.xcdatamodeld/CoreDataModel.xcdatamodel/contents @@ -38,6 +38,7 @@ + @@ -85,7 +86,7 @@ - + diff --git a/apple/OmnivoreKit/Sources/Models/DataModels/FeedItem.swift b/apple/OmnivoreKit/Sources/Models/DataModels/FeedItem.swift index c6b8421a3..27bfc1144 100644 --- a/apple/OmnivoreKit/Sources/Models/DataModels/FeedItem.swift +++ b/apple/OmnivoreKit/Sources/Models/DataModels/FeedItem.swift @@ -45,8 +45,8 @@ public extension LinkedItem { return (pageURLString ?? "").hasSuffix("pdf") } - var publisherHostname: String? { - URL(string: publisherURLString ?? pageURLString ?? "")?.host + var publisherDisplayName: String? { + siteName ?? URL(string: publisherURLString ?? pageURLString ?? "")?.host } var imageURL: URL? { diff --git a/apple/OmnivoreKit/Sources/Services/DataService/DataService.swift b/apple/OmnivoreKit/Sources/Services/DataService/DataService.swift index 3528a3dab..6878a40dc 100644 --- a/apple/OmnivoreKit/Sources/Services/DataService/DataService.swift +++ b/apple/OmnivoreKit/Sources/Services/DataService/DataService.swift @@ -55,6 +55,10 @@ public final class DataService: ObservableObject { } } + public func hasConnectionAndValidToken() async -> Bool { + await networker.hasConnectionAndValidToken() + } + private func resetCoreData() { let storeContainer = persistentContainer.persistentStoreCoordinator diff --git a/apple/OmnivoreKit/Sources/Services/DataService/Networking/Networker.swift b/apple/OmnivoreKit/Sources/Services/DataService/Networking/Networker.swift index 7e3320f83..4f2869e23 100644 --- a/apple/OmnivoreKit/Sources/Services/DataService/Networking/Networker.swift +++ b/apple/OmnivoreKit/Sources/Services/DataService/Networking/Networker.swift @@ -20,3 +20,28 @@ public final class Networker { self.urlSession = urlSession } } + +extension Networker { + /// Test if the user has a network connection and a valid auth token + /// - Returns: A `Bool` value + func hasConnectionAndValidToken() async -> Bool { + let urlRequest = URLRequest.create( + baseURL: appEnvironment.serverBaseURL, + urlPath: "/api/auth/verify", + requestMethod: .get, + includeAuthToken: true + ) + + let resource = ServerResource( + urlRequest: urlRequest, + decode: AuthVerification.decode + ) + + do { + let authVerification = try await urlSession.performReq(resource: resource) + return authVerification.authStatus.isAuthenticated + } catch { + return false + } + } +} diff --git a/apple/OmnivoreKit/Sources/Services/DataService/Networking/ServerResource.swift b/apple/OmnivoreKit/Sources/Services/DataService/Networking/ServerResource.swift index 4357931f9..5bdb206c7 100644 --- a/apple/OmnivoreKit/Sources/Services/DataService/Networking/ServerResource.swift +++ b/apple/OmnivoreKit/Sources/Services/DataService/Networking/ServerResource.swift @@ -33,6 +33,9 @@ extension ServerResponse { } } +/// Empty struct to use when a successful network call does not include any JSON +struct EmptyResponse: Decodable {} + extension URLSession { func performReq( resource: ServerResource diff --git a/apple/OmnivoreKit/Sources/Services/DataService/Queries/ArticleContentQuery.swift b/apple/OmnivoreKit/Sources/Services/DataService/Queries/ArticleContentQuery.swift index b4ec3ffbe..bbea73ead 100644 --- a/apple/OmnivoreKit/Sources/Services/DataService/Queries/ArticleContentQuery.swift +++ b/apple/OmnivoreKit/Sources/Services/DataService/Queries/ArticleContentQuery.swift @@ -105,6 +105,7 @@ extension DataService { pageURLString: try $0.url(), descriptionText: try $0.description(), publisherURLString: try $0.originalArticleUrl(), + siteName: try $0.siteName(), author: try $0.author(), publishDate: try $0.publishedAt()?.value, slug: try $0.slug(), diff --git a/apple/OmnivoreKit/Sources/Services/DataService/Queries/LibraryItemsQuery.swift b/apple/OmnivoreKit/Sources/Services/DataService/Queries/LibraryItemsQuery.swift index ac6152ac3..3534ce291 100644 --- a/apple/OmnivoreKit/Sources/Services/DataService/Queries/LibraryItemsQuery.swift +++ b/apple/OmnivoreKit/Sources/Services/DataService/Queries/LibraryItemsQuery.swift @@ -95,6 +95,7 @@ private let articleSelection = Selection.Article { pageURLString: try $0.url(), descriptionText: try $0.description(), publisherURLString: try $0.originalArticleUrl(), + siteName: try $0.siteName(), author: try $0.author(), publishDate: try $0.publishedAt()?.value, slug: try $0.slug(), diff --git a/apple/OmnivoreKit/Sources/Services/InternalModels/InternalLinkedItem.swift b/apple/OmnivoreKit/Sources/Services/InternalModels/InternalLinkedItem.swift index fb69d1fcb..7214897c9 100644 --- a/apple/OmnivoreKit/Sources/Services/InternalModels/InternalLinkedItem.swift +++ b/apple/OmnivoreKit/Sources/Services/InternalModels/InternalLinkedItem.swift @@ -15,6 +15,7 @@ struct InternalLinkedItem { let pageURLString: String let descriptionText: String? let publisherURLString: String? + let siteName: String? let author: String? let publishDate: Date? let slug: String @@ -37,6 +38,7 @@ struct InternalLinkedItem { linkedItem.pageURLString = pageURLString linkedItem.descriptionText = descriptionText linkedItem.publisherURLString = publisherURLString + linkedItem.siteName = siteName linkedItem.author = author linkedItem.publishDate = publishDate linkedItem.slug = slug @@ -93,6 +95,7 @@ extension JSONArticle { pageURLString: url, descriptionText: title, publisherURLString: nil, + siteName: nil, author: nil, publishDate: nil, slug: slug, diff --git a/apple/OmnivoreKit/Sources/Views/FeedItem/GridCard.swift b/apple/OmnivoreKit/Sources/Views/FeedItem/GridCard.swift index bd1f03cd1..a3aba313f 100644 --- a/apple/OmnivoreKit/Sources/Views/FeedItem/GridCard.swift +++ b/apple/OmnivoreKit/Sources/Views/FeedItem/GridCard.swift @@ -100,11 +100,10 @@ public struct GridCard: View { .lineLimit(1) } - if let publisherURL = item.publisherHostname { - Text(publisherURL) + if let publisherDisplayName = item.publisherDisplayName { + Text(publisherDisplayName) .font(.appCaptionTwo) .foregroundColor(.appGrayText) - .underline() .lineLimit(1) } diff --git a/apple/OmnivoreKit/Sources/Views/FeedItem/HomeFeedCardView.swift b/apple/OmnivoreKit/Sources/Views/FeedItem/HomeFeedCardView.swift index 52a477c39..fcd34ec8f 100644 --- a/apple/OmnivoreKit/Sources/Views/FeedItem/HomeFeedCardView.swift +++ b/apple/OmnivoreKit/Sources/Views/FeedItem/HomeFeedCardView.swift @@ -26,11 +26,10 @@ public struct FeedCard: View { .lineLimit(1) } - if let publisherURL = item.publisherHostname { - Text(publisherURL) + if let publisherDisplayName = item.publisherDisplayName { + Text(publisherDisplayName) .font(.appCaption) .foregroundColor(.appGrayText) - .underline() .lineLimit(1) } }