From 48de634e984c8f427e7a0f4b41471196a2cae271 Mon Sep 17 00:00:00 2001 From: Satindar Dhillon Date: Wed, 23 Feb 2022 16:13:29 -0800 Subject: [PATCH] move ProfileContainerViewModel into Binders package --- .../Scenes/ProfileContainerScene.swift | 115 ++++++++++++++++++ .../Sources/Binders/Views/HomeFeedView.swift | 8 +- .../Profile/ProfileCard.swift | 8 +- .../Profile/ProfileContainerView.swift | 114 ----------------- .../UserSettings/ManageAccountView.swift | 8 +- .../Sources/Views/Utils/MacOSSizeClass.swift | 12 +- .../Sources/Views/Web/BasicWebAppView.swift | 26 ++-- 7 files changed, 155 insertions(+), 136 deletions(-) diff --git a/apple/OmnivoreKit/Sources/Binders/Scenes/ProfileContainerScene.swift b/apple/OmnivoreKit/Sources/Binders/Scenes/ProfileContainerScene.swift index 86a7dba1d..049e47e59 100644 --- a/apple/OmnivoreKit/Sources/Binders/Scenes/ProfileContainerScene.swift +++ b/apple/OmnivoreKit/Sources/Binders/Scenes/ProfileContainerScene.swift @@ -1,7 +1,11 @@ +import Combine +import Models import Services import SwiftUI +import Utils import Views +// TODO: remove this view model extension ProfileContainerViewModel { static func make(services: Services) -> ProfileContainerViewModel { let viewModel = ProfileContainerViewModel() @@ -39,3 +43,114 @@ extension ProfileContainerViewModel { .store(in: &subscriptions) } } + +final class ProfileContainerViewModel: ObservableObject { + @Published var isLoading = false + @Published var profileCardData = ProfileCardData() + + enum Action { + case logout + case loadProfileData + case showIntercomMessenger + case deleteAccount + } + + var subscriptions = Set() + let performActionSubject = PassthroughSubject() + + init() {} +} + +struct ProfileContainerView: View { + @ObservedObject private var viewModel: ProfileContainerViewModel + @State private var showLogoutConfirmation = false + + init(viewModel: ProfileContainerViewModel) { + self.viewModel = viewModel + } + + var body: some View { + #if os(iOS) + Form { + innerBody + } + #elseif os(macOS) + List { + innerBody + } + .listStyle(InsetListStyle()) + #endif + } + + private var innerBody: some View { + Group { + Section { + ProfileCard(data: viewModel.profileCardData) + .onAppear { + viewModel.performActionSubject.send(.loadProfileData) + } + } + + Section { + NavigationLink(destination: BasicWebAppView.privacyPolicyWebView) { + Text("Privacy Policy") + } + + NavigationLink(destination: BasicWebAppView.termsConditionsWebView) { + Text("Terms and Conditions") + } + + #if os(iOS) + Button( + action: { + viewModel.performActionSubject.send(.showIntercomMessenger) + }, + label: { Text("Feedback") } + ) + #endif + } + + Section { + if FeatureFlag.showAccountDeletion { + NavigationLink( + destination: ManageAccountView(handleAccountDeletion: { + viewModel.performActionSubject.send(.deleteAccount) + }) + ) { + Text("Manage Account") + } + } + + Text("Logout") + .onTapGesture { + showLogoutConfirmation = true + } + .alert(isPresented: $showLogoutConfirmation) { + Alert( + title: Text("Are you sure you want to logout?"), + primaryButton: .destructive(Text("Confirm")) { + viewModel.performActionSubject.send(.logout) + }, + secondaryButton: .cancel() + ) + } + } + } + .navigationTitle("Profile") + } +} + +private extension BasicWebAppView { + static let privacyPolicyWebView: BasicWebAppView = { + omnivoreWebView(path: "privacy") + }() + + static let termsConditionsWebView: BasicWebAppView = { + omnivoreWebView(path: "terms") + }() + + private static func omnivoreWebView(path: String) -> BasicWebAppView { + let urlString = "https://omnivore.app/\(path)?isAppEmbedView=true" + return BasicWebAppView(request: URLRequest(url: URL(string: urlString)!)) + } +} diff --git a/apple/OmnivoreKit/Sources/Binders/Views/HomeFeedView.swift b/apple/OmnivoreKit/Sources/Binders/Views/HomeFeedView.swift index d93a78a13..5b0706d57 100644 --- a/apple/OmnivoreKit/Sources/Binders/Views/HomeFeedView.swift +++ b/apple/OmnivoreKit/Sources/Binders/Views/HomeFeedView.swift @@ -12,9 +12,11 @@ extension HomeFeedViewModel { LinkItemDetailViewModel.make(feedItem: feedItem, services: services) } - if UIDevice.isIPhone { - viewModel.profileContainerViewModel = ProfileContainerViewModel.make(services: services) - } + #if os(iOS) + if UIDevice.isIPhone { + viewModel.profileContainerViewModel = ProfileContainerViewModel.make(services: services) + } + #endif viewModel.bind(services: services) viewModel.loadItems(dataService: services.dataService, searchQuery: nil, isRefresh: false) diff --git a/apple/OmnivoreKit/Sources/Views/PrimaryContainerViews/Profile/ProfileCard.swift b/apple/OmnivoreKit/Sources/Views/PrimaryContainerViews/Profile/ProfileCard.swift index b2d415805..a27ad3857 100644 --- a/apple/OmnivoreKit/Sources/Views/PrimaryContainerViews/Profile/ProfileCard.swift +++ b/apple/OmnivoreKit/Sources/Views/PrimaryContainerViews/Profile/ProfileCard.swift @@ -12,10 +12,14 @@ public struct ProfileCardData { } } -struct ProfileCard: View { +public struct ProfileCard: View { let data: ProfileCardData - var body: some View { + public init(data: ProfileCardData) { + self.data = data + } + + public var body: some View { HStack(alignment: .center) { Group { if let url = data.imageURL { diff --git a/apple/OmnivoreKit/Sources/Views/PrimaryContainerViews/Profile/ProfileContainerView.swift b/apple/OmnivoreKit/Sources/Views/PrimaryContainerViews/Profile/ProfileContainerView.swift index 3c3a9fc16..8b1378917 100644 --- a/apple/OmnivoreKit/Sources/Views/PrimaryContainerViews/Profile/ProfileContainerView.swift +++ b/apple/OmnivoreKit/Sources/Views/PrimaryContainerViews/Profile/ProfileContainerView.swift @@ -1,115 +1 @@ -import Combine -import Models -import SwiftUI -import Utils -public final class ProfileContainerViewModel: ObservableObject { - @Published public var isLoading = false - @Published public var profileCardData = ProfileCardData() - - public enum Action { - case logout - case loadProfileData - case showIntercomMessenger - case deleteAccount - } - - public var subscriptions = Set() - public let performActionSubject = PassthroughSubject() - - public init() {} -} - -public struct ProfileContainerView: View { - @ObservedObject private var viewModel: ProfileContainerViewModel - @State private var showLogoutConfirmation = false - - public init(viewModel: ProfileContainerViewModel) { - self.viewModel = viewModel - } - - public var body: some View { - #if os(iOS) - Form { - innerBody - } - #elseif os(macOS) - List { - innerBody - } - .listStyle(InsetListStyle()) - #endif - } - - private var innerBody: some View { - Group { - Section { - ProfileCard(data: viewModel.profileCardData) - .onAppear { - viewModel.performActionSubject.send(.loadProfileData) - } - } - - Section { - NavigationLink(destination: BasicWebAppView.privacyPolicyWebView) { - Text("Privacy Policy") - } - - NavigationLink(destination: BasicWebAppView.termsConditionsWebView) { - Text("Terms and Conditions") - } - - #if os(iOS) - Button( - action: { - viewModel.performActionSubject.send(.showIntercomMessenger) - }, - label: { Text("Feedback") } - ) - #endif - } - - Section { - if FeatureFlag.showAccountDeletion { - NavigationLink( - destination: ManageAccountView(handleAccountDeletion: { - viewModel.performActionSubject.send(.deleteAccount) - }) - ) { - Text("Manage Account") - } - } - - Text("Logout") - .onTapGesture { - showLogoutConfirmation = true - } - .alert(isPresented: $showLogoutConfirmation) { - Alert( - title: Text("Are you sure you want to logout?"), - primaryButton: .destructive(Text("Confirm")) { - viewModel.performActionSubject.send(.logout) - }, - secondaryButton: .cancel() - ) - } - } - } - .navigationTitle("Profile") - } -} - -private extension BasicWebAppView { - static let privacyPolicyWebView: BasicWebAppView = { - omnivoreWebView(path: "privacy") - }() - - static let termsConditionsWebView: BasicWebAppView = { - omnivoreWebView(path: "terms") - }() - - private static func omnivoreWebView(path: String) -> BasicWebAppView { - let urlString = "https://omnivore.app/\(path)?isAppEmbedView=true" - return BasicWebAppView(request: URLRequest(url: URL(string: urlString)!)) - } -} diff --git a/apple/OmnivoreKit/Sources/Views/UserSettings/ManageAccountView.swift b/apple/OmnivoreKit/Sources/Views/UserSettings/ManageAccountView.swift index 247860487..1b6d589ca 100644 --- a/apple/OmnivoreKit/Sources/Views/UserSettings/ManageAccountView.swift +++ b/apple/OmnivoreKit/Sources/Views/UserSettings/ManageAccountView.swift @@ -1,10 +1,14 @@ import SwiftUI -struct ManageAccountView: View { +public struct ManageAccountView: View { let handleAccountDeletion: () -> Void @State private var showDeleteAccountConfirmation = false - var body: some View { + public init(handleAccountDeletion: @escaping () -> Void) { + self.handleAccountDeletion = handleAccountDeletion + } + + public var body: some View { Button( action: { showDeleteAccountConfirmation = true diff --git a/apple/OmnivoreKit/Sources/Views/Utils/MacOSSizeClass.swift b/apple/OmnivoreKit/Sources/Views/Utils/MacOSSizeClass.swift index 85c3adff9..f53d08f91 100644 --- a/apple/OmnivoreKit/Sources/Views/Utils/MacOSSizeClass.swift +++ b/apple/OmnivoreKit/Sources/Views/Utils/MacOSSizeClass.swift @@ -8,20 +8,20 @@ import SwiftUI // https://stackoverflow.com/questions/63526478/swiftui-userinterfacesizeclass-for-universal-macos-ios-views #if os(macOS) - enum UserInterfaceSizeClass { + public enum UserInterfaceSizeClass { case compact case regular } - struct HorizontalSizeClassEnvironmentKey: EnvironmentKey { - static let defaultValue: UserInterfaceSizeClass = .regular + public struct HorizontalSizeClassEnvironmentKey: EnvironmentKey { + public static let defaultValue: UserInterfaceSizeClass = .regular } - struct VerticalSizeClassEnvironmentKey: EnvironmentKey { - static let defaultValue: UserInterfaceSizeClass = .regular + public struct VerticalSizeClassEnvironmentKey: EnvironmentKey { + public static let defaultValue: UserInterfaceSizeClass = .regular } - extension EnvironmentValues { + public extension EnvironmentValues { var horizontalSizeClass: UserInterfaceSizeClass { get { self[HorizontalSizeClassEnvironmentKey.self] } set { self[HorizontalSizeClassEnvironmentKey.self] = newValue } diff --git a/apple/OmnivoreKit/Sources/Views/Web/BasicWebAppView.swift b/apple/OmnivoreKit/Sources/Views/Web/BasicWebAppView.swift index ae4231c4a..370760116 100644 --- a/apple/OmnivoreKit/Sources/Views/Web/BasicWebAppView.swift +++ b/apple/OmnivoreKit/Sources/Views/Web/BasicWebAppView.swift @@ -2,22 +2,26 @@ import SwiftUI import WebKit #if os(iOS) - struct BasicWebAppView: UIViewRepresentable { + public struct BasicWebAppView: UIViewRepresentable { let request: URLRequest let webView = WKWebView() - func makeCoordinator() -> BasicWebAppViewCoordinator { + public init(request: URLRequest) { + self.request = request + } + + public func makeCoordinator() -> BasicWebAppViewCoordinator { BasicWebAppViewCoordinator() } - func makeUIView(context _: Context) -> WKWebView { + public func makeUIView(context _: Context) -> WKWebView { webView.scrollView.isScrollEnabled = true webView.isOpaque = false webView.backgroundColor = UIColor.clear return webView } - func updateUIView(_ webView: WKWebView, context: Context) { + public func updateUIView(_ webView: WKWebView, context: Context) { if context.coordinator.needsReload { webView.load(request) context.coordinator.needsReload = false @@ -27,18 +31,22 @@ import WebKit #endif #if os(macOS) - struct BasicWebAppView: NSViewRepresentable { + public struct BasicWebAppView: NSViewRepresentable { let request: URLRequest - func makeCoordinator() -> BasicWebAppViewCoordinator { + public init(request: URLRequest) { + self.request = request + } + + public func makeCoordinator() -> BasicWebAppViewCoordinator { BasicWebAppViewCoordinator() } - func makeNSView(context _: Context) -> WKWebView { + public func makeNSView(context _: Context) -> WKWebView { WebView(frame: CGRect.zero) } - func updateNSView(_ webView: WKWebView, context: Context) { + public func updateNSView(_ webView: WKWebView, context: Context) { if context.coordinator.needsReload { webView.load(request) context.coordinator.needsReload = false @@ -47,7 +55,7 @@ import WebKit } #endif -final class BasicWebAppViewCoordinator: NSObject { +public final class BasicWebAppViewCoordinator: NSObject { var needsReload = true override init() {