move ProfileContainerViewModel into Binders package
This commit is contained in:
@ -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<AnyCancellable>()
|
||||
let performActionSubject = PassthroughSubject<Action, Never>()
|
||||
|
||||
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)!))
|
||||
}
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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<AnyCancellable>()
|
||||
public let performActionSubject = PassthroughSubject<Action, Never>()
|
||||
|
||||
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)!))
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 }
|
||||
|
||||
@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user