diff --git a/Passepartout.xcodeproj/project.pbxproj b/Passepartout.xcodeproj/project.pbxproj index b180dd75..35bc3ade 100644 --- a/Passepartout.xcodeproj/project.pbxproj +++ b/Passepartout.xcodeproj/project.pbxproj @@ -68,7 +68,6 @@ 0E9AA978259F756A003FAFF1 /* PacketTunnelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9AA977259F756A003FAFF1 /* PacketTunnelProvider.swift */; }; 0E9C233027F47032007D5FC7 /* IntentsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9C232F27F47032007D5FC7 /* IntentsManager.swift */; }; 0E9C233327F47E95007D5FC7 /* IntentDispatcher+Activities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9C233227F47E95007D5FC7 /* IntentDispatcher+Activities.swift */; }; - 0E9C3B6C27FB3A9C00D0F02E /* ReloadingContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9C3B6B27FB3A9C00D0F02E /* ReloadingContent.swift */; }; 0E9C3B6F27FC573E00D0F02E /* CloudKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0E9C3B6E27FC573E00D0F02E /* CloudKit.framework */; }; 0E9E5AEF27B44CF1008C95DA /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0E9E5AE227B44CF1008C95DA /* Localizable.strings */; }; 0E9ED48127FD9BAE003B2316 /* CopySavingButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9ED48027FD9BAE003B2316 /* CopySavingButton.swift */; }; @@ -250,7 +249,6 @@ 0E9AA977259F756A003FAFF1 /* PacketTunnelProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PacketTunnelProvider.swift; sourceTree = ""; }; 0E9C232F27F47032007D5FC7 /* IntentsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntentsManager.swift; sourceTree = ""; }; 0E9C233227F47E95007D5FC7 /* IntentDispatcher+Activities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "IntentDispatcher+Activities.swift"; sourceTree = ""; }; - 0E9C3B6B27FB3A9C00D0F02E /* ReloadingContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReloadingContent.swift; sourceTree = ""; }; 0E9C3B6E27FC573E00D0F02E /* CloudKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CloudKit.framework; path = System/Library/Frameworks/CloudKit.framework; sourceTree = SDKROOT; }; 0E9E5AE327B44CF1008C95DA /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; 0E9E5AE427B44CF1008C95DA /* el */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = el; path = el.lproj/Localizable.strings; sourceTree = ""; }; @@ -382,7 +380,6 @@ 0ED89C1627DE0E05008B36D6 /* IntentEditView.swift */, 0E5324A827D2AC55002565C3 /* LongContentView.swift */, 0EBC075427EBC83800208AD9 /* MailComposerView.swift */, - 0E9C3B6B27FB3A9C00D0F02E /* ReloadingContent.swift */, 0ED30DCB27EA197C0057D8A3 /* RevealingSecureField.swift */, 0E2C172A27CB63F9007E8488 /* Reviewer.swift */, 0ED89C1427DE0A0C008B36D6 /* Shortcut.swift */, @@ -902,7 +899,6 @@ 0EF2213127E674BD001D0BD7 /* AddProviderViewModel.swift in Sources */, 0E90DFE627BACC1500EF5078 /* AddHostViewModel.swift in Sources */, 0E34AC8227F892C40042F2AB /* OnDemandView+SSID.swift in Sources */, - 0E9C3B6C27FB3A9C00D0F02E /* ReloadingContent.swift in Sources */, 0E5324A627D297BB002565C3 /* InApp.swift in Sources */, 0E3B7FCD27E47B3700C66F13 /* AddHostView.swift in Sources */, 0EF2212D27E66EB5001D0BD7 /* AddProviderView.swift in Sources */, diff --git a/Passepartout.xcodeproj/xcshareddata/xcschemes/Passepartout.xcscheme b/Passepartout.xcodeproj/xcshareddata/xcschemes/Passepartout.xcscheme index 8649b99f..5824feb5 100644 --- a/Passepartout.xcodeproj/xcshareddata/xcschemes/Passepartout.xcscheme +++ b/Passepartout.xcodeproj/xcshareddata/xcschemes/Passepartout.xcscheme @@ -126,7 +126,7 @@ . -// - -import SwiftUI - -struct ReloadingContent: View { - @Environment(\.scenePhase) private var scenePhase - - @ObservedObject private var object: O - - private let keyPath: KeyPath - - private var elements: [T] { - object[keyPath: keyPath] - } - - private let equality: ([T], [T]) -> Bool - - private let reload: (() -> Void)? - - @ViewBuilder private let content: ([T]) -> Content - - @State private var localElements: [T] = [] - - init( - observing object: O, - on keyPath: KeyPath, - equality: @escaping ([T], [T]) -> Bool = { $0 == $1 }, - reload: (() -> Void)? = nil, - @ViewBuilder content: @escaping ([T]) -> Content - ) { - self.object = object - self.keyPath = keyPath - self.equality = equality - self.reload = reload - self.content = content - - // XXX: not sure about this, but if content() is empty .onAppear() will - // never trigger, thus never setting initial elements - // - // BEWARE: localElements will not be automatically bound to changes - // in elements (use a Binding for that), but this is actually intended - _localElements = State(initialValue: elements) - if elements.isEmpty { - reload?() - } - } - - var body: some View { - debugChanges() - return Group { - content(localElements) -// }.onAppear { -// localElements = elements -// if localElements.isEmpty { -// reload?() -// } - }.onChange(of: elements) { newElements in - guard !equality(localElements, newElements) else { - return - } - withAnimation { - localElements = newElements - } - }.onChange(of: scenePhase) { - if $0 == .active { - reload?() - } - } - } -} diff --git a/Passepartout/App/Views/DonateView.swift b/Passepartout/App/Views/DonateView.swift index 4511459c..5977f72f 100644 --- a/Passepartout/App/Views/DonateView.swift +++ b/Passepartout/App/Views/DonateView.swift @@ -44,6 +44,8 @@ struct DonateView: View { @Environment(\.presentationMode) private var presentationMode + @Environment(\.scenePhase) private var scenePhase + @ObservedObject private var productManager: ProductManager @State private var alertType: AlertType? @@ -63,6 +65,15 @@ struct DonateView: View { .toolbar { themeCloseItem(presentationMode: presentationMode) }.alert(item: $alertType, content: presentedAlert) + + // reloading + .onAppear { + productManager.refreshProducts() + }.onChange(of: scenePhase) { newValue in + if newValue == .active { + productManager.refreshProducts() + } + }.animation(.default, value: productManager.isRefreshingProducts) } private func presentedAlert(_ alertType: AlertType) -> Alert { @@ -89,17 +100,10 @@ struct DonateView: View { footer: Text(L10n.Donate.Sections.OneTime.footer) .xxxThemeTruncation() ) { - ReloadingContent( - observing: productManager, - on: \.donations, - equality: { - Set($0.map(\.productIdentifier)) == Set($1.map(\.productIdentifier)) - }, - reload: { - productManager.refreshProducts() - } - ) { - ForEach($0, id: \.productIdentifier, content: productRow) + if !productManager.isRefreshingProducts { + ForEach(productManager.donations, id: \.productIdentifier, content: productRow) + } else { + ProgressView() } } } diff --git a/Passepartout/App/Views/PaywallView+Purchase.swift b/Passepartout/App/Views/PaywallView+Purchase.swift index 952d4a50..4ffa956b 100644 --- a/Passepartout/App/Views/PaywallView+Purchase.swift +++ b/Passepartout/App/Views/PaywallView+Purchase.swift @@ -75,6 +75,15 @@ extension PaywallView { .disabled(purchaseState != nil) }.navigationTitle(Unlocalized.appName) .alert(item: $alertType, content: presentedAlert) + + // reloading + .onAppear { + productManager.refreshProducts() + }.onChange(of: scenePhase) { newValue in + if newValue == .active { + productManager.refreshProducts() + } + }.animation(.default, value: productManager.isRefreshingProducts) } private func presentedAlert(_ alertType: AlertType) -> Alert { @@ -104,19 +113,12 @@ extension PaywallView { header: Text(L10n.Paywall.title), footer: Text(L10n.Paywall.Sections.Products.footer) ) { - ReloadingContent( - observing: productManager, - on: \.products, - equality: { - Set($0.map(\.productIdentifier)) == Set($1.map(\.productIdentifier)) - }, - reload: { - productManager.refreshProducts() - } - ) { _ in + if !productManager.isRefreshingProducts { ForEach(productRowModels, id: \.product.productIdentifier, content: productRow) - restoreRow + } else { + ProgressView() } + restoreRow } }