diff --git a/submodules/AccountContext/Sources/AccountContext.swift b/submodules/AccountContext/Sources/AccountContext.swift index 288232c512..d7b3ecb81a 100644 --- a/submodules/AccountContext/Sources/AccountContext.swift +++ b/submodules/AccountContext/Sources/AccountContext.swift @@ -305,6 +305,7 @@ public enum ResolvedUrl { case startAttach(peerId: PeerId, payload: String?, choose: ResolvedBotChoosePeerTypes?) case invoice(slug: String, invoice: TelegramMediaInvoice?) case premiumOffer(reference: String?) + case starsTopup(amount: Int64?) case chatFolder(slug: String) case story(peerId: PeerId, id: Int32) case boost(peerId: PeerId?, status: ChannelBoostStatus?, myBoostStatus: MyBoostStatus?) diff --git a/submodules/AccountContext/Sources/Premium.swift b/submodules/AccountContext/Sources/Premium.swift index 52ee4ce8d4..183c5aeea7 100644 --- a/submodules/AccountContext/Sources/Premium.swift +++ b/submodules/AccountContext/Sources/Premium.swift @@ -123,7 +123,7 @@ public enum BoostSubject: Equatable { } public enum StarsPurchasePurpose: Equatable { - case generic + case generic(requiredStars: Int64?) case transfer(peerId: EnginePeer.Id, requiredStars: Int64) case subscription(peerId: EnginePeer.Id, requiredStars: Int64, renew: Bool) case gift(peerId: EnginePeer.Id) diff --git a/submodules/AttachmentUI/Sources/AttachmentController.swift b/submodules/AttachmentUI/Sources/AttachmentController.swift index 9841bfd570..60646efeb7 100644 --- a/submodules/AttachmentUI/Sources/AttachmentController.swift +++ b/submodules/AttachmentUI/Sources/AttachmentController.swift @@ -713,7 +713,7 @@ public class AttachmentController: ViewController, MinimizableController { } if case .ended = recognizer.state { if let lastController = self.currentControllers.last { - if let controller = self.controller, controller.shouldMinimizeOnSwipe?(self.currentType) == true { + if let controller = self.controller, let layout = self.validLayout, !layout.metrics.isTablet, controller.shouldMinimizeOnSwipe?(self.currentType) == true { self.minimize() return } diff --git a/submodules/BrowserUI/BUILD b/submodules/BrowserUI/BUILD index b49526f0c2..9f7432956e 100644 --- a/submodules/BrowserUI/BUILD +++ b/submodules/BrowserUI/BUILD @@ -48,6 +48,7 @@ swift_library( "//submodules/SearchBarNode", "//submodules/TelegramUI/Components/SaveProgressScreen", "//submodules/TelegramUI/Components/ListActionItemComponent", + "//submodules/Utils/DeviceModel", ], visibility = [ "//visibility:public", diff --git a/submodules/BrowserUI/Sources/BrowserWebContent.swift b/submodules/BrowserUI/Sources/BrowserWebContent.swift index 51f7e365d1..3886d877d0 100644 --- a/submodules/BrowserUI/Sources/BrowserWebContent.swift +++ b/submodules/BrowserUI/Sources/BrowserWebContent.swift @@ -20,6 +20,7 @@ import MultilineTextComponent import UrlEscaping import UrlHandling import SaveProgressScreen +import DeviceModel private final class TonSchemeHandler: NSObject, WKURLSchemeHandler { private final class PendingTask { @@ -151,6 +152,22 @@ private class WeakScriptMessageHandler: NSObject, WKScriptMessageHandler { } } +private func computedUserAgent() -> String { + func getFirmwareVersion() -> String? { + var size = 0 + sysctlbyname("kern.osversion", nil, &size, nil, 0) + + var str = [CChar](repeating: 0, count: size) + sysctlbyname("kern.osversion", &str, &size, nil, 0) + + return String(cString: str) + } + + let osVersion = UIDevice.current.systemVersion + let firmwareVersion = getFirmwareVersion() ?? "15E148" + return DeviceModel.current.isIpad ? "Version/\(osVersion) Safari/605.1.15" : "Version/\(osVersion) Mobile/\(firmwareVersion) Safari/604.1" +} + final class BrowserWebContent: UIView, BrowserContent, WKNavigationDelegate, WKUIDelegate, UIScrollViewDelegate { private let context: AccountContext private var presentationData: PresentationData @@ -211,6 +228,7 @@ final class BrowserWebContent: UIView, BrowserContent, WKNavigationDelegate, WKU let touchScript = WKUserScript(source: setupTouchObservers, injectionTime: .atDocumentStart, forMainFrameOnly: false) contentController.addUserScript(touchScript) configuration.userContentController = contentController + configuration.applicationNameForUserAgent = computedUserAgent() var handleScriptMessageImpl: ((WKScriptMessage) -> Void)? let eventProxyScript = WKUserScript(source: eventProxySource, injectionTime: .atDocumentStart, forMainFrameOnly: false) @@ -221,7 +239,7 @@ final class BrowserWebContent: UIView, BrowserContent, WKNavigationDelegate, WKU self.webView = WebView(frame: CGRect(), configuration: configuration) self.webView.allowsLinkPreview = true - + if #available(iOS 11.0, *) { self.webView.scrollView.contentInsetAdjustmentBehavior = .never } @@ -529,7 +547,14 @@ final class BrowserWebContent: UIView, BrowserContent, WKNavigationDelegate, WKU self.previousScrollingOffset = ScrollingOffsetState(value: self.webView.scrollView.contentOffset.y, isDraggingOrDecelerating: self.webView.scrollView.isDragging || self.webView.scrollView.isDecelerating) - let webViewFrame = CGRect(origin: CGPoint(x: insets.left, y: insets.top), size: CGSize(width: size.width - insets.left - insets.right, height: size.height - insets.top)) + let currentBounds = self.webView.scrollView.bounds + let offsetToBottomEdge = max(0.0, self.webView.scrollView.contentSize.height - currentBounds.maxY) + var bottomInset = insets.bottom + if offsetToBottomEdge < 128.0 { + bottomInset = fullInsets.bottom + } + + let webViewFrame = CGRect(origin: CGPoint(x: insets.left, y: insets.top), size: CGSize(width: size.width - insets.left - insets.right, height: size.height - insets.top - bottomInset)) var refresh = false if self.webView.frame.width > 0 && webViewFrame.width != self.webView.frame.width { refresh = true @@ -540,11 +565,10 @@ final class BrowserWebContent: UIView, BrowserContent, WKNavigationDelegate, WKU self.webView.reloadInputViews() } - self.webView.scrollView.contentInset = UIEdgeInsets(top: 0.0, left: 0.0, bottom: fullInsets.bottom, right: 0.0) - self.webView.customBottomInset = max(insets.bottom, safeInsets.bottom) + self.webView.customBottomInset = safeInsets.bottom * (1.0 - insets.bottom / fullInsets.bottom) - self.webView.scrollView.scrollIndicatorInsets = UIEdgeInsets(top: 0.0, left: -insets.left, bottom: 0.0, right: -insets.right) - self.webView.scrollView.horizontalScrollIndicatorInsets = UIEdgeInsets(top: 0.0, left: -insets.left, bottom: 0.0, right: -insets.right) +// self.webView.scrollView.scrollIndicatorInsets = UIEdgeInsets(top: 0.0, left: -insets.left, bottom: 0.0, right: -insets.right) +// self.webView.scrollView.horizontalScrollIndicatorInsets = UIEdgeInsets(top: 0.0, left: -insets.left, bottom: 0.0, right: -insets.right) if let error = self.currentError { let errorSize = self.errorView.update( @@ -682,7 +706,7 @@ final class BrowserWebContent: UIView, BrowserContent, WKNavigationDelegate, WKU // }) // } else { if let url = navigationAction.request.url?.absoluteString { - if (navigationAction.targetFrame == nil || navigationAction.targetFrame?.isMainFrame == true) && (isTelegramMeLink(url) || isTelegraPhLink(url)) { + if (navigationAction.targetFrame == nil || navigationAction.targetFrame?.isMainFrame == true) && (isTelegramMeLink(url) || isTelegraPhLink(url)) && !url.contains("/auth/push?") && !self._state.url.contains("/auth/push?") { decisionHandler(.cancel, preferences) self.minimize() self.openAppUrl(url) @@ -770,7 +794,9 @@ final class BrowserWebContent: UIView, BrowserContent, WKNavigationDelegate, WKU } func webViewDidClose(_ webView: WKWebView) { - self.close() + Queue.mainQueue().after(0.5, { + self.close() + }) } @available(iOS 15.0, *) diff --git a/submodules/Camera/BUILD b/submodules/Camera/BUILD index 07377c40c1..a5150befbb 100644 --- a/submodules/Camera/BUILD +++ b/submodules/Camera/BUILD @@ -58,6 +58,7 @@ swift_library( "//submodules/Display:Display", "//submodules/ImageBlur:ImageBlur", "//submodules/TelegramCore:TelegramCore", + "//submodules/Utils/DeviceModel", ], visibility = [ "//visibility:public", diff --git a/submodules/Camera/Sources/Camera.swift b/submodules/Camera/Sources/Camera.swift index 922e9af872..ca84dca958 100644 --- a/submodules/Camera/Sources/Camera.swift +++ b/submodules/Camera/Sources/Camera.swift @@ -4,6 +4,7 @@ import SwiftSignalKit import AVFoundation import CoreImage import TelegramCore +import DeviceModel final class CameraSession { private let singleSession: AVCaptureSession? diff --git a/submodules/Camera/Sources/CameraMetrics.swift b/submodules/Camera/Sources/CameraMetrics.swift index c1c8a3e429..4d5c684da8 100644 --- a/submodules/Camera/Sources/CameraMetrics.swift +++ b/submodules/Camera/Sources/CameraMetrics.swift @@ -1,4 +1,5 @@ import Foundation +import DeviceModel public extension Camera { enum Metrics { @@ -56,370 +57,3 @@ public extension Camera { } } } - -enum DeviceModel: CaseIterable, Equatable { - static var allCases: [DeviceModel] { - return [ - .iPodTouch1, - .iPodTouch2, - .iPodTouch3, - .iPodTouch4, - .iPodTouch5, - .iPodTouch6, - .iPodTouch7, - .iPhone, - .iPhone3G, - .iPhone3GS, - .iPhone4, - .iPhone4S, - .iPhone5, - .iPhone5C, - .iPhone5S, - .iPhone6, - .iPhone6Plus, - .iPhone6S, - .iPhone6SPlus, - .iPhoneSE, - .iPhone7, - .iPhone7Plus, - .iPhone8, - .iPhone8Plus, - .iPhoneX, - .iPhoneXS, - .iPhoneXR, - .iPhone11, - .iPhone11Pro, - .iPhone11ProMax, - .iPhone12, - .iPhone12Mini, - .iPhone12Pro, - .iPhone12ProMax, - .iPhone13, - .iPhone13Mini, - .iPhone13Pro, - .iPhone13ProMax, - .iPhone14, - .iPhone14Plus, - .iPhone14Pro, - .iPhone14ProMax, - .iPhone15, - .iPhone15Plus, - .iPhone15Pro, - .iPhone15ProMax - ] - } - - case iPodTouch1 - case iPodTouch2 - case iPodTouch3 - case iPodTouch4 - case iPodTouch5 - case iPodTouch6 - case iPodTouch7 - - case iPhone - case iPhone3G - case iPhone3GS - - case iPhone4 - case iPhone4S - - case iPhone5 - case iPhone5C - case iPhone5S - - case iPhone6 - case iPhone6Plus - case iPhone6S - case iPhone6SPlus - - case iPhoneSE - - case iPhone7 - case iPhone7Plus - case iPhone8 - case iPhone8Plus - - case iPhoneX - case iPhoneXS - case iPhoneXSMax - case iPhoneXR - - case iPhone11 - case iPhone11Pro - case iPhone11ProMax - - case iPhoneSE2ndGen - - case iPhone12 - case iPhone12Mini - case iPhone12Pro - case iPhone12ProMax - - case iPhone13 - case iPhone13Mini - case iPhone13Pro - case iPhone13ProMax - - case iPhoneSE3rdGen - - case iPhone14 - case iPhone14Plus - case iPhone14Pro - case iPhone14ProMax - - case iPhone15 - case iPhone15Plus - case iPhone15Pro - case iPhone15ProMax - - case unknown(String) - - var modelId: [String] { - switch self { - case .iPodTouch1: - return ["iPod1,1"] - case .iPodTouch2: - return ["iPod2,1"] - case .iPodTouch3: - return ["iPod3,1"] - case .iPodTouch4: - return ["iPod4,1"] - case .iPodTouch5: - return ["iPod5,1"] - case .iPodTouch6: - return ["iPod7,1"] - case .iPodTouch7: - return ["iPod9,1"] - case .iPhone: - return ["iPhone1,1"] - case .iPhone3G: - return ["iPhone1,2"] - case .iPhone3GS: - return ["iPhone2,1"] - case .iPhone4: - return ["iPhone3,1", "iPhone3,2", "iPhone3,3"] - case .iPhone4S: - return ["iPhone4,1", "iPhone4,2", "iPhone4,3"] - case .iPhone5: - return ["iPhone5,1", "iPhone5,2"] - case .iPhone5C: - return ["iPhone5,3", "iPhone5,4"] - case .iPhone5S: - return ["iPhone6,1", "iPhone6,2"] - case .iPhone6: - return ["iPhone7,2"] - case .iPhone6Plus: - return ["iPhone7,1"] - case .iPhone6S: - return ["iPhone8,1"] - case .iPhone6SPlus: - return ["iPhone8,2"] - case .iPhoneSE: - return ["iPhone8,4"] - case .iPhone7: - return ["iPhone9,1", "iPhone9,3"] - case .iPhone7Plus: - return ["iPhone9,2", "iPhone9,4"] - case .iPhone8: - return ["iPhone10,1", "iPhone10,4"] - case .iPhone8Plus: - return ["iPhone10,2", "iPhone10,5"] - case .iPhoneX: - return ["iPhone10,3", "iPhone10,6"] - case .iPhoneXS: - return ["iPhone11,2"] - case .iPhoneXSMax: - return ["iPhone11,4", "iPhone11,6"] - case .iPhoneXR: - return ["iPhone11,8"] - case .iPhone11: - return ["iPhone12,1"] - case .iPhone11Pro: - return ["iPhone12,3"] - case .iPhone11ProMax: - return ["iPhone12,5"] - case .iPhoneSE2ndGen: - return ["iPhone12,8"] - case .iPhone12: - return ["iPhone13,2"] - case .iPhone12Mini: - return ["iPhone13,1"] - case .iPhone12Pro: - return ["iPhone13,3"] - case .iPhone12ProMax: - return ["iPhone13,4"] - case .iPhone13: - return ["iPhone14,5"] - case .iPhone13Mini: - return ["iPhone14,4"] - case .iPhone13Pro: - return ["iPhone14,2"] - case .iPhone13ProMax: - return ["iPhone14,3"] - case .iPhoneSE3rdGen: - return ["iPhone14,6"] - case .iPhone14: - return ["iPhone14,7"] - case .iPhone14Plus: - return ["iPhone14,8"] - case .iPhone14Pro: - return ["iPhone15,2"] - case .iPhone14ProMax: - return ["iPhone15,3"] - case .iPhone15: - return ["iPhone15,4"] - case .iPhone15Plus: - return ["iPhone15,5"] - case .iPhone15Pro: - return ["iPhone16,1"] - case .iPhone15ProMax: - return ["iPhone16,2"] - case let .unknown(modelId): - return [modelId] - } - } - - var modelName: String { - switch self { - case .iPodTouch1: - return "iPod touch 1G" - case .iPodTouch2: - return "iPod touch 2G" - case .iPodTouch3: - return "iPod touch 3G" - case .iPodTouch4: - return "iPod touch 4G" - case .iPodTouch5: - return "iPod touch 5G" - case .iPodTouch6: - return "iPod touch 6G" - case .iPodTouch7: - return "iPod touch 7G" - case .iPhone: - return "iPhone" - case .iPhone3G: - return "iPhone 3G" - case .iPhone3GS: - return "iPhone 3GS" - case .iPhone4: - return "iPhone 4" - case .iPhone4S: - return "iPhone 4S" - case .iPhone5: - return "iPhone 5" - case .iPhone5C: - return "iPhone 5C" - case .iPhone5S: - return "iPhone 5S" - case .iPhone6: - return "iPhone 6" - case .iPhone6Plus: - return "iPhone 6 Plus" - case .iPhone6S: - return "iPhone 6S" - case .iPhone6SPlus: - return "iPhone 6S Plus" - case .iPhoneSE: - return "iPhone SE" - case .iPhone7: - return "iPhone 7" - case .iPhone7Plus: - return "iPhone 7 Plus" - case .iPhone8: - return "iPhone 8" - case .iPhone8Plus: - return "iPhone 8 Plus" - case .iPhoneX: - return "iPhone X" - case .iPhoneXS: - return "iPhone XS" - case .iPhoneXSMax: - return "iPhone XS Max" - case .iPhoneXR: - return "iPhone XR" - case .iPhone11: - return "iPhone 11" - case .iPhone11Pro: - return "iPhone 11 Pro" - case .iPhone11ProMax: - return "iPhone 11 Pro Max" - case .iPhoneSE2ndGen: - return "iPhone SE (2nd gen)" - case .iPhone12: - return "iPhone 12" - case .iPhone12Mini: - return "iPhone 12 mini" - case .iPhone12Pro: - return "iPhone 12 Pro" - case .iPhone12ProMax: - return "iPhone 12 Pro Max" - case .iPhone13: - return "iPhone 13" - case .iPhone13Mini: - return "iPhone 13 mini" - case .iPhone13Pro: - return "iPhone 13 Pro" - case .iPhone13ProMax: - return "iPhone 13 Pro Max" - case .iPhoneSE3rdGen: - return "iPhone SE (3rd gen)" - case .iPhone14: - return "iPhone 14" - case .iPhone14Plus: - return "iPhone 14 Plus" - case .iPhone14Pro: - return "iPhone 14 Pro" - case .iPhone14ProMax: - return "iPhone 14 Pro Max" - case .iPhone15: - return "iPhone 15" - case .iPhone15Plus: - return "iPhone 15 Plus" - case .iPhone15Pro: - return "iPhone 15 Pro" - case .iPhone15ProMax: - return "iPhone 15 Pro Max" - case let .unknown(modelId): - if modelId.hasPrefix("iPhone") { - return "Unknown iPhone" - } else if modelId.hasPrefix("iPod") { - return "Unknown iPod" - } else if modelId.hasPrefix("iPad") { - return "Unknown iPad" - } else { - return "Unknown Device" - } - } - } - - var isIpad: Bool { - return self.modelId.first?.hasPrefix("iPad") ?? false - } - - static let current = DeviceModel() - - private init() { - var systemInfo = utsname() - uname(&systemInfo) - let modelCode = withUnsafePointer(to: &systemInfo.machine) { - $0.withMemoryRebound(to: CChar.self, capacity: 1) { - ptr in String.init(validatingUTF8: ptr) - } - } - var result: DeviceModel? - if let modelCode { - for model in DeviceModel.allCases { - if model.modelId.contains(modelCode) { - result = model - break - } - } - } - if let result { - self = result - } else { - self = .unknown(modelCode ?? "") - } - } -} diff --git a/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsControllerNode.swift b/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsControllerNode.swift index d2a58e97ce..32d3549ad1 100644 --- a/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsControllerNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsControllerNode.swift @@ -1260,6 +1260,8 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { break case .premiumOffer: break + case .starsTopup: + break case let .joinVoiceChat(peerId, invite): strongSelf.presentController(VoiceChatJoinScreen(context: strongSelf.context, peerId: peerId, invite: invite, join: { call in }), .window(.root), nil) diff --git a/submodules/TelegramUI/Components/Stars/StarsPurchaseScreen/Sources/StarsPurchaseScreen.swift b/submodules/TelegramUI/Components/Stars/StarsPurchaseScreen/Sources/StarsPurchaseScreen.swift index 74529be6e7..a5257985bd 100644 --- a/submodules/TelegramUI/Components/Stars/StarsPurchaseScreen/Sources/StarsPurchaseScreen.swift +++ b/submodules/TelegramUI/Components/Stars/StarsPurchaseScreen/Sources/StarsPurchaseScreen.swift @@ -208,7 +208,8 @@ private final class StarsPurchaseScreenContentComponent: CombinedComponent { let textString: String switch context.component.purpose { - case .generic: + case let .generic(requiredStars): + let _ = requiredStars textString = strings.Stars_Purchase_GetStarsInfo case .gift: textString = strings.Stars_Purchase_GiftInfo(component.peers.first?.value.compactDisplayTitle ?? "").string @@ -299,8 +300,13 @@ private final class StarsPurchaseScreenContentComponent: CombinedComponent { if let products = state.products, let balance = context.component.balance { var minimumCount: Int64? if let requiredStars = context.component.purpose.requiredStars { - minimumCount = requiredStars - balance + if case .generic = context.component.purpose { + minimumCount = requiredStars + } else { + minimumCount = requiredStars - balance + } } + for product in products { if let minimumCount, minimumCount > product.count && !(items.isEmpty && product.id == products.last?.id) { continue @@ -810,8 +816,12 @@ private final class StarsPurchaseScreenComponent: CombinedComponent { let titleText: String switch context.component.purpose { - case .generic: - titleText = strings.Stars_Purchase_GetStars + case let .generic(requiredStars): + if let requiredStars { + titleText = strings.Stars_Purchase_StarsNeeded(Int32(requiredStars)) + } else { + titleText = strings.Stars_Purchase_GetStars + } case .gift: titleText = strings.Stars_Purchase_GiftStars case let .transfer(_, requiredStars), let .subscription(_, requiredStars, _), let .unlockMedia(requiredStars): @@ -1216,6 +1226,8 @@ private extension StarsPurchasePurpose { var requiredStars: Int64? { switch self { + case let .generic(requiredStars): + return requiredStars case let .transfer(_, requiredStars): return requiredStars case let .subscription(_, requiredStars, _): diff --git a/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsTransactionsScreen.swift b/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsTransactionsScreen.swift index e6329ee119..d0ff4ecdb2 100644 --- a/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsTransactionsScreen.swift +++ b/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsTransactionsScreen.swift @@ -806,7 +806,7 @@ public final class StarsTransactionsScreen: ViewControllerComponentContainer { guard let self else { return } - let controller = context.sharedContext.makeStarsPurchaseScreen(context: context, starsContext: starsContext, options: options, purpose: .generic, completion: { [weak self] stars in + let controller = context.sharedContext.makeStarsPurchaseScreen(context: context, starsContext: starsContext, options: options, purpose: .generic(requiredStars: nil), completion: { [weak self] stars in guard let self else { return } diff --git a/submodules/TelegramUI/Components/Stars/StarsTransferScreen/Sources/StarsTransferScreen.swift b/submodules/TelegramUI/Components/Stars/StarsTransferScreen/Sources/StarsTransferScreen.swift index 84cdd6589f..913a0eff7e 100644 --- a/submodules/TelegramUI/Components/Stars/StarsTransferScreen/Sources/StarsTransferScreen.swift +++ b/submodules/TelegramUI/Components/Stars/StarsTransferScreen/Sources/StarsTransferScreen.swift @@ -484,7 +484,7 @@ private final class SheetContent: CombinedComponent { } else if let peerId = state?.botPeer?.id { purpose = .transfer(peerId: peerId, requiredStars: invoice.totalAmount) } else { - purpose = .generic + purpose = .generic(requiredStars: nil) } let purchaseController = accountContext.sharedContext.makeStarsPurchaseScreen( context: accountContext, diff --git a/submodules/TelegramUI/Sources/OpenResolvedUrl.swift b/submodules/TelegramUI/Sources/OpenResolvedUrl.swift index 4a21ce561c..c92885e83d 100644 --- a/submodules/TelegramUI/Sources/OpenResolvedUrl.swift +++ b/submodules/TelegramUI/Sources/OpenResolvedUrl.swift @@ -656,6 +656,14 @@ func openResolvedUrlImpl( if let navigationController = navigationController { navigationController.pushViewController(controller, animated: true) } + case let .starsTopup(amount): + dismissInput() + if let starsContext = context.starsContext { + let controller = context.sharedContext.makeStarsPurchaseScreen(context: context, starsContext: starsContext, options: [], purpose: .generic(requiredStars: amount), completion: { _ in }) + if let navigationController = navigationController { + navigationController.pushViewController(controller, animated: true) + } + } case let .joinVoiceChat(peerId, invite): let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)) |> deliverOnMainQueue).start(next: { peer in diff --git a/submodules/TelegramUI/Sources/OpenUrl.swift b/submodules/TelegramUI/Sources/OpenUrl.swift index d4b2515af7..a30266f109 100644 --- a/submodules/TelegramUI/Sources/OpenUrl.swift +++ b/submodules/TelegramUI/Sources/OpenUrl.swift @@ -918,6 +918,20 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur } } handleResolvedUrl(.premiumMultiGift(reference: reference)) + } else if parsedUrl.host == "stars_topup" { + var amount: Int64? + if let components = URLComponents(string: "/?" + query) { + if let queryItems = components.queryItems { + for queryItem in queryItems { + if let value = queryItem.value { + if queryItem.name == "amount" { + amount = Int64(value) + } + } + } + } + } + handleResolvedUrl(.starsTopup(amount: amount)) } else if parsedUrl.host == "addlist" { if let components = URLComponents(string: "/?" + query) { var slug: String? diff --git a/submodules/Utils/DeviceModel/BUILD b/submodules/Utils/DeviceModel/BUILD new file mode 100644 index 0000000000..16d3d3f356 --- /dev/null +++ b/submodules/Utils/DeviceModel/BUILD @@ -0,0 +1,20 @@ +load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library") + +swift_library( + name = "DeviceModel", + module_name = "DeviceModel", + srcs = glob([ + "Sources/**/*.swift", + ]), + copts = [ + "-warnings-as-errors", + ], + deps = [ + "//submodules/SSignalKit/SwiftSignalKit", + "//submodules/LegacyComponents", + "//submodules/AccountContext", + ], + visibility = [ + "//visibility:public", + ], +) diff --git a/submodules/Utils/DeviceModel/Sources/DeviceModel.swift b/submodules/Utils/DeviceModel/Sources/DeviceModel.swift new file mode 100644 index 0000000000..ba30871c3b --- /dev/null +++ b/submodules/Utils/DeviceModel/Sources/DeviceModel.swift @@ -0,0 +1,368 @@ +import Foundation + +public enum DeviceModel: CaseIterable, Equatable { + public static var allCases: [DeviceModel] { + return [ + .iPodTouch1, + .iPodTouch2, + .iPodTouch3, + .iPodTouch4, + .iPodTouch5, + .iPodTouch6, + .iPodTouch7, + .iPhone, + .iPhone3G, + .iPhone3GS, + .iPhone4, + .iPhone4S, + .iPhone5, + .iPhone5C, + .iPhone5S, + .iPhone6, + .iPhone6Plus, + .iPhone6S, + .iPhone6SPlus, + .iPhoneSE, + .iPhone7, + .iPhone7Plus, + .iPhone8, + .iPhone8Plus, + .iPhoneX, + .iPhoneXS, + .iPhoneXR, + .iPhone11, + .iPhone11Pro, + .iPhone11ProMax, + .iPhone12, + .iPhone12Mini, + .iPhone12Pro, + .iPhone12ProMax, + .iPhone13, + .iPhone13Mini, + .iPhone13Pro, + .iPhone13ProMax, + .iPhone14, + .iPhone14Plus, + .iPhone14Pro, + .iPhone14ProMax, + .iPhone15, + .iPhone15Plus, + .iPhone15Pro, + .iPhone15ProMax + ] + } + + case iPodTouch1 + case iPodTouch2 + case iPodTouch3 + case iPodTouch4 + case iPodTouch5 + case iPodTouch6 + case iPodTouch7 + + case iPhone + case iPhone3G + case iPhone3GS + + case iPhone4 + case iPhone4S + + case iPhone5 + case iPhone5C + case iPhone5S + + case iPhone6 + case iPhone6Plus + case iPhone6S + case iPhone6SPlus + + case iPhoneSE + + case iPhone7 + case iPhone7Plus + case iPhone8 + case iPhone8Plus + + case iPhoneX + case iPhoneXS + case iPhoneXSMax + case iPhoneXR + + case iPhone11 + case iPhone11Pro + case iPhone11ProMax + + case iPhoneSE2ndGen + + case iPhone12 + case iPhone12Mini + case iPhone12Pro + case iPhone12ProMax + + case iPhone13 + case iPhone13Mini + case iPhone13Pro + case iPhone13ProMax + + case iPhoneSE3rdGen + + case iPhone14 + case iPhone14Plus + case iPhone14Pro + case iPhone14ProMax + + case iPhone15 + case iPhone15Plus + case iPhone15Pro + case iPhone15ProMax + + case unknown(String) + + public var modelId: [String] { + switch self { + case .iPodTouch1: + return ["iPod1,1"] + case .iPodTouch2: + return ["iPod2,1"] + case .iPodTouch3: + return ["iPod3,1"] + case .iPodTouch4: + return ["iPod4,1"] + case .iPodTouch5: + return ["iPod5,1"] + case .iPodTouch6: + return ["iPod7,1"] + case .iPodTouch7: + return ["iPod9,1"] + case .iPhone: + return ["iPhone1,1"] + case .iPhone3G: + return ["iPhone1,2"] + case .iPhone3GS: + return ["iPhone2,1"] + case .iPhone4: + return ["iPhone3,1", "iPhone3,2", "iPhone3,3"] + case .iPhone4S: + return ["iPhone4,1", "iPhone4,2", "iPhone4,3"] + case .iPhone5: + return ["iPhone5,1", "iPhone5,2"] + case .iPhone5C: + return ["iPhone5,3", "iPhone5,4"] + case .iPhone5S: + return ["iPhone6,1", "iPhone6,2"] + case .iPhone6: + return ["iPhone7,2"] + case .iPhone6Plus: + return ["iPhone7,1"] + case .iPhone6S: + return ["iPhone8,1"] + case .iPhone6SPlus: + return ["iPhone8,2"] + case .iPhoneSE: + return ["iPhone8,4"] + case .iPhone7: + return ["iPhone9,1", "iPhone9,3"] + case .iPhone7Plus: + return ["iPhone9,2", "iPhone9,4"] + case .iPhone8: + return ["iPhone10,1", "iPhone10,4"] + case .iPhone8Plus: + return ["iPhone10,2", "iPhone10,5"] + case .iPhoneX: + return ["iPhone10,3", "iPhone10,6"] + case .iPhoneXS: + return ["iPhone11,2"] + case .iPhoneXSMax: + return ["iPhone11,4", "iPhone11,6"] + case .iPhoneXR: + return ["iPhone11,8"] + case .iPhone11: + return ["iPhone12,1"] + case .iPhone11Pro: + return ["iPhone12,3"] + case .iPhone11ProMax: + return ["iPhone12,5"] + case .iPhoneSE2ndGen: + return ["iPhone12,8"] + case .iPhone12: + return ["iPhone13,2"] + case .iPhone12Mini: + return ["iPhone13,1"] + case .iPhone12Pro: + return ["iPhone13,3"] + case .iPhone12ProMax: + return ["iPhone13,4"] + case .iPhone13: + return ["iPhone14,5"] + case .iPhone13Mini: + return ["iPhone14,4"] + case .iPhone13Pro: + return ["iPhone14,2"] + case .iPhone13ProMax: + return ["iPhone14,3"] + case .iPhoneSE3rdGen: + return ["iPhone14,6"] + case .iPhone14: + return ["iPhone14,7"] + case .iPhone14Plus: + return ["iPhone14,8"] + case .iPhone14Pro: + return ["iPhone15,2"] + case .iPhone14ProMax: + return ["iPhone15,3"] + case .iPhone15: + return ["iPhone15,4"] + case .iPhone15Plus: + return ["iPhone15,5"] + case .iPhone15Pro: + return ["iPhone16,1"] + case .iPhone15ProMax: + return ["iPhone16,2"] + case let .unknown(modelId): + return [modelId] + } + } + + public var modelName: String { + switch self { + case .iPodTouch1: + return "iPod touch 1G" + case .iPodTouch2: + return "iPod touch 2G" + case .iPodTouch3: + return "iPod touch 3G" + case .iPodTouch4: + return "iPod touch 4G" + case .iPodTouch5: + return "iPod touch 5G" + case .iPodTouch6: + return "iPod touch 6G" + case .iPodTouch7: + return "iPod touch 7G" + case .iPhone: + return "iPhone" + case .iPhone3G: + return "iPhone 3G" + case .iPhone3GS: + return "iPhone 3GS" + case .iPhone4: + return "iPhone 4" + case .iPhone4S: + return "iPhone 4S" + case .iPhone5: + return "iPhone 5" + case .iPhone5C: + return "iPhone 5C" + case .iPhone5S: + return "iPhone 5S" + case .iPhone6: + return "iPhone 6" + case .iPhone6Plus: + return "iPhone 6 Plus" + case .iPhone6S: + return "iPhone 6S" + case .iPhone6SPlus: + return "iPhone 6S Plus" + case .iPhoneSE: + return "iPhone SE" + case .iPhone7: + return "iPhone 7" + case .iPhone7Plus: + return "iPhone 7 Plus" + case .iPhone8: + return "iPhone 8" + case .iPhone8Plus: + return "iPhone 8 Plus" + case .iPhoneX: + return "iPhone X" + case .iPhoneXS: + return "iPhone XS" + case .iPhoneXSMax: + return "iPhone XS Max" + case .iPhoneXR: + return "iPhone XR" + case .iPhone11: + return "iPhone 11" + case .iPhone11Pro: + return "iPhone 11 Pro" + case .iPhone11ProMax: + return "iPhone 11 Pro Max" + case .iPhoneSE2ndGen: + return "iPhone SE (2nd gen)" + case .iPhone12: + return "iPhone 12" + case .iPhone12Mini: + return "iPhone 12 mini" + case .iPhone12Pro: + return "iPhone 12 Pro" + case .iPhone12ProMax: + return "iPhone 12 Pro Max" + case .iPhone13: + return "iPhone 13" + case .iPhone13Mini: + return "iPhone 13 mini" + case .iPhone13Pro: + return "iPhone 13 Pro" + case .iPhone13ProMax: + return "iPhone 13 Pro Max" + case .iPhoneSE3rdGen: + return "iPhone SE (3rd gen)" + case .iPhone14: + return "iPhone 14" + case .iPhone14Plus: + return "iPhone 14 Plus" + case .iPhone14Pro: + return "iPhone 14 Pro" + case .iPhone14ProMax: + return "iPhone 14 Pro Max" + case .iPhone15: + return "iPhone 15" + case .iPhone15Plus: + return "iPhone 15 Plus" + case .iPhone15Pro: + return "iPhone 15 Pro" + case .iPhone15ProMax: + return "iPhone 15 Pro Max" + case let .unknown(modelId): + if modelId.hasPrefix("iPhone") { + return "Unknown iPhone" + } else if modelId.hasPrefix("iPod") { + return "Unknown iPod" + } else if modelId.hasPrefix("iPad") { + return "Unknown iPad" + } else { + return "Unknown Device" + } + } + } + + public var isIpad: Bool { + return self.modelId.first?.hasPrefix("iPad") ?? false + } + + public static let current = DeviceModel() + + private init() { + var systemInfo = utsname() + uname(&systemInfo) + let modelCode = withUnsafePointer(to: &systemInfo.machine) { + $0.withMemoryRebound(to: CChar.self, capacity: 1) { + ptr in String.init(validatingUTF8: ptr) + } + } + var result: DeviceModel? + if let modelCode { + for model in DeviceModel.allCases { + if model.modelId.contains(modelCode) { + result = model + break + } + } + } + if let result { + self = result + } else { + self = .unknown(modelCode ?? "") + } + } +}