diff --git a/Swiftgram/SGDebugUI/Sources/SGDebugUI.swift b/Swiftgram/SGDebugUI/Sources/SGDebugUI.swift index 2fd9a61543..dd852e384c 100644 --- a/Swiftgram/SGDebugUI/Sources/SGDebugUI.swift +++ b/Swiftgram/SGDebugUI/Sources/SGDebugUI.swift @@ -159,17 +159,14 @@ public func sgDebugController(context: AccountContext) -> ViewController { } #endif case .restorePurchases: - context.sharedContext.SGIAP?.restorePurchases { - DispatchQueue.main.async { - presentControllerImpl?(UndoOverlayController( - presentationData: presentationData, - content: .info(title: nil, text: "PayWall.Button.Restoring".i18n(args: context.sharedContext.currentPresentationData.with { $0 }.strings.baseLanguageCode), timeout: nil, customUndoText: nil), - elevatedLayout: false, - action: { _ in return false } - ), - nil) - } - } + presentControllerImpl?(UndoOverlayController( + presentationData: presentationData, + content: .info(title: nil, text: "PayWall.Button.Restoring".i18n(args: context.sharedContext.currentPresentationData.with { $0 }.strings.baseLanguageCode), timeout: nil, customUndoText: nil), + elevatedLayout: false, + action: { _ in return false } + ), + nil) + context.sharedContext.SGIAP?.restorePurchases {} case .setIAP: #if DEBUG #endif diff --git a/Swiftgram/SGPayWall/Sources/SGPayWall.swift b/Swiftgram/SGPayWall/Sources/SGPayWall.swift index 82087f36ad..2a1ae85504 100644 --- a/Swiftgram/SGPayWall/Sources/SGPayWall.swift +++ b/Swiftgram/SGPayWall/Sources/SGPayWall.swift @@ -13,7 +13,7 @@ import TelegramUIPreferences @available(iOS 13.0, *) -public func sgPayWallController(statusSignal: Signal, replacementController: ViewController, presentationData: PresentationData? = nil, SGIAPManager: SGIAPManager, openUrl: @escaping (String) -> Void, paymentsEnabled: Bool, canBuyInBeta: Bool, openAppStorePage: @escaping () -> Void) -> ViewController { +public func sgPayWallController(statusSignal: Signal, replacementController: ViewController, presentationData: PresentationData? = nil, SGIAPManager: SGIAPManager, openUrl: @escaping (String, Bool) -> Void /* url, forceExternal */, paymentsEnabled: Bool, canBuyInBeta: Bool, openAppStorePage: @escaping () -> Void, proSupportUrl: String?) -> ViewController { // let theme = presentationData?.theme ?? (UITraitCollection.current.userInterfaceStyle == .dark ? defaultDarkColorPresentationTheme : defaultPresentationTheme) let theme = defaultDarkColorPresentationTheme let strings = presentationData?.strings ?? defaultPresentationStrings @@ -31,7 +31,7 @@ public func sgPayWallController(statusSignal: Signal, replacemen let swiftUIView = SGSwiftUIView( legacyController: legacyController, content: { - SGPayWallView(wrapperController: legacyController, replacementController: replacementController, SGIAP: SGIAPManager, statusSignal: statusSignal, openUrl: openUrl, openAppStorePage: openAppStorePage, paymentsEnabled: paymentsEnabled, canBuyInBeta: canBuyInBeta) + SGPayWallView(wrapperController: legacyController, replacementController: replacementController, SGIAP: SGIAPManager, statusSignal: statusSignal, openUrl: openUrl, openAppStorePage: openAppStorePage, paymentsEnabled: paymentsEnabled, canBuyInBeta: canBuyInBeta, proSupportUrl: proSupportUrl) } ) let controller = UIHostingController(rootView: swiftUIView, ignoreSafeArea: true) @@ -101,7 +101,7 @@ struct SGPayWallFeatureDetails: View { let dismissAction: () -> Void var bottomOffset: CGFloat = 0.0 - let contentHeight: CGFloat = 666.0 // heh + let contentHeight: CGFloat = 690.0 let features: [SGProFeature] @State var shownFeature: SGProFeatureId? @@ -326,10 +326,11 @@ struct SGPayWallView: View { let replacementController: ViewController let SGIAP: SGIAPManager let statusSignal: Signal - let openUrl: (String) -> Void + let openUrl: (String, Bool) -> Void // url, forceExternal let openAppStorePage: () -> Void let paymentsEnabled: Bool let canBuyInBeta: Bool + let proSupportUrl: String? private enum PayWallState: Equatable { case ready // ready to buy @@ -519,20 +520,36 @@ struct SGPayWallView: View { private var purchaseSection: some View { VStack(spacing: 0) { Divider() - - Button(action: handlePurchase) { - Text(buttonTitle) - .fontWeight(.semibold) - .frame(maxWidth: .infinity) - .padding() - .background(Color(hex: accentColorHex)) - .foregroundColor(.white) - .cornerRadius(12) + VStack(spacing: 8) { + Button(action: handlePurchase) { + Text(buttonTitle) + .fontWeight(.semibold) + .frame(maxWidth: .infinity) + .padding() + .background(Color(hex: accentColorHex)) + .foregroundColor(.white) + .cornerRadius(12) + } + .disabled((state != .ready || !canPurchase) && !(currentStatus > 1)) + .opacity(((state != .ready || !canPurchase) && !(currentStatus > 1)) ? 0.5 : 1.0) + + if let proSupportUrl = proSupportUrl { + HStack(alignment: .center, spacing: 4) { + Text("PayWall.ProSupport.Title".i18n(lang)) + .font(.caption) + .foregroundColor(.secondary) + Button(action: { + openUrl(proSupportUrl, false) + }) { + Text("PayWall.ProSupport.Contact".i18n(lang)) + .font(.caption) + .foregroundColor(Color(hex: accentColorHex)) + } + } + } } - .disabled((state != .ready || !canPurchase) && !(currentStatus > 1)) - .opacity(((state != .ready || !canPurchase) && !(currentStatus > 1)) ? 0.5 : 1.0) .padding([.horizontal, .top]) - .padding(.bottom, sgBottomSafeAreaInset(containerViewLayout)) + .padding(.bottom, sgBottomSafeAreaInset(containerViewLayout) + 2.0) } .foregroundColor(Color.black) .backgroundIfAvailable(material: .ultraThinMaterial) @@ -547,7 +564,7 @@ struct SGPayWallView: View { .tint(Color(hex: accentColorHex)) .foregroundColor(.secondary) .environment(\.openURL, OpenURLAction { url in - openUrl(url.absoluteString) + openUrl(url.absoluteString, false) return .handled }) } else { @@ -556,14 +573,14 @@ struct SGPayWallView: View { .foregroundColor(.secondary) HStack(alignment: .top, spacing: 8) { Button(action: { - openUrl("PayWall.PrivacyURL".i18n(lang)) + openUrl("PayWall.PrivacyURL".i18n(lang), true) }) { Text("PayWall.Privacy".i18n(lang)) .font(.caption) .foregroundColor(Color(hex: accentColorHex)) } Button(action: { - openUrl("PayWall.TermsURL".i18n(lang)) + openUrl("PayWall.TermsURL".i18n(lang), true) }) { Text("PayWall.Terms".i18n(lang)) .font(.caption) @@ -592,7 +609,7 @@ struct SGPayWallView: View { } HStack { Button(action: { - openUrl("PayWall.About.SignatureURL".i18n(lang)) + openUrl("PayWall.About.SignatureURL".i18n(lang), false) }) { Text("PayWall.About.Signature".i18n(lang)) .font(.caption) diff --git a/Swiftgram/SGStrings/Strings/en.lproj/SGLocalizable.strings b/Swiftgram/SGStrings/Strings/en.lproj/SGLocalizable.strings index 28284484e3..c7f70b4559 100644 --- a/Swiftgram/SGStrings/Strings/en.lproj/SGLocalizable.strings +++ b/Swiftgram/SGStrings/Strings/en.lproj/SGLocalizable.strings @@ -214,10 +214,14 @@ "PayWall.About.Title" = "About Swiftgram Pro"; "PayWall.About.Notice" = "Free version of Swiftgram provides dozens of features and improvements over Telegram app. Innovating and keeping Swiftgram in sync with monthly Telegram updates is a huge effort that requires a lot of time and expensive hardware.\n\nSwiftgram is an open-source app that respects your privacy and doesn't bother you with ads. Subscribing to Swiftgram Pro you get access to exclusive features and support an independent developer."; +/* DO NOT TRANSLATE */ "PayWall.About.Signature" = "@Kylmakalle"; /* DO NOT TRANSLATE */ "PayWall.About.SignatureURL" = "https://t.me/Kylmakalle"; +"PayWall.ProSupport.Title" = "Troubles with payment?"; +"PayWall.ProSupport.Contact" = "No worries!"; + "PayWall.RestorePurchases" = "Restore Purchases"; "PayWall.Terms" = "Terms of Service"; "PayWall.Privacy" = "Privacy Policy"; diff --git a/Swiftgram/SGWebSettingsScheme/Sources/File.swift b/Swiftgram/SGWebSettingsScheme/Sources/File.swift index c61f4b1a63..b8e976e99f 100644 --- a/Swiftgram/SGWebSettingsScheme/Sources/File.swift +++ b/Swiftgram/SGWebSettingsScheme/Sources/File.swift @@ -5,7 +5,7 @@ public struct SGWebSettings: Codable, Equatable { public let user: SGUserSettings public static var defaultValue: SGWebSettings { - return SGWebSettings(global: SGGlobalSettings(ytPip: true, qrLogin: true, storiesAvailable: false, canViewMessages: true, canEditSettings: false, canShowTelescope: false, announcementsData: nil, regdateFormat: "month", botMonkeys: [], forceReasons: [], unforceReasons: [], paymentsEnabled: true, duckyAppIconAvailable: true, canGrant: false), user: SGUserSettings(contentReasons: [], canSendTelescope: false, canBuyInBeta: true)) + return SGWebSettings(global: SGGlobalSettings(ytPip: true, qrLogin: true, storiesAvailable: false, canViewMessages: true, canEditSettings: false, canShowTelescope: false, announcementsData: nil, regdateFormat: "month", botMonkeys: [], forceReasons: [], unforceReasons: [], paymentsEnabled: true, duckyAppIconAvailable: true, canGrant: false, proSupportUrl: nil), user: SGUserSettings(contentReasons: [], canSendTelescope: false, canBuyInBeta: true)) } } @@ -24,6 +24,7 @@ public struct SGGlobalSettings: Codable, Equatable { public let paymentsEnabled: Bool public let duckyAppIconAvailable: Bool public let canGrant: Bool + public let proSupportUrl: String? } public struct SGBotMonkeys: Codable, Equatable { diff --git a/submodules/TelegramUI/Sources/OpenUrl.swift b/submodules/TelegramUI/Sources/OpenUrl.swift index 1afe709df5..c8976a7f87 100644 --- a/submodules/TelegramUI/Sources/OpenUrl.swift +++ b/submodules/TelegramUI/Sources/OpenUrl.swift @@ -4,6 +4,8 @@ import SGConfig import SGSettingsUI import SGDebugUI import SFSafariViewControllerPlus +import UndoUI +// import ContactListUI import Foundation import Display @@ -1041,6 +1043,33 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur } } } + case "restart": + let presentationData = context.sharedContext.currentPresentationData.with { $0 } + let lang = presentationData.strings.baseLanguageCode + context.sharedContext.presentGlobalController( + UndoOverlayController( + presentationData: presentationData, + content: .info(title: nil, + text: "Common.RestartRequired".i18n(lang), + timeout: nil, + customUndoText: "Common.RestartNow".i18n(lang) + ), + elevatedLayout: false, + action: { action in if action == .undo { exit(0) }; return true } + ), + nil + ) + case "restore_purchases", "pro_restore", "validate", "restore": + let presentationData = context.sharedContext.currentPresentationData.with { $0 } + let lang = presentationData.strings.baseLanguageCode + context.sharedContext.presentGlobalController(UndoOverlayController( + presentationData: presentationData, + content: .info(title: nil, text: "PayWall.Button.Restoring".i18n(lang), timeout: nil, customUndoText: nil), + elevatedLayout: false, + action: { _ in return false } + ), + nil) + context.sharedContext.SGIAP?.restorePurchases {} default: break } diff --git a/submodules/TelegramUI/Sources/SharedAccountContext.swift b/submodules/TelegramUI/Sources/SharedAccountContext.swift index 8378530671..b1cc4a7866 100644 --- a/submodules/TelegramUI/Sources/SharedAccountContext.swift +++ b/submodules/TelegramUI/Sources/SharedAccountContext.swift @@ -3625,7 +3625,23 @@ extension SharedAccountContextImpl { let proController = self.makeSGProController(context: context) let sgWebSettings = context.currentAppConfiguration.with { $0 }.sgWebSettings - let payWallController = sgPayWallController(statusSignal: statusSignal, replacementController: proController, presentationData: self.currentPresentationData.with { $0 }, SGIAPManager: sgIAP, openUrl: self.applicationBindings.openUrl, paymentsEnabled: sgWebSettings.global.paymentsEnabled, canBuyInBeta: sgWebSettings.user.canBuyInBeta, openAppStorePage: self.applicationBindings.openAppStorePage) + let presentationData = self.currentPresentationData.with { $0 } + var payWallController: ViewController? = nil + let openUrl: ((String, Bool) -> Void) = { [weak self, weak context] url, forceExternal in + guard let strongSelf = self, let strongContext = context, let strongPayWallController = payWallController else { + return + } + let navigationController = strongPayWallController.navigationController as? NavigationController + Queue.mainQueue().async { + strongSelf.openExternalUrl(context: strongContext, urlContext: .generic, url: url, forceExternal: forceExternal, presentationData: presentationData, navigationController: navigationController, dismissInput: {}) + } + } + + var supportUrl: String? = nil + if let supportUrlString = sgWebSettings.global.proSupportUrl, !supportUrlString.isEmpty, let data = Data(base64Encoded: supportUrlString), let decodedString = String(data: data, encoding: .utf8) { + supportUrl = decodedString + } + payWallController = sgPayWallController(statusSignal: statusSignal, replacementController: proController, presentationData: presentationData, SGIAPManager: sgIAP, openUrl: openUrl, paymentsEnabled: sgWebSettings.global.paymentsEnabled, canBuyInBeta: sgWebSettings.user.canBuyInBeta, openAppStorePage: self.applicationBindings.openAppStorePage, proSupportUrl: supportUrl) return payWallController }