From bb9b706c9439b16208c6a563f11f7cd84f92dec1 Mon Sep 17 00:00:00 2001 From: Peter <> Date: Thu, 3 Oct 2019 04:11:41 +0400 Subject: [PATCH 01/12] Bugfixes --- Makefile | 24 +- Telegram-iOS/Info.plist | 10 +- .../Telegram_Buck+IntentsExtension.xcscheme | 4 + ...Buck+NotificationContentExtension.xcscheme | 4 + ...Buck+NotificationServiceExtension.xcscheme | 4 + .../Telegram_Buck+ShareExtension.xcscheme | 4 + .../Telegram_Buck+WidgetExtension.xcscheme | 4 + .../xcschemes/Telegram_Buck.xcscheme | 6 + package_app.sh | 6 + submodules/BuildConfig/Sources/BuildConfig.h | 2 +- submodules/BuildConfig/Sources/BuildConfig.m | 15 +- .../ContextUI/Sources/ContextGesture.swift | 13 +- .../GlobalOverlayPresentationContext.swift | 4 +- submodules/Display/Display/ListView.swift | 4 + .../Navigation/NavigationContainer.swift | 52 +++- .../Navigation/NavigationController.swift | 287 ++++++++++++++++-- .../Navigation/NavigationModalContainer.swift | 8 + .../NavigationOverlayContainer.swift | 78 +++++ .../Navigation/NavigationSplitContainer.swift | 34 ++- .../Display/ScrollToTopProxyView.swift | 12 + submodules/Display/Display/StatusBar.swift | 8 + .../Display/Display/StatusBarHost.swift | 3 + .../Display/Display/TabBarController.swift | 9 + .../Display/Display/ViewController.swift | 4 +- .../Display/Display/WindowContent.swift | 114 +++++-- .../Sources/GalleryControllerNode.swift | 10 +- .../Sources/ItemListControllerNode.swift | 4 +- .../TGModernGalleryController.m | 12 +- .../LegacyUI/Sources/LegacyController.swift | 2 +- .../LocalizedPeerData/Sources/PeerTitle.swift | 2 + .../xcschemes/SwiftSignalKit.xcscheme | 13 + .../Sources/SettingsController.swift | 12 +- .../TermsOfServiceController.swift | 2 +- .../Themes/ThemePreviewControllerNode.swift | 1 + .../TelegramCore/TelegramCore/PeerUtils.swift | 2 +- .../TelegramCore/TelegramCore/Wallets.swift | 13 +- .../TelegramUI/TelegramUI/AppDelegate.swift | 29 +- .../TelegramUI/ApplicationContext.swift | 1 + .../TelegramUI/ChatController.swift | 36 ++- .../TelegramUI/ChatControllerNode.swift | 3 + .../NotificationContainerController.swift | 14 +- .../NotificationContainerControllerNode.swift | 21 +- .../TelegramUI/SharedAccountContext.swift | 9 +- .../WalletUI/Sources/WalletSplashScreen.swift | 57 ++-- 44 files changed, 781 insertions(+), 175 deletions(-) create mode 100644 submodules/Display/Display/Navigation/NavigationOverlayContainer.swift diff --git a/Makefile b/Makefile index 3b8bcbc4b8..efcd86c157 100644 --- a/Makefile +++ b/Makefile @@ -168,6 +168,28 @@ package_arm64: PACKAGE_BUNDLE_ID="${BUNDLE_ID}" \ sh package_app.sh iphoneos-arm64 $(BUCK) $(BUCK_OPTIONS) ${BUCK_RELEASE_OPTIONS} +package_debug_arm64: + PACKAGE_DEVELOPMENT_TEAM="${DEVELOPMENT_TEAM}" \ + PACKAGE_CODE_SIGN_IDENTITY="${DEVELOPMENT_CODE_SIGN_IDENTITY}" \ + PACKAGE_PROVISIONING_PROFILE_APP="${DEVELOPMENT_PROVISIONING_PROFILE_APP}" \ + PACKAGE_ENTITLEMENTS_APP="${ENTITLEMENTS_APP}" \ + PACKAGE_PROVISIONING_PROFILE_EXTENSION_Share="${DEVELOPMENT_PROVISIONING_PROFILE_EXTENSION_SHARE}" \ + PACKAGE_ENTITLEMENTS_EXTENSION_Share="${ENTITLEMENTS_EXTENSION_SHARE}" \ + PACKAGE_PROVISIONING_PROFILE_EXTENSION_Widget="${DEVELOPMENT_PROVISIONING_PROFILE_EXTENSION_WIDGET}" \ + PACKAGE_ENTITLEMENTS_EXTENSION_Widget="${ENTITLEMENTS_EXTENSION_WIDGET}" \ + PACKAGE_PROVISIONING_PROFILE_EXTENSION_NotificationService="${DEVELOPMENT_PROVISIONING_PROFILE_EXTENSION_NOTIFICATIONSERVICE}" \ + PACKAGE_ENTITLEMENTS_EXTENSION_NotificationService="${ENTITLEMENTS_EXTENSION_NOTIFICATIONSERVICE}" \ + PACKAGE_PROVISIONING_PROFILE_EXTENSION_NotificationContent="${DEVELOPMENT_PROVISIONING_PROFILE_EXTENSION_NOTIFICATIONCONTENT}" \ + PACKAGE_ENTITLEMENTS_EXTENSION_NotificationContent="${ENTITLEMENTS_EXTENSION_NOTIFICATIONCONTENT}" \ + PACKAGE_PROVISIONING_PROFILE_EXTENSION_Intents="${DEVELOPMENT_PROVISIONING_PROFILE_EXTENSION_INTENTS}" \ + PACKAGE_ENTITLEMENTS_EXTENSION_Intents="${ENTITLEMENTS_EXTENSION_INTENTS}" \ + PACKAGE_PROVISIONING_PROFILE_WATCH_APP="${DEVELOPMENT_PROVISIONING_PROFILE_WATCH_APP}" \ + PACKAGE_PROVISIONING_PROFILE_WATCH_EXTENSION="${DISTRIBUTION_PROVISIONING_PROFILE_WATCH_EXTENSION}" \ + PACKAGE_BUNDLE_ID="${BUNDLE_ID}" \ + ENABLE_GET_TASK_ALLOW=1 \ + CODESIGNING_PROFILES_VARIANT="development" \ + sh package_app.sh iphoneos-arm64 $(BUCK) $(BUCK_OPTIONS) ${BUCK_RELEASE_OPTIONS} + package: PACKAGE_DEVELOPMENT_TEAM="${DEVELOPMENT_TEAM}" \ PACKAGE_CODE_SIGN_IDENTITY="${DISTRIBUTION_CODE_SIGN_IDENTITY}" \ @@ -192,7 +214,7 @@ app: build package app_arm64: build_arm64 package_arm64 -app_debug_arm64: build_debug_arm64 package_arm64 +app_debug_arm64: build_debug_arm64 package_debug_arm64 build_buckdebug: check_env BUCK_DEBUG_MODE=1 $(BUCK) build \ diff --git a/Telegram-iOS/Info.plist b/Telegram-iOS/Info.plist index c56fd2a710..d7514c0887 100644 --- a/Telegram-iOS/Info.plist +++ b/Telegram-iOS/Info.plist @@ -301,6 +301,11 @@ remote-notification voip + UIDeviceFamily + + 1 + 2 + UIFileSharingEnabled UILaunchStoryboardName @@ -356,10 +361,5 @@ - UIDeviceFamily - - 1 - 2 - diff --git a/Telegram_Buck.xcworkspace/xcshareddata/xcschemes/Telegram_Buck+IntentsExtension.xcscheme b/Telegram_Buck.xcworkspace/xcshareddata/xcschemes/Telegram_Buck+IntentsExtension.xcscheme index ce9b325629..a48bce0372 100644 --- a/Telegram_Buck.xcworkspace/xcshareddata/xcschemes/Telegram_Buck+IntentsExtension.xcscheme +++ b/Telegram_Buck.xcworkspace/xcshareddata/xcschemes/Telegram_Buck+IntentsExtension.xcscheme @@ -44,6 +44,8 @@ shouldUseLaunchSchemeArgsEnv = "YES"> + + + + + + + + + + + + + + + + + + + + + + + + " "$PROFILE_ENTITLEMENTS_PATH" + fi + ENTITLEMENTS_VAR=PACKAGE_ENTITLEMENTS_$ITEM if [ ! -z "${!ENTITLEMENTS_VAR}" ]; then if [ ! -f "${!ENTITLEMENTS_VAR}" ]; then diff --git a/submodules/BuildConfig/Sources/BuildConfig.h b/submodules/BuildConfig/Sources/BuildConfig.h index 24a5cbe241..b57ccb7bf2 100644 --- a/submodules/BuildConfig/Sources/BuildConfig.h +++ b/submodules/BuildConfig/Sources/BuildConfig.h @@ -24,6 +24,6 @@ + (void)getHardwareEncryptionAvailableWithBaseAppBundleId:(NSString * _Nonnull)baseAppBundleId completion:(void (^)(NSData * _Nullable))completion; + (void)encryptApplicationSecret:(NSData * _Nonnull)secret baseAppBundleId:(NSString * _Nonnull)baseAppBundleId completion:(void (^)(NSData * _Nullable, NSData * _Nullable))completion; -+ (void)decryptApplicationSecret:(NSData * _Nonnull)secret publicKey:(NSData * _Nonnull)publicKey baseAppBundleId:(NSString * _Nonnull)baseAppBundleId completion:(void (^)(NSData * _Nullable))completion; ++ (void)decryptApplicationSecret:(NSData * _Nonnull)secret publicKey:(NSData * _Nonnull)publicKey baseAppBundleId:(NSString * _Nonnull)baseAppBundleId completion:(void (^)(NSData * _Nullable, bool))completion; @end diff --git a/submodules/BuildConfig/Sources/BuildConfig.m b/submodules/BuildConfig/Sources/BuildConfig.m index 7805b19d4d..1472a4e45a 100644 --- a/submodules/BuildConfig/Sources/BuildConfig.m +++ b/submodules/BuildConfig/Sources/BuildConfig.m @@ -694,28 +694,29 @@ API_AVAILABLE(ios(10)) }); } -+ (void)decryptApplicationSecret:(NSData * _Nonnull)secret publicKey:(NSData * _Nonnull)publicKey baseAppBundleId:(NSString * _Nonnull)baseAppBundleId completion:(void (^)(NSData * _Nullable))completion { ++ (void)decryptApplicationSecret:(NSData * _Nonnull)secret publicKey:(NSData * _Nonnull)publicKey baseAppBundleId:(NSString * _Nonnull)baseAppBundleId completion:(void (^)(NSData * _Nullable, bool))completion { dispatch_async([self encryptionQueue], ^{ LocalPrivateKey *privateKey = [self getApplicationSecretKey:baseAppBundleId isCheckKey:false]; if (privateKey == nil) { - completion(nil); + completion(nil, false); return; } if (privateKey == nil) { - completion(nil); + completion(nil, false); return; } NSData *currentPublicKey = [privateKey getPublicKey]; if (currentPublicKey == nil) { - completion(nil); + completion(nil, false); return; } if (![publicKey isEqualToData:currentPublicKey]) { - completion(nil); + completion(nil, false); return; } - NSData *result = [privateKey decrypt:secret cancelled:nil]; - completion(result); + bool cancelled = false; + NSData *result = [privateKey decrypt:secret cancelled:&cancelled]; + completion(result, cancelled); }); } diff --git a/submodules/ContextUI/Sources/ContextGesture.swift b/submodules/ContextUI/Sources/ContextGesture.swift index 6450b1f77c..e415027bc6 100644 --- a/submodules/ContextUI/Sources/ContextGesture.swift +++ b/submodules/ContextUI/Sources/ContextGesture.swift @@ -57,6 +57,8 @@ public final class ContextGesture: UIGestureRecognizer, UIGestureRecognizerDeleg override public func reset() { super.reset() + self.endPressedAppearance() + self.currentProgress = 0.0 self.delayTimer?.invalidate() self.delayTimer = nil @@ -152,9 +154,8 @@ public final class ContextGesture: UIGestureRecognizer, UIGestureRecognizerDeleg if let touch = touches.first { if !self.currentProgress.isZero, self.isValidated { - if #available(iOS 9.0, *) { - self.activationProgress?(0.0, .ended(self.currentProgress)) - } + self.currentProgress = 0.0 + self.activationProgress?(0.0, .ended(self.currentProgress)) } self.externalEnded?((self.view, touch.location(in: self.view))) @@ -170,9 +171,8 @@ public final class ContextGesture: UIGestureRecognizer, UIGestureRecognizerDeleg super.touchesCancelled(touches, with: event) if let touch = touches.first, !self.currentProgress.isZero, self.isValidated { - if #available(iOS 9.0, *) { - self.activationProgress?(0.0, .ended(self.currentProgress)) - } + self.currentProgress = 0.0 + self.activationProgress?(0.0, .ended(self.currentProgress)) } self.delayTimer?.invalidate() @@ -183,6 +183,7 @@ public final class ContextGesture: UIGestureRecognizer, UIGestureRecognizerDeleg public func cancel() { if !self.currentProgress.isZero, self.isValidated { + self.currentProgress = 0.0 self.activationProgress?(0.0, .ended(self.currentProgress)) self.delayTimer?.invalidate() diff --git a/submodules/Display/Display/GlobalOverlayPresentationContext.swift b/submodules/Display/Display/GlobalOverlayPresentationContext.swift index b0b89b2d24..9f99cb5a52 100644 --- a/submodules/Display/Display/GlobalOverlayPresentationContext.swift +++ b/submodules/Display/Display/GlobalOverlayPresentationContext.swift @@ -95,10 +95,8 @@ final class GlobalOverlayPresentationContext { } return keyboardWindow } else { - if underStatusBar, let view = self.parentView { + if let view = self.parentView { return view - } else { - return statusBarHost.statusBarWindow } } } diff --git a/submodules/Display/Display/ListView.swift b/submodules/Display/Display/ListView.swift index bd1d46609a..6b8a92d754 100644 --- a/submodules/Display/Display/ListView.swift +++ b/submodules/Display/Display/ListView.swift @@ -3313,6 +3313,10 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture indicatorFrame.origin.y = self.visibleSize.height - (self.scrollIndicatorInsets.bottom + indicatorBottomInset) - indicatorFrame.height } + if indicatorFrame.origin.y.isNaN { + indicatorFrame.origin.y = indicatorTopInset + } + if indicatorHeight >= visibleHeightWithoutIndicatorInsets { verticalScrollIndicator.isHidden = true verticalScrollIndicator.frame = indicatorFrame diff --git a/submodules/Display/Display/Navigation/NavigationContainer.swift b/submodules/Display/Display/Navigation/NavigationContainer.swift index ed26d9a2e2..82658ae960 100644 --- a/submodules/Display/Display/Navigation/NavigationContainer.swift +++ b/submodules/Display/Display/Navigation/NavigationContainer.swift @@ -76,13 +76,22 @@ final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelegate { private(set) var controllers: [ViewController] = [] private var state: State = State(layout: nil, canBeClosed: nil, top: nil, transition: nil, pending: nil) + private var ignoreInputHeight: Bool = false + private(set) var isReady: Bool = false var isReadyUpdated: (() -> Void)? var controllerRemoved: (ViewController) -> Void var keyboardViewManager: KeyboardViewManager? { didSet { - if self.keyboardViewManager !== oldValue { - + } + } + var canHaveKeyboardFocus: Bool = false { + didSet { + if self.canHaveKeyboardFocus != oldValue { + if !self.canHaveKeyboardFocus { + self.view.endEditing(true) + self.performUpdate(transition: .animated(duration: 0.5, curve: .spring)) + } } } } @@ -147,6 +156,7 @@ final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelegate { guard self.state.transition == nil else { return } + let beginGesture = self.controllers.count > 1 if beginGesture { @@ -163,7 +173,7 @@ final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelegate { topController.viewWillDisappear(true) let topNode = topController.displayNode - bottomController.containerLayoutUpdated(layout, transition: .immediate) + bottomController.containerLayoutUpdated(layout.withUpdatedInputHeight(nil), transition: .immediate) bottomController.viewWillAppear(true) let bottomNode = bottomController.displayNode @@ -195,11 +205,16 @@ final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelegate { let topController = top.value let bottomController = transition.previous.value + + if viewTreeContainsFirstResponder(view: top.value.view) { + strongSelf.ignoreInputHeight = true + } strongSelf.keyboardViewManager?.dismissEditingWithoutAnimation(view: topController.view) strongSelf.state.transition = nil strongSelf.controllerRemoved(top.value) + strongSelf.ignoreInputHeight = false }) } else { navigationTransitionCoordinator.animateCancel({ [weak self] in @@ -383,12 +398,16 @@ final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelegate { } private func makeChild(layout: ContainerViewLayout, value: ViewController) -> Child { - value.containerLayoutUpdated(layout, transition: .immediate) - return Child(value: value, layout: layout) + let updatedLayout = layout.withUpdatedInputHeight(nil) + value.containerLayoutUpdated(updatedLayout, transition: .immediate) + return Child(value: value, layout: updatedLayout) } private func applyLayout(layout: ContainerViewLayout, to child: Child, isMaster: Bool, transition: ContainedViewLayoutTransition) { var childFrame = CGRect(origin: CGPoint(), size: layout.size) + + var updatedLayout = layout + var shouldSyncKeyboard = false if let transition = self.state.transition { childFrame.origin.x = child.value.displayNode.frame.origin.x @@ -400,10 +419,21 @@ final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelegate { case .push: break } + if updatedLayout.inputHeight != nil { + if !self.canHaveKeyboardFocus { + updatedLayout = updatedLayout.withUpdatedInputHeight(nil) + } + } } else { if isMaster { shouldSyncKeyboard = true } + + if updatedLayout.inputHeight != nil { + if !self.canHaveKeyboardFocus || self.ignoreInputHeight { + updatedLayout = updatedLayout.withUpdatedInputHeight(nil) + } + } } if child.value.displayNode.frame != childFrame { transition.updateFrame(node: child.value.displayNode, frame: childFrame) @@ -411,9 +441,9 @@ final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelegate { if shouldSyncKeyboard && isMaster { self.syncKeyboard(leftEdge: childFrame.minX, transition: transition) } - if child.layout != layout { - child.layout = layout - child.value.containerLayoutUpdated(layout, transition: transition) + if child.layout != updatedLayout { + child.layout = updatedLayout + child.value.containerLayoutUpdated(updatedLayout, transition: transition) } } @@ -430,13 +460,13 @@ final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelegate { private func pendingChildIsReady(_ child: PendingChild) { if let pending = self.state.pending, pending === child { pending.isReady = true - self.performUpdate() + self.performUpdate(transition: .immediate) } } - private func performUpdate() { + private func performUpdate(transition: ContainedViewLayoutTransition) { if let layout = self.state.layout, let canBeClosed = self.state.canBeClosed { - self.update(layout: layout, canBeClosed: canBeClosed, controllers: self.controllers, transition: .immediate) + self.update(layout: layout, canBeClosed: canBeClosed, controllers: self.controllers, transition: transition) } } diff --git a/submodules/Display/Display/Navigation/NavigationController.swift b/submodules/Display/Display/Navigation/NavigationController.swift index 65ae04481e..e8a48dc5d9 100644 --- a/submodules/Display/Display/Navigation/NavigationController.swift +++ b/submodules/Display/Display/Navigation/NavigationController.swift @@ -118,12 +118,18 @@ open class NavigationController: UINavigationController, ContainableController, return self.view as! NavigationControllerView } + var inCallNavigate: (() -> Void)? private var inCallStatusBar: StatusBar? + private var globalScrollToTopNode: ScrollToTopNode? private var rootContainer: RootContainer? private var rootModalFrame: NavigationModalFrame? private var modalContainers: [NavigationModalContainer] = [] + private var overlayContainers: [NavigationOverlayContainer] = [] private var validLayout: ContainerViewLayout? private var validStatusBarStyle: NavigationStatusBarStyle? + private var validStatusBarHidden: Bool = false + + private var currentStatusBarExternalHidden: Bool = false private var scheduledLayoutTransitionRequestId: Int = 0 private var scheduledLayoutTransitionRequest: (Int, ContainedViewLayoutTransition)? @@ -151,7 +157,10 @@ open class NavigationController: UINavigationController, ContainableController, return self._displayNode! } - var statusBarHost: StatusBarHost? + var statusBarHost: StatusBarHost? { + didSet { + } + } var keyboardViewManager: KeyboardViewManager? public func updateMasterDetailsBlackout(_ blackout: MasterDetailLayoutBlackout?, transition: ContainedViewLayoutTransition) { @@ -199,6 +208,9 @@ open class NavigationController: UINavigationController, ContainableController, for modalContainer in self.modalContainers { supportedOrientations = supportedOrientations.intersection(modalContainer.container.combinedSupportedOrientations(currentOrientationToLock: currentOrientationToLock)) } + for overlayContrainer in self.overlayContainers { + supportedOrientations = supportedOrientations.intersection(overlayContrainer.controller.combinedSupportedOrientations(currentOrientationToLock: currentOrientationToLock)) + } return supportedOrientations } @@ -214,18 +226,10 @@ open class NavigationController: UINavigationController, ContainableController, } } if self.isViewLoaded { - if statusBarStyleUpdated { - self.validStatusBarStyle = self.theme.statusBar - let normalStatusBarStyle: UIStatusBarStyle - switch self.theme.statusBar { - case .black: - normalStatusBarStyle = .default - case .white: - normalStatusBarStyle = .lightContent - } - //self.statusBarHost?.setStatusBarStyle(normalStatusBarStyle, animated: false) - } self.controllerView.backgroundColor = theme.emptyAreaColor + if let layout = self.validLayout { + self.containerLayoutUpdated(layout, transition: .immediate) + } } } @@ -239,16 +243,33 @@ open class NavigationController: UINavigationController, ContainableController, } self.validLayout = layout self.updateContainers(layout: layout, transition: transition) - - self.inCallStatusBar?.frame = CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: max(40.0, layout.safeInsets.top))) - self.inCallStatusBar?.updateState(statusBar: nil, withSafeInsets: false, inCallText: "In Call Text", animated: false) } - private func updateContainers(layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { + private weak var currentTopVisibleOverlayContainerStatusBar: NavigationOverlayContainer? = nil + + private func updateContainers(layout rawLayout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { + var layout = rawLayout + + if let globalScrollToTopNode = self.globalScrollToTopNode { + globalScrollToTopNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -1.0), size: CGSize(width: layout.size.width, height: 1.0)) + } + + if let inCallStatusBar = self.inCallStatusBar { + let inCallStatusBarFrame = CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: max(40.0, layout.safeInsets.top))) + if inCallStatusBar.frame.isEmpty { + inCallStatusBar.frame = inCallStatusBarFrame + } else { + transition.updateFrame(node: inCallStatusBar, frame: inCallStatusBarFrame) + } + layout.statusBarHeight = inCallStatusBarFrame.height + self.inCallStatusBar?.frame = inCallStatusBarFrame + } + let navigationLayout = makeNavigationLayout(mode: self.mode, layout: layout, controllers: self._viewControllers) var transition = transition var statusBarStyle: StatusBarStyle = .Ignore + var statusBarHidden = false var animateStatusBarStyleTransition = transition.isAnimated var modalContainers: [NavigationModalContainer] = [] @@ -311,6 +332,56 @@ open class NavigationController: UINavigationController, ContainableController, } self.modalContainers = modalContainers + var previousOverlayContainer: NavigationOverlayContainer? + var topVisibleOverlayContainerWithStatusBar: NavigationOverlayContainer? + for i in (0 ..< self.overlayContainers.count).reversed() { + let overlayContainer = self.overlayContainers[i] + + let containerTransition: ContainedViewLayoutTransition + if overlayContainer.supernode == nil { + containerTransition = .immediate + } else { + containerTransition = transition + } + + containerTransition.updateFrame(node: overlayContainer, frame: CGRect(origin: CGPoint(), size: layout.size)) + overlayContainer.update(layout: layout, transition: containerTransition) + + if overlayContainer.supernode == nil && overlayContainer.isReady { + if let previousOverlayContainer = previousOverlayContainer { + self.displayNode.insertSubnode(overlayContainer, belowSubnode: previousOverlayContainer) + } else if let globalScrollToTopNode = self.globalScrollToTopNode { + self.displayNode.insertSubnode(overlayContainer, belowSubnode: globalScrollToTopNode) + } else { + self.displayNode.addSubnode(overlayContainer) + } + overlayContainer.transitionIn() + } + + if overlayContainer.supernode != nil { + previousOverlayContainer = overlayContainer + let controllerStatusBarStyle = overlayContainer.controller.statusBar.statusBarStyle + switch controllerStatusBarStyle { + case .Black, .White, .Hide: + if topVisibleOverlayContainerWithStatusBar == nil { + topVisibleOverlayContainerWithStatusBar = overlayContainer + } + if case .Hide = controllerStatusBarStyle { + statusBarHidden = true + } else { + statusBarHidden = overlayContainer.controller.statusBar.alpha.isZero + } + case .Ignore: + break + } + } + } + + if self.currentTopVisibleOverlayContainerStatusBar !== topVisibleOverlayContainerWithStatusBar { + self.currentTopVisibleOverlayContainerStatusBar = topVisibleOverlayContainerWithStatusBar + animateStatusBarStyleTransition = true + } + var previousModalContainer: NavigationModalContainer? var visibleModalCount = 0 var topModalDismissProgress: CGFloat = 0.0 @@ -342,6 +413,10 @@ open class NavigationController: UINavigationController, ContainableController, self.displayNode.insertSubnode(modalContainer, belowSubnode: previousModalContainer) } else if let inCallStatusBar = self.inCallStatusBar { self.displayNode.insertSubnode(modalContainer, belowSubnode: inCallStatusBar) + } else if let previousOverlayContainer = previousOverlayContainer { + self.displayNode.insertSubnode(modalContainer, belowSubnode: previousOverlayContainer) + } else if let globalScrollToTopNode = self.globalScrollToTopNode { + self.displayNode.insertSubnode(modalContainer, belowSubnode: globalScrollToTopNode) } else { self.displayNode.addSubnode(modalContainer) } @@ -354,11 +429,14 @@ open class NavigationController: UINavigationController, ContainableController, topModalDismissProgress = modalContainer.dismissProgress if case .compact = layout.metrics.widthClass { modalContainer.keyboardViewManager = self.keyboardViewManager + modalContainer.canHaveKeyboardFocus = true } else { modalContainer.keyboardViewManager = nil + modalContainer.canHaveKeyboardFocus = true } } else { modalContainer.keyboardViewManager = nil + modalContainer.canHaveKeyboardFocus = false } previousModalContainer = modalContainer } @@ -371,8 +449,10 @@ open class NavigationController: UINavigationController, ContainableController, case let .flat(flatContainer): if previousModalContainer == nil { flatContainer.keyboardViewManager = self.keyboardViewManager + flatContainer.canHaveKeyboardFocus = true } else { flatContainer.keyboardViewManager = nil + flatContainer.canHaveKeyboardFocus = false } transition.updateFrame(node: flatContainer, frame: CGRect(origin: CGPoint(), size: layout.size)) flatContainer.update(layout: layout, canBeClosed: false, controllers: controllers, transition: transition) @@ -386,6 +466,13 @@ open class NavigationController: UINavigationController, ContainableController, } strongSelf.updateContainers(layout: layout, transition: transition) } + if previousModalContainer == nil { + flatContainer.keyboardViewManager = self.keyboardViewManager + flatContainer.canHaveKeyboardFocus = true + } else { + flatContainer.keyboardViewManager = nil + flatContainer.canHaveKeyboardFocus = false + } self.displayNode.insertSubnode(flatContainer, at: 0) self.rootContainer = .flat(flatContainer) flatContainer.frame = CGRect(origin: CGPoint(), size: layout.size) @@ -402,6 +489,13 @@ open class NavigationController: UINavigationController, ContainableController, } strongSelf.updateContainers(layout: layout, transition: transition) } + if previousModalContainer == nil { + flatContainer.keyboardViewManager = self.keyboardViewManager + flatContainer.canHaveKeyboardFocus = true + } else { + flatContainer.keyboardViewManager = nil + flatContainer.canHaveKeyboardFocus = false + } self.displayNode.insertSubnode(flatContainer, at: 0) self.rootContainer = .flat(flatContainer) flatContainer.frame = CGRect(origin: CGPoint(), size: layout.size) @@ -413,23 +507,42 @@ open class NavigationController: UINavigationController, ContainableController, case let .flat(flatContainer): let splitContainer = NavigationSplitContainer(theme: self.theme, controllerRemoved: { [weak self] controller in self?.controllerRemoved(controller) + }, scrollToTop: { [weak self] subject in + self?.scrollToTop(subject) }) self.displayNode.insertSubnode(splitContainer, at: 0) self.rootContainer = .split(splitContainer) + if previousModalContainer == nil { + splitContainer.canHaveKeyboardFocus = true + } else { + splitContainer.canHaveKeyboardFocus = false + } splitContainer.frame = CGRect(origin: CGPoint(), size: layout.size) splitContainer.update(layout: layout, masterControllers: masterControllers, detailControllers: detailControllers, transition: .immediate) flatContainer.statusBarStyleUpdated = nil flatContainer.removeFromSupernode() case let .split(splitContainer): + if previousModalContainer == nil { + splitContainer.canHaveKeyboardFocus = true + } else { + splitContainer.canHaveKeyboardFocus = false + } transition.updateFrame(node: splitContainer, frame: CGRect(origin: CGPoint(), size: layout.size)) splitContainer.update(layout: layout, masterControllers: masterControllers, detailControllers: detailControllers, transition: transition) } } else { let splitContainer = NavigationSplitContainer(theme: self.theme, controllerRemoved: { [weak self] controller in self?.controllerRemoved(controller) + }, scrollToTop: { [weak self] subject in + self?.scrollToTop(subject) }) self.displayNode.insertSubnode(splitContainer, at: 0) self.rootContainer = .split(splitContainer) + if previousModalContainer == nil { + splitContainer.canHaveKeyboardFocus = true + } else { + splitContainer.canHaveKeyboardFocus = false + } splitContainer.frame = CGRect(origin: CGPoint(), size: layout.size) splitContainer.update(layout: layout, masterControllers: masterControllers, detailControllers: detailControllers, transition: .immediate) } @@ -439,8 +552,9 @@ open class NavigationController: UINavigationController, ContainableController, switch rootContainer { case let .flat(container): statusBarStyle = container.statusBarStyle + self.globalScrollToTopNode?.isHidden = false case .split: - break + self.globalScrollToTopNode?.isHidden = true } } @@ -559,6 +673,18 @@ open class NavigationController: UINavigationController, ContainableController, } } + if self.inCallStatusBar != nil { + statusBarStyle = .White + } + + if let topVisibleOverlayContainerWithStatusBar = topVisibleOverlayContainerWithStatusBar { + statusBarStyle = topVisibleOverlayContainerWithStatusBar.controller.statusBar.statusBarStyle + } + + if self.currentStatusBarExternalHidden { + statusBarHidden = true + } + let resolvedStatusBarStyle: NavigationStatusBarStyle switch statusBarStyle { case .Ignore, .Hide: @@ -580,6 +706,11 @@ open class NavigationController: UINavigationController, ContainableController, } self.statusBarHost?.setStatusBarStyle(normalStatusBarStyle, animated: animateStatusBarStyleTransition) } + + if self.validStatusBarHidden != statusBarHidden { + self.validStatusBarHidden = statusBarHidden + self.statusBarHost?.setStatusBarHidden(statusBarHidden, animated: animateStatusBarStyleTransition) + } } private func controllerRemoved(_ controller: ViewController) { @@ -589,6 +720,28 @@ open class NavigationController: UINavigationController, ContainableController, public func updateModalTransition(_ value: CGFloat, transition: ContainedViewLayoutTransition) { } + private func scrollToTop(_ subject: NavigationSplitContainerScrollToTop) { + if let _ = self.inCallStatusBar { + self.inCallNavigate?() + } else if let rootContainer = self.rootContainer { + if let modalContainer = self.modalContainers.last { + modalContainer.container.controllers.last?.scrollToTop?() + } else { + switch rootContainer { + case let .flat(container): + container.controllers.last?.scrollToTop?() + case let .split(container): + switch subject { + case .master: + container.masterControllers.last?.scrollToTop?() + case .detail: + container.detailControllers.last?.scrollToTop?() + } + } + } + } + } + public func updateToInterfaceOrientation(_ orientation: UIInterfaceOrientation) { /*for record in self._viewControllers { if let controller = record.controller as? ContainableController { @@ -613,9 +766,11 @@ open class NavigationController: UINavigationController, ContainableController, } self.navigationBar.removeFromSuperview() - /*let inCallStatusBar = StatusBar() - self.displayNode.addSubnode(inCallStatusBar) - self.inCallStatusBar = inCallStatusBar*/ + let globalScrollToTopNode = ScrollToTopNode(action: { [weak self] in + self?.scrollToTop(.master) + }) + self.displayNode.addSubnode(globalScrollToTopNode) + self.globalScrollToTopNode = globalScrollToTopNode } public func pushViewController(_ controller: ViewController) { @@ -750,6 +905,53 @@ open class NavigationController: UINavigationController, ContainableController, } } + public func presentOverlay(controller: ViewController, inGlobal: Bool = false) { + let container = NavigationOverlayContainer(controller: controller, controllerRemoved: { [weak self] controller in + guard let strongSelf = self else { + return + } + for i in 0 ..< strongSelf.overlayContainers.count { + let overlayContainer = strongSelf.overlayContainers[i] + if overlayContainer.controller === controller { + overlayContainer.removeFromSupernode() + strongSelf.overlayContainers.remove(at: i) + break + } + } + if let layout = strongSelf.validLayout { + strongSelf.updateContainers(layout: layout, transition: .immediate) + } + }, statusBarUpdated: { [weak self] transition in + guard let strongSelf = self else { + return + } + if let layout = strongSelf.validLayout { + strongSelf.updateContainers(layout: layout, transition: transition) + } + }) + self.overlayContainers.append(container) + container.isReadyUpdated = { [weak self, weak container] in + guard let strongSelf = self, let container = container else { + return + } + if let layout = strongSelf.validLayout { + strongSelf.updateContainers(layout: layout, transition: .immediate) + } + } + if let layout = self.validLayout { + self.updateContainers(layout: layout, transition: .immediate) + } + } + + func updateExternalStatusBarHidden(_ value: Bool, transition: ContainedViewLayoutTransition) { + if self.currentStatusBarExternalHidden != value { + self.currentStatusBarExternalHidden = value + if let layout = self.validLayout { + self.updateContainers(layout: layout, transition: transition) + } + } + } + override open func present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)? = nil) { preconditionFailure() } @@ -816,4 +1018,49 @@ open class NavigationController: UINavigationController, ContainableController, self.containerLayoutUpdated(validLayout, transition: transition) } } + + public func setForceInCallStatusBar(_ forceInCallStatusBarText: String?, transition: ContainedViewLayoutTransition = .animated(duration: 0.3, curve: .easeInOut)) { + if let forceInCallStatusBarText = forceInCallStatusBarText { + let inCallStatusBar: StatusBar + if let current = self.inCallStatusBar { + inCallStatusBar = current + } else { + inCallStatusBar = StatusBar() + inCallStatusBar.inCallNavigate = { [weak self] in + self?.scrollToTop(.master) + } + inCallStatusBar.alpha = 0.0 + self.inCallStatusBar = inCallStatusBar + + var bottomOverlayContainer: NavigationOverlayContainer? + for overlayContainer in self.overlayContainers { + if overlayContainer.supernode != nil { + bottomOverlayContainer = overlayContainer + break + } + } + + if let bottomOverlayContainer = bottomOverlayContainer { + self.displayNode.insertSubnode(inCallStatusBar, belowSubnode: bottomOverlayContainer) + } else if let globalScrollToTopNode = self.globalScrollToTopNode { + self.displayNode.insertSubnode(inCallStatusBar, belowSubnode: globalScrollToTopNode) + } else { + self.displayNode.addSubnode(inCallStatusBar) + } + transition.updateAlpha(node: inCallStatusBar, alpha: 1.0) + } + if let layout = self.validLayout { + self.containerLayoutUpdated(layout, transition: transition) + inCallStatusBar.updateState(statusBar: nil, withSafeInsets: false, inCallText: forceInCallStatusBarText, animated: false) + } + } else if let inCallStatusBar = self.inCallStatusBar { + self.inCallStatusBar = nil + transition.updateAlpha(node: inCallStatusBar, alpha: 0.0, completion: { [weak inCallStatusBar] _ in + inCallStatusBar?.removeFromSupernode() + }) + if let layout = self.validLayout { + self.containerLayoutUpdated(layout, transition: transition) + } + } + } } diff --git a/submodules/Display/Display/Navigation/NavigationModalContainer.swift b/submodules/Display/Display/Navigation/NavigationModalContainer.swift index dd1141c9d9..22aa86011a 100644 --- a/submodules/Display/Display/Navigation/NavigationModalContainer.swift +++ b/submodules/Display/Display/Navigation/NavigationModalContainer.swift @@ -33,6 +33,12 @@ final class NavigationModalContainer: ASDisplayNode, UIScrollViewDelegate, UIGes } } + var canHaveKeyboardFocus: Bool = false { + didSet { + self.container.canHaveKeyboardFocus = self.canHaveKeyboardFocus + } + } + init(theme: NavigationControllerTheme, controllerRemoved: @escaping (ViewController) -> Void) { self.theme = theme @@ -195,6 +201,8 @@ final class NavigationModalContainer: ASDisplayNode, UIScrollViewDelegate, UIGes self.dismissProgress = dismissProgress self.applyDismissProgress(transition: transition, completion: {}) + + self.view.endEditing(true) } func scrollViewDidScroll(_ scrollView: UIScrollView) { diff --git a/submodules/Display/Display/Navigation/NavigationOverlayContainer.swift b/submodules/Display/Display/Navigation/NavigationOverlayContainer.swift new file mode 100644 index 0000000000..608a999b24 --- /dev/null +++ b/submodules/Display/Display/Navigation/NavigationOverlayContainer.swift @@ -0,0 +1,78 @@ +import Foundation +import UIKit +import AsyncDisplayKit +import SwiftSignalKit + +final class NavigationOverlayContainer: ASDisplayNode { + let controller: ViewController + + private(set) var isReady: Bool = false + var isReadyUpdated: (() -> Void)? + private var isReadyDisposable: Disposable? + + private var validLayout: ContainerViewLayout? + + var keyboardViewManager: KeyboardViewManager? { + didSet { + if self.keyboardViewManager !== oldValue { + } + } + } + + init(controller: ViewController, controllerRemoved: @escaping (ViewController) -> Void, statusBarUpdated: @escaping (ContainedViewLayoutTransition) -> Void) { + self.controller = controller + + super.init() + + self.controller.navigation_setDismiss({ [weak self] in + guard let strongSelf = self else { + return + } + controllerRemoved(strongSelf.controller) + }, rootController: nil) + + self.controller.statusBar.alphaUpdated = { transition in + statusBarUpdated(transition) + } + + self.isReadyDisposable = (self.controller.ready.get() + |> filter { $0 } + |> take(1) + |> deliverOnMainQueue).start(next: { [weak self] _ in + guard let strongSelf = self else { + return + } + if !strongSelf.isReady { + strongSelf.isReady = true + strongSelf.isReadyUpdated?() + } + }) + } + + deinit { + self.isReadyDisposable?.dispose() + } + + override func didLoad() { + super.didLoad() + } + + func update(layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { + let updateLayout = self.validLayout != layout + + self.validLayout = layout + + if updateLayout { + transition.updateFrame(node: self.controller.displayNode, frame: CGRect(origin: CGPoint(), size: layout.size)) + self.controller.containerLayoutUpdated(layout, transition: transition) + } + } + + func transitionIn() { + self.controller.viewWillAppear(false) + self.controller.setIgnoreAppearanceMethodInvocations(true) + self.addSubnode(self.controller.displayNode) + self.controller.setIgnoreAppearanceMethodInvocations(false) + self.controller.viewDidAppear(false) + } +} diff --git a/submodules/Display/Display/Navigation/NavigationSplitContainer.swift b/submodules/Display/Display/Navigation/NavigationSplitContainer.swift index d47a47c6ab..155fd2a186 100644 --- a/submodules/Display/Display/Navigation/NavigationSplitContainer.swift +++ b/submodules/Display/Display/Navigation/NavigationSplitContainer.swift @@ -3,19 +3,42 @@ import UIKit import AsyncDisplayKit import SwiftSignalKit +enum NavigationSplitContainerScrollToTop { + case master + case detail +} + final class NavigationSplitContainer: ASDisplayNode { private var theme: NavigationControllerTheme + private let masterScrollToTopView: ScrollToTopView + private let detailScrollToTopView: ScrollToTopView private let masterContainer: NavigationContainer private let detailContainer: NavigationContainer private let separator: ASDisplayNode - private var masterControllers: [ViewController] = [] - private var detailControllers: [ViewController] = [] + private(set) var masterControllers: [ViewController] = [] + private(set) var detailControllers: [ViewController] = [] - init(theme: NavigationControllerTheme, controllerRemoved: @escaping (ViewController) -> Void) { + var canHaveKeyboardFocus: Bool = false { + didSet { + self.masterContainer.canHaveKeyboardFocus = self.canHaveKeyboardFocus + self.detailContainer.canHaveKeyboardFocus = self.canHaveKeyboardFocus + } + } + + init(theme: NavigationControllerTheme, controllerRemoved: @escaping (ViewController) -> Void, scrollToTop: @escaping (NavigationSplitContainerScrollToTop) -> Void) { self.theme = theme + self.masterScrollToTopView = ScrollToTopView(frame: CGRect()) + self.masterScrollToTopView.action = { + scrollToTop(.master) + } + self.detailScrollToTopView = ScrollToTopView(frame: CGRect()) + self.detailScrollToTopView.action = { + scrollToTop(.detail) + } + self.masterContainer = NavigationContainer(controllerRemoved: controllerRemoved) self.masterContainer.clipsToBounds = true @@ -30,6 +53,8 @@ final class NavigationSplitContainer: ASDisplayNode { self.addSubnode(self.masterContainer) self.addSubnode(self.detailContainer) self.addSubnode(self.separator) + self.view.addSubview(self.masterScrollToTopView) + self.view.addSubview(self.detailScrollToTopView) } func updateTheme(theme: NavigationControllerTheme) { @@ -40,6 +65,9 @@ final class NavigationSplitContainer: ASDisplayNode { let masterWidth = min(max(320.0, floor(layout.size.width / 3.0)), floor(layout.size.width / 2.0)) let detailWidth = layout.size.width - masterWidth + self.masterScrollToTopView.frame = CGRect(origin: CGPoint(x: 0.0, y: -1.0), size: CGSize(width: masterWidth, height: 1.0)) + self.detailScrollToTopView.frame = CGRect(origin: CGPoint(x: masterWidth, y: -1.0), size: CGSize(width: detailWidth, height: 1.0)) + transition.updateFrame(node: self.masterContainer, frame: CGRect(origin: CGPoint(), size: CGSize(width: masterWidth, height: layout.size.height))) transition.updateFrame(node: self.detailContainer, frame: CGRect(origin: CGPoint(x: masterWidth, y: 0.0), size: CGSize(width: detailWidth, height: layout.size.height))) transition.updateFrame(node: self.separator, frame: CGRect(origin: CGPoint(x: masterWidth, y: 0.0), size: CGSize(width: UIScreenPixel, height: layout.size.height))) diff --git a/submodules/Display/Display/ScrollToTopProxyView.swift b/submodules/Display/Display/ScrollToTopProxyView.swift index 3e6f76a24a..d0e8eb459e 100644 --- a/submodules/Display/Display/ScrollToTopProxyView.swift +++ b/submodules/Display/Display/ScrollToTopProxyView.swift @@ -35,3 +35,15 @@ class ScrollToTopView: UIScrollView, UIScrollViewDelegate { return false } } + +class ScrollToTopNode: ASDisplayNode { + init(action: @escaping () -> Void) { + super.init() + + self.setViewBlock({ + let view = ScrollToTopView(frame: CGRect()) + view.action = action + return view + }) + } +} diff --git a/submodules/Display/Display/StatusBar.swift b/submodules/Display/Display/StatusBar.swift index f0e1ae3462..5f6fa9ee22 100644 --- a/submodules/Display/Display/StatusBar.swift +++ b/submodules/Display/Display/StatusBar.swift @@ -68,6 +68,7 @@ public final class StatusBar: ASDisplayNode { didSet { if self.statusBarStyle != oldValue { self.layer.invalidateUpTheTree() + self.alphaUpdated?(.immediate) } } } @@ -94,6 +95,13 @@ public final class StatusBar: ASDisplayNode { } } + var alphaUpdated: ((ContainedViewLayoutTransition) -> Void)? + + public func updateAlpha(_ alpha: CGFloat, transition: ContainedViewLayoutTransition) { + self.alpha = alpha + self.alphaUpdated?(transition) + } + public override init() { self.inCallLabel = StatusBarLabelNode() self.inCallLabel.isUserInteractionEnabled = false diff --git a/submodules/Display/Display/StatusBarHost.swift b/submodules/Display/Display/StatusBarHost.swift index 58f24fcb20..9514657bd7 100644 --- a/submodules/Display/Display/StatusBarHost.swift +++ b/submodules/Display/Display/StatusBarHost.swift @@ -12,5 +12,8 @@ public protocol StatusBarHost { var handleVolumeControl: Signal { get } + var isApplicationInForeground: Bool { get } + func setStatusBarStyle(_ style: UIStatusBarStyle, animated: Bool) + func setStatusBarHidden(_ value: Bool, animated: Bool) } diff --git a/submodules/Display/Display/TabBarController.swift b/submodules/Display/Display/TabBarController.swift index 9bf049704a..5c16bda583 100644 --- a/submodules/Display/Display/TabBarController.swift +++ b/submodules/Display/Display/TabBarController.swift @@ -127,6 +127,15 @@ open class TabBarController: ViewController { self.theme = theme super.init(navigationBarPresentationData: navigationBarPresentationData) + + self.scrollToTop = { [weak self] in + guard let strongSelf = self else { + return + } + if let controller = strongSelf.currentController { + controller.scrollToTop?() + } + } } required public init(coder aDecoder: NSCoder) { diff --git a/submodules/Display/Display/ViewController.swift b/submodules/Display/Display/ViewController.swift index 2ca9484f03..37ddae07ec 100644 --- a/submodules/Display/Display/ViewController.swift +++ b/submodules/Display/Display/ViewController.swift @@ -246,7 +246,7 @@ public enum ViewControllerNavigationPresentation { } private func updateScrollToTopView() { - if self.scrollToTop != nil { + /*if self.scrollToTop != nil { if let displayNode = self._displayNode , self.scrollToTopView == nil { let scrollToTopView = ScrollToTopView(frame: CGRect(x: 0.0, y: -1.0, width: displayNode.bounds.size.width, height: 1.0)) scrollToTopView.action = { [weak self] in @@ -257,7 +257,7 @@ public enum ViewControllerNavigationPresentation { self.scrollToTopView = scrollToTopView self.view.addSubview(scrollToTopView) } - } else if let scrollToTopView = self.scrollToTopView { + } else*/ if let scrollToTopView = self.scrollToTopView { scrollToTopView.removeFromSuperview() self.scrollToTopView = nil } diff --git a/submodules/Display/Display/WindowContent.swift b/submodules/Display/Display/WindowContent.swift index 795f086366..1f654e78cc 100644 --- a/submodules/Display/Display/WindowContent.swift +++ b/submodules/Display/Display/WindowContent.swift @@ -280,7 +280,7 @@ public class Window1 { private var deviceMetrics: DeviceMetrics private let statusBarHost: StatusBarHost? - private let statusBarManager: StatusBarManager? + //private let statusBarManager: StatusBarManager? private let keyboardManager: KeyboardManager? private let keyboardViewManager: KeyboardViewManager? private var statusBarChangeObserver: AnyObject? @@ -312,7 +312,7 @@ public class Window1 { public private(set) var forceInCallStatusBarText: String? = nil public var inCallNavigate: (() -> Void)? { didSet { - self.statusBarManager?.inCallNavigate = self.inCallNavigate + //self.statusBarManager?.inCallNavigate = self.inCallNavigate } } @@ -323,21 +323,17 @@ public class Window1 { private var keyboardTypeChangeTimer: SwiftSignalKit.Timer? - private let volumeControlStatusBar: VolumeControlStatusBar - private let volumeControlStatusBarNode: VolumeControlStatusBarNode + //private let volumeControlStatusBar: VolumeControlStatusBar + //private let volumeControlStatusBarNode: VolumeControlStatusBarNode private var isInteractionBlocked = false - /*private var accessibilityElements: [Any]? { - return self.viewController?.view.accessibilityElements - }*/ - public init(hostView: WindowHostView, statusBarHost: StatusBarHost?) { self.hostView = hostView - self.volumeControlStatusBar = VolumeControlStatusBar(frame: CGRect(origin: CGPoint(x: 0.0, y: -20.0), size: CGSize(width: 100.0, height: 20.0)), shouldBeVisible: statusBarHost?.handleVolumeControl ?? .single(false)) - self.volumeControlStatusBarNode = VolumeControlStatusBarNode() - self.volumeControlStatusBarNode.isHidden = true + //self.volumeControlStatusBar = VolumeControlStatusBar(frame: CGRect(origin: CGPoint(x: 0.0, y: -20.0), size: CGSize(width: 100.0, height: 20.0)), shouldBeVisible: statusBarHost?.handleVolumeControl ?? .single(false)) + //self.volumeControlStatusBarNode = VolumeControlStatusBarNode() + //self.volumeControlStatusBarNode.isHidden = true let boundsSize = self.hostView.eventView.bounds.size self.deviceMetrics = DeviceMetrics(screenSize: UIScreen.main.bounds.size, statusBarHeight: statusBarHost?.statusBarFrame.height ?? defaultStatusBarHeight, onScreenNavigationHeight: self.hostView.onScreenNavigationHeight) @@ -346,12 +342,12 @@ public class Window1 { let statusBarHeight: CGFloat if let statusBarHost = statusBarHost { statusBarHeight = statusBarHost.statusBarFrame.size.height - self.statusBarManager = StatusBarManager(host: statusBarHost, volumeControlStatusBar: self.volumeControlStatusBar, volumeControlStatusBarNode: self.volumeControlStatusBarNode) + //self.statusBarManager = StatusBarManager(host: statusBarHost, volumeControlStatusBar: self.volumeControlStatusBar, volumeControlStatusBarNode: self.volumeControlStatusBarNode) self.keyboardManager = KeyboardManager(host: statusBarHost) self.keyboardViewManager = KeyboardViewManager(host: statusBarHost) } else { statusBarHeight = self.deviceMetrics.statusBarHeight - self.statusBarManager = nil + //self.statusBarManager = nil self.keyboardManager = nil self.keyboardViewManager = nil } @@ -394,7 +390,7 @@ public class Window1 { } self.hostView.layoutSubviews = { [weak self] in - self?.layoutSubviews() + self?.layoutSubviews(force: false) } self.hostView.updateToInterfaceOrientation = { [weak self] orientation in @@ -433,7 +429,7 @@ public class Window1 { }*/ self.presentationContext.view = self.hostView.containerView - self.presentationContext.volumeControlStatusBarNodeView = self.volumeControlStatusBarNode.view + //self.presentationContext.volumeControlStatusBarNodeView = self.volumeControlStatusBarNode.view self.presentationContext.containerLayoutUpdated(containedLayoutForWindowLayout(self.windowLayout, deviceMetrics: self.deviceMetrics), transition: .immediate) self.overlayPresentationContext.containerLayoutUpdated(containedLayoutForWindowLayout(self.windowLayout, deviceMetrics: self.deviceMetrics), transition: .immediate) @@ -455,7 +451,7 @@ public class Window1 { keyboardHeight = max(0.0, keyboardHeight - 24.0) } - print("keyboardHeight: \(keyboardHeight)") + //print("rotation keyboardHeight: \(keyboardHeight)") var duration: Double = (notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0.0 if duration > Double.ulpOfOne { @@ -483,12 +479,31 @@ public class Window1 { } } + var popoverDelta: CGFloat = 0.0 + let screenHeight: CGFloat var inPopover = false if keyboardFrame.width.isEqual(to: UIScreen.main.bounds.width) { + var portraitScreenSize = UIScreen.main.bounds.size + if portraitScreenSize.width > portraitScreenSize.height { + portraitScreenSize = CGSize(width: portraitScreenSize.height, height: portraitScreenSize.width) + } + var portraitLayoutSize = strongSelf.windowLayout.size + if portraitLayoutSize.width > portraitLayoutSize.height { + portraitLayoutSize = CGSize(width: portraitLayoutSize.height, height: portraitLayoutSize.width) + } if abs(strongSelf.windowLayout.size.height - UIScreen.main.bounds.height) > 41.0 { screenHeight = UIScreen.main.bounds.height - inPopover = true + if abs(portraitLayoutSize.height - portraitScreenSize.height) > 41.0 || abs(portraitLayoutSize.width - portraitScreenSize.width) > 41.0 { + popoverDelta = 48.0 + inPopover = true + } + } else if abs(strongSelf.windowLayout.size.height - UIScreen.main.bounds.height) > 39.0 { + screenHeight = UIScreen.main.bounds.height + if abs(portraitLayoutSize.height - portraitScreenSize.height) > 39.0 || abs(portraitLayoutSize.width - portraitScreenSize.width) > 39.0 { + popoverDelta = 40.0 + inPopover = true + } } else { screenHeight = strongSelf.windowLayout.size.height } @@ -503,14 +518,14 @@ public class Window1 { keyboardHeight = max(0.0, screenHeight - keyboardFrame.minY) if inPopover { if strongSelf.windowLayout.onScreenNavigationHeight != nil { - keyboardHeight = max(0.0, keyboardHeight - 24.0) + keyboardHeight = max(0.0, keyboardHeight - popoverDelta / 2.0) } else { - keyboardHeight = max(0.0, keyboardHeight - 48.0) + keyboardHeight = max(0.0, keyboardHeight - popoverDelta) } } } - print("keyboardHeight: \(keyboardHeight)") + print("keyboardHeight: \(keyboardHeight) (raw: \(keyboardFrame))") var duration: Double = (notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0.0 if duration > Double.ulpOfOne { @@ -586,8 +601,8 @@ public class Window1 { self.windowPanRecognizer = recognizer self.hostView.containerView.addGestureRecognizer(recognizer) - self.hostView.containerView.addSubview(self.volumeControlStatusBar) - self.hostView.containerView.addSubview(self.volumeControlStatusBarNode.view) + //self.hostView.containerView.addSubview(self.volumeControlStatusBar) + //self.hostView.containerView.addSubview(self.volumeControlStatusBarNode.view) } public required init(coder aDecoder: NSCoder) { @@ -613,7 +628,7 @@ public class Window1 { } public func setupVolumeControlStatusBarGraphics(_ graphics: (UIImage, UIImage, UIImage)) { - self.volumeControlStatusBarNode.graphics = graphics + //self.volumeControlStatusBarNode.graphics = graphics } public func setForceInCallStatusBar(_ forceInCallStatusBarText: String?, transition: ContainedViewLayoutTransition = .animated(duration: 0.3, curve: .easeInOut)) { @@ -701,6 +716,9 @@ public class Window1 { transition = .immediate } self.updateLayout { $0.update(size: value, metrics: layoutMetricsForScreenSize(value), safeInsets: self.deviceMetrics.safeInsets(inLandscape: value.width > value.height), forceInCallStatusBarText: self.forceInCallStatusBarText, transition: transition, overrideTransition: true) } + if let statusBarHost = self.statusBarHost, !statusBarHost.isApplicationInForeground { + self.layoutSubviews(force: true) + } } private var _rootController: ContainableController? @@ -718,6 +736,9 @@ public class Window1 { if let rootController = rootController as? NavigationController { rootController.statusBarHost = self.statusBarHost rootController.keyboardViewManager = self.keyboardViewManager + rootController.inCallNavigate = { [weak self] in + self?.inCallNavigate?() + } } if !self.windowLayout.size.width.isZero && !self.windowLayout.size.height.isZero { rootController.displayNode.frame = CGRect(origin: CGPoint(), size: self.windowLayout.size) @@ -738,6 +759,9 @@ public class Window1 { } set(value) { for controller in self._topLevelOverlayControllers { + if let controller = controller as? ViewController { + controller.statusBar.alphaUpdated = nil + } controller.view.removeFromSuperview() } self._topLevelOverlayControllers = value @@ -750,7 +774,25 @@ public class Window1 { if let coveringView = self.coveringView { self.hostView.containerView.insertSubview(controller.view, belowSubview: coveringView) } else { - self.hostView.containerView.insertSubview(controller.view, belowSubview: self.volumeControlStatusBarNode.view) + self.hostView.containerView.addSubview(controller.view) + } + + if let controller = controller as? ViewController { + controller.statusBar.alphaUpdated = { [weak self] transition in + guard let strongSelf = self, let navigationController = strongSelf._rootController as? NavigationController else { + return + } + var isStatusBarHidden: Bool = false + for controller in strongSelf._topLevelOverlayControllers { + if let controller = controller as? ViewController { + if case .Hide = controller.statusBar.statusBarStyle { + isStatusBarHidden = true + } + } + } + + navigationController.updateExternalStatusBarHidden(isStatusBarHidden, transition: .animated(duration: 0.3, curve: .easeInOut)) + } } } @@ -771,7 +813,7 @@ public class Window1 { coveringView.layer.removeAnimation(forKey: "opacity") coveringView.layer.allowsGroupOpacity = false coveringView.alpha = 1.0 - self.hostView.containerView.insertSubview(coveringView, belowSubview: self.volumeControlStatusBarNode.view) + self.hostView.containerView.addSubview(coveringView) if !self.windowLayout.size.width.isZero { coveringView.frame = CGRect(origin: CGPoint(), size: self.windowLayout.size) coveringView.updateLayout(self.windowLayout.size) @@ -781,7 +823,7 @@ public class Window1 { } } - private func layoutSubviews() { + private func layoutSubviews(force: Bool) { var hasPreview = false var updatedHasPreview = false for subview in self.hostView.eventView.subviews { @@ -796,7 +838,7 @@ public class Window1 { updatedHasPreview = true } - if self.tracingStatusBarsInvalidated || updatedHasPreview, let statusBarManager = statusBarManager, let keyboardManager = keyboardManager { + if self.tracingStatusBarsInvalidated || updatedHasPreview, let keyboardManager = keyboardManager { self.tracingStatusBarsInvalidated = false /*if self.statusBarHidden { @@ -902,7 +944,9 @@ public class Window1 { } } - if !UIWindow.isDeviceRotating() { + if force { + self.commitUpdatingLayout() + } else if !UIWindow.isDeviceRotating() { if !self.hostView.isUpdatingOrientationLayout { self.commitUpdatingLayout() } else { @@ -967,6 +1011,9 @@ public class Window1 { let boundsSize = updatingLayout.layout.size let isLandscape = boundsSize.width > boundsSize.height var statusBarHeight: CGFloat? = self.deviceMetrics.statusBarHeight(for: boundsSize) + if let statusBarHeightValue = statusBarHeight, let statusBarHost = self.statusBarHost { + statusBarHeight = max(statusBarHeightValue, statusBarHost.statusBarFrame.size.height) + } if self.deviceMetrics.type == .tablet, let onScreenNavigationHeight = self.hostView.onScreenNavigationHeight, onScreenNavigationHeight != self.deviceMetrics.onScreenNavigationHeight(inLandscape: false) { self.deviceMetrics = DeviceMetrics(screenSize: UIScreen.main.bounds.size, statusBarHeight: statusBarHeight ?? defaultStatusBarHeight, onScreenNavigationHeight: onScreenNavigationHeight) @@ -1023,8 +1070,8 @@ public class Window1 { }) } - self.volumeControlStatusBarNode.frame = CGRect(origin: CGPoint(), size: self.windowLayout.size) - self.volumeControlStatusBarNode.updateLayout(layout: childLayout, transition: updatingLayout.transition) + //self.volumeControlStatusBarNode.frame = CGRect(origin: CGPoint(), size: self.windowLayout.size) + //self.volumeControlStatusBarNode.updateLayout(layout: childLayout, transition: updatingLayout.transition) if let coveringView = self.coveringView { coveringView.frame = CGRect(origin: CGPoint(), size: self.windowLayout.size) @@ -1035,7 +1082,12 @@ public class Window1 { } public func present(_ controller: ContainableController, on level: PresentationSurfaceLevel, blockInteraction: Bool = false, completion: @escaping () -> Void = {}) { - self.presentationContext.present(controller, on: level, blockInteraction: blockInteraction, completion: completion) + if let navigationController = self._rootController as? NavigationController, let controller = controller as? ViewController { + navigationController.presentOverlay(controller: controller, inGlobal: false) + } else { + assertionFailure() + } + //self.presentationContext.present(controller, on: level, blockInteraction: blockInteraction, completion: completion) } public func presentInGlobalOverlay(_ controller: ContainableController) { diff --git a/submodules/GalleryUI/Sources/GalleryControllerNode.swift b/submodules/GalleryUI/Sources/GalleryControllerNode.swift index 92d0f0f082..6cdd05663a 100644 --- a/submodules/GalleryUI/Sources/GalleryControllerNode.swift +++ b/submodules/GalleryUI/Sources/GalleryControllerNode.swift @@ -275,14 +275,14 @@ open class GalleryControllerNode: ASDisplayNode, UIScrollViewDelegate, UIGesture UIView.animate(withDuration: 0.3, animations: { let alpha: CGFloat = self.areControlsHidden ? 0.0 : 1.0 self.navigationBar?.alpha = alpha - self.statusBar?.alpha = alpha + self.statusBar?.updateAlpha(alpha, transition: .animated(duration: 0.3, curve: .easeInOut)) self.footerNode.alpha = alpha self.updateThumbnailContainerNodeAlpha(.immediate) }) } else { let alpha: CGFloat = self.areControlsHidden ? 0.0 : 1.0 self.navigationBar?.alpha = alpha - self.statusBar?.alpha = alpha + self.statusBar?.updateAlpha(alpha, transition: .immediate) self.footerNode.alpha = alpha self.updateThumbnailContainerNodeAlpha(.immediate) } @@ -374,7 +374,11 @@ open class GalleryControllerNode: ASDisplayNode, UIScrollViewDelegate, UIGesture self.updateThumbnailContainerNodeAlpha(.immediate) if !self.areControlsHidden { - self.statusBar?.alpha = transition + if transition < 0.5 { + self.statusBar?.updateAlpha(0.0, transition: .animated(duration: 0.3, curve: .easeInOut)) + } else { + self.statusBar?.updateAlpha(1.0, transition: .animated(duration: 0.3, curve: .easeInOut)) + } self.navigationBar?.alpha = transition self.footerNode.alpha = transition diff --git a/submodules/ItemListUI/Sources/ItemListControllerNode.swift b/submodules/ItemListUI/Sources/ItemListControllerNode.swift index 5524d79f49..8501bee00e 100644 --- a/submodules/ItemListUI/Sources/ItemListControllerNode.swift +++ b/submodules/ItemListUI/Sources/ItemListControllerNode.swift @@ -364,10 +364,10 @@ open class ItemListControllerNode: ASDisplayNode, UISc addedInsets = UIEdgeInsets(top: 0.0, left: inset, bottom: 0.0, right: inset) if self.leftOverlayNode.supernode == nil { - self.addSubnode(self.leftOverlayNode) + self.insertSubnode(self.leftOverlayNode, aboveSubnode: self.listNode) } if self.rightOverlayNode.supernode == nil { - self.addSubnode(self.rightOverlayNode) + self.insertSubnode(self.rightOverlayNode, aboveSubnode: self.listNode) } } else { insets.left += layout.safeInsets.left diff --git a/submodules/LegacyComponents/LegacyComponents/TGModernGalleryController.m b/submodules/LegacyComponents/LegacyComponents/TGModernGalleryController.m index 6dd12ae19d..652f3fb09b 100644 --- a/submodules/LegacyComponents/LegacyComponents/TGModernGalleryController.m +++ b/submodules/LegacyComponents/LegacyComponents/TGModernGalleryController.m @@ -93,13 +93,15 @@ - (BOOL)prefersStatusBarHidden { - if (!TGIsPad() && iosMajorVersion() >= 11 && UIInterfaceOrientationIsLandscape([[LegacyComponentsGlobals provider] applicationStatusBarOrientation])) + return true; + + /*if (!TGIsPad() && iosMajorVersion() >= 11 && UIInterfaceOrientationIsLandscape([[LegacyComponentsGlobals provider] applicationStatusBarOrientation])) return true; if (self.childViewControllers.count > 0) return [self.childViewControllers.lastObject prefersStatusBarHidden]; - return [super prefersStatusBarHidden]; + return [super prefersStatusBarHidden];*/ } - (UIRectEdge)preferredScreenEdgesDeferringSystemGestures @@ -262,7 +264,7 @@ { [UIView animateWithDuration:0.2 animations:^ { - [strongSelf->_context setApplicationStatusBarAlpha:1.0f]; + //[strongSelf->_context setApplicationStatusBarAlpha:1.0f]; }]; } @@ -1155,7 +1157,7 @@ static CGFloat transformRotation(CGAffineTransform transform) { [UIView animateWithDuration:0.2 animations:^ { - [_context setApplicationStatusBarAlpha:1.0f]; + //[_context setApplicationStatusBarAlpha:1.0f]; }]; } } @@ -1228,7 +1230,7 @@ static CGFloat transformRotation(CGAffineTransform transform) if (self.adjustsStatusBarVisibility) { - [_context setApplicationStatusBarAlpha:1.0f]; + //[_context setApplicationStatusBarAlpha:1.0f]; } } diff --git a/submodules/LegacyUI/Sources/LegacyController.swift b/submodules/LegacyUI/Sources/LegacyController.swift index 1a617c6021..406f5e5581 100644 --- a/submodules/LegacyUI/Sources/LegacyController.swift +++ b/submodules/LegacyUI/Sources/LegacyController.swift @@ -247,7 +247,7 @@ public final class LegacyControllerContext: NSObject, LegacyComponentsContext { public func setApplicationStatusBarAlpha(_ alpha: CGFloat) { if let controller = self.controller { - controller.statusBar.alpha = alpha + controller.statusBar.updateAlpha(alpha, transition: .immediate) self.updateDeferScreenEdgeGestures() } } diff --git a/submodules/LocalizedPeerData/Sources/PeerTitle.swift b/submodules/LocalizedPeerData/Sources/PeerTitle.swift index 6f4fdd0d0b..6230f7a2c5 100644 --- a/submodules/LocalizedPeerData/Sources/PeerTitle.swift +++ b/submodules/LocalizedPeerData/Sources/PeerTitle.swift @@ -21,6 +21,8 @@ public extension Peer { } } else if let lastName = user.lastName { return lastName + } else if let phone = user.phone { + return "+\(phone)" } else { return strings.User_DeletedAccount } diff --git a/submodules/SSignalKit/SwiftSignalKit/SwiftSignalKit.xcodeproj/xcshareddata/xcschemes/SwiftSignalKit.xcscheme b/submodules/SSignalKit/SwiftSignalKit/SwiftSignalKit.xcodeproj/xcshareddata/xcschemes/SwiftSignalKit.xcscheme index 843e7441be..c82fe8764f 100644 --- a/submodules/SSignalKit/SwiftSignalKit/SwiftSignalKit.xcodeproj/xcshareddata/xcschemes/SwiftSignalKit.xcscheme +++ b/submodules/SSignalKit/SwiftSignalKit/SwiftSignalKit.xcodeproj/xcshareddata/xcschemes/SwiftSignalKit.xcscheme @@ -29,6 +29,8 @@ shouldUseLaunchSchemeArgsEnv = "YES"> + + + + + + + + mapToSignal { context in return context.account.postbox.preferencesView(keys: [PreferencesKeys.appConfiguration]) |> map { view -> Bool in - let appConfiguration = view.values[PreferencesKeys.appConfiguration] as? AppConfiguration ?? .defaultValue - let configuration = WalletConfiguration.with(appConfiguration: appConfiguration) - return configuration.config != nil + if #available(iOSApplicationExtension 10.3, iOS 10.3, *) { + let appConfiguration = view.values[PreferencesKeys.appConfiguration] as? AppConfiguration ?? .defaultValue + let configuration = WalletConfiguration.with(appConfiguration: appConfiguration) + return configuration.config != nil + } else { + return false + } } } @@ -1375,7 +1379,7 @@ public func settingsController(context: AccountContext, accountManager: AccountM (controller?.navigationController as? NavigationController)?.replaceAllButRootController(value, animated: true, animationOptions: [.removeOnMasterDetails]) } presentControllerImpl = { [weak controller] value, arguments in - controller?.present(value, in: .window(.root), with: arguments ?? ViewControllerPresentationArguments(presentationAnimation: .modalSheet), blockInteraction: true) + controller?.present(value, in: .window(.root), with: arguments, blockInteraction: true) } presentInGlobalOverlayImpl = { [weak controller] value, arguments in controller?.presentInGlobalOverlay(value, with: arguments) diff --git a/submodules/SettingsUI/Sources/Terms of Service/TermsOfServiceController.swift b/submodules/SettingsUI/Sources/Terms of Service/TermsOfServiceController.swift index 2beff53b73..bcddf5ae69 100644 --- a/submodules/SettingsUI/Sources/Terms of Service/TermsOfServiceController.swift +++ b/submodules/SettingsUI/Sources/Terms of Service/TermsOfServiceController.swift @@ -54,7 +54,7 @@ public extension TermsOfServiceControllerTheme { } } -public class TermsOfServiceController: ViewController { +public class TermsOfServiceController: ViewController, StandalonePresentableController { private var controllerNode: TermsOfServiceControllerNode { return self.displayNode as! TermsOfServiceControllerNode } diff --git a/submodules/SettingsUI/Sources/Themes/ThemePreviewControllerNode.swift b/submodules/SettingsUI/Sources/Themes/ThemePreviewControllerNode.swift index bc518970b3..a58d47df20 100644 --- a/submodules/SettingsUI/Sources/Themes/ThemePreviewControllerNode.swift +++ b/submodules/SettingsUI/Sources/Themes/ThemePreviewControllerNode.swift @@ -271,6 +271,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate { override func didLoad() { super.didLoad() + self.scrollNode.view.disablesInteractiveTransitionGestureRecognizer = true self.scrollNode.view.showsHorizontalScrollIndicator = false self.scrollNode.view.isPagingEnabled = true self.scrollNode.view.delegate = self diff --git a/submodules/TelegramCore/TelegramCore/PeerUtils.swift b/submodules/TelegramCore/TelegramCore/PeerUtils.swift index 20a7762670..6e3f3d50ba 100644 --- a/submodules/TelegramCore/TelegramCore/PeerUtils.swift +++ b/submodules/TelegramCore/TelegramCore/PeerUtils.swift @@ -129,7 +129,7 @@ public extension Peer { var isDeleted: Bool { switch self { case let user as TelegramUser: - return user.firstName == nil && user.lastName == nil + return user.firstName == nil && user.lastName == nil && user.phone == nil default: return false } diff --git a/submodules/TelegramCore/TelegramCore/Wallets.swift b/submodules/TelegramCore/TelegramCore/Wallets.swift index f633d02d5d..64738ea8bd 100644 --- a/submodules/TelegramCore/TelegramCore/Wallets.swift +++ b/submodules/TelegramCore/TelegramCore/Wallets.swift @@ -28,6 +28,7 @@ public enum TonKeychainEncryptDataError { public enum TonKeychainDecryptDataError { case generic case publicKeyMismatch + case cancelled } public struct TonKeychain { @@ -332,8 +333,8 @@ public final class TonInstance { fileprivate func walletRestoreWords(walletInfo: WalletInfo, keychain: TonKeychain, serverSalt: Data) -> Signal<[String], WalletRestoreWordsError> { return keychain.decrypt(walletInfo.encryptedSecret) - |> mapError { _ -> WalletRestoreWordsError in - return .secretDecryptionFailed + |> mapError { error -> WalletRestoreWordsError in + return .secretDecryptionFailed(error) } |> mapToSignal { decryptedSecret -> Signal<[String], WalletRestoreWordsError> in return Signal { subscriber in @@ -365,8 +366,8 @@ public final class TonInstance { fileprivate func deleteLocalWalletData(walletInfo: WalletInfo, keychain: TonKeychain, serverSalt: Data) -> Signal { return keychain.decrypt(walletInfo.encryptedSecret) - |> mapError { _ -> DeleteLocalWalletDataError in - return .secretDecryptionFailed + |> mapError { error -> DeleteLocalWalletDataError in + return .secretDecryptionFailed(error) } |> mapToSignal { decryptedSecret -> Signal in return Signal { subscriber in @@ -581,7 +582,7 @@ public func importWallet(postbox: Postbox, network: Network, tonInstance: TonIns public enum DeleteLocalWalletDataError { case generic - case secretDecryptionFailed + case secretDecryptionFailed(TonKeychainDecryptDataError) } public func deleteLocalWalletData(postbox: Postbox, network: Network, tonInstance: TonInstance, keychain: TonKeychain, walletInfo: WalletInfo) -> Signal { @@ -612,7 +613,7 @@ public func deleteLocalWalletData(postbox: Postbox, network: Network, tonInstanc public enum WalletRestoreWordsError { case generic - case secretDecryptionFailed + case secretDecryptionFailed(TonKeychainDecryptDataError) } public func walletRestoreWords(network: Network, walletInfo: WalletInfo, tonInstance: TonInstance, keychain: TonKeychain) -> Signal<[String], WalletRestoreWordsError> { diff --git a/submodules/TelegramUI/TelegramUI/AppDelegate.swift b/submodules/TelegramUI/TelegramUI/AppDelegate.swift index 55b3a7ae91..bad165bda5 100644 --- a/submodules/TelegramUI/TelegramUI/AppDelegate.swift +++ b/submodules/TelegramUI/TelegramUI/AppDelegate.swift @@ -56,6 +56,15 @@ private let keyboardWindowClass: AnyClass? = { private class ApplicationStatusBarHost: StatusBarHost { private let application = UIApplication.shared + var isApplicationInForeground: Bool { + switch self.application.applicationState { + case .background: + return false + default: + return true + } + } + var statusBarFrame: CGRect { return self.application.statusBarFrame } @@ -71,6 +80,10 @@ private class ApplicationStatusBarHost: StatusBarHost { self.application.setStatusBarStyle(style, animated: animated) } + func setStatusBarHidden(_ value: Bool, animated: Bool) { + self.application.setStatusBarHidden(value, with: animated ? .fade : .none) + } + var statusBarWindow: UIView? { return self.application.value(forKey: "statusBarWindow") as? UIView } @@ -664,6 +677,7 @@ final class SharedApplicationContext { #if targetEnvironment(simulator) tonKeychain = TonKeychain(encryptionPublicKey: { //return .single(nil) + //return .single("1".data(using: .utf8)!) return .single(Data()) }, encrypt: { data in return Signal { subscriber in @@ -701,11 +715,17 @@ final class SharedApplicationContext { } }, decrypt: { encryptedData in return Signal { subscriber in - BuildConfig.decryptApplicationSecret(encryptedData.data, publicKey: encryptedData.publicKey, baseAppBundleId: baseAppBundleId, completion: { result in + BuildConfig.decryptApplicationSecret(encryptedData.data, publicKey: encryptedData.publicKey, baseAppBundleId: baseAppBundleId, completion: { result, cancelled in if let result = result { subscriber.putNext(result) } else { - subscriber.putError(.generic) + let error: TonKeychainDecryptDataError + if cancelled { + error = .cancelled + } else { + error = .generic + } + subscriber.putError(error) } subscriber.putCompletion() }) @@ -1259,9 +1279,12 @@ final class SharedApplicationContext { #endif } + if UIApplication.shared.isStatusBarHidden { + UIApplication.shared.setStatusBarHidden(false, with: .none) + } NotificationCenter.default.addObserver(forName: UIWindow.didBecomeHiddenNotification, object: nil, queue: nil, using: { notification in if UIApplication.shared.isStatusBarHidden { - UIApplication.shared.setStatusBarHidden(false, with: .none) + //UIApplication.shared.setStatusBarHidden(false, with: .none) } }) return true diff --git a/submodules/TelegramUI/TelegramUI/ApplicationContext.swift b/submodules/TelegramUI/TelegramUI/ApplicationContext.swift index 1525646fc4..f08b8ca648 100644 --- a/submodules/TelegramUI/TelegramUI/ApplicationContext.swift +++ b/submodules/TelegramUI/TelegramUI/ApplicationContext.swift @@ -456,6 +456,7 @@ final class AuthorizedApplicationContext { }, expandAction: { expandData in if let strongSelf = self { let chatController = ChatControllerImpl(context: strongSelf.context, chatLocation: .peer(firstMessage.id.peerId), mode: .overlay) + //chatController.navigation_setNavigationController(strongSelf.rootController) (strongSelf.rootController.viewControllers.last as? ViewController)?.present(chatController, in: .window(.root), with: ChatControllerOverlayPresentationData(expandData: expandData())) } })) diff --git a/submodules/TelegramUI/TelegramUI/ChatController.swift b/submodules/TelegramUI/TelegramUI/ChatController.swift index 48ff3f22b2..bdca97cdf8 100644 --- a/submodules/TelegramUI/TelegramUI/ChatController.swift +++ b/submodules/TelegramUI/TelegramUI/ChatController.swift @@ -2312,7 +2312,16 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G private func themeAndStringsUpdated() { self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil) - self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style + switch self.presentationInterfaceState.mode { + case .standard: + self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style + self.deferScreenEdgeGestures = [] + case .overlay: + self.statusBar.statusBarStyle = .Hide + self.deferScreenEdgeGestures = [.top] + case .inline: + self.statusBar.statusBarStyle = .Ignore + } self.navigationBar?.updatePresentationData(NavigationBarPresentationData(presentationData: self.presentationData)) self.chatTitleView?.updateThemeAndStrings(theme: self.presentationData.theme, strings: self.presentationData.strings) self.updateChatPresentationInterfaceState(animated: false, interactive: false, { state in @@ -2589,22 +2598,19 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G self.chatDisplayNode.historyNode.contentPositionChanged = { [weak self] offset in if let strongSelf = self { let offsetAlpha: CGFloat - if case let .standard(previewing) = strongSelf.presentationInterfaceState.mode, previewing { - offsetAlpha = 0.0 - } else { - switch offset { - case let .known(offset): - if offset < 40.0 { - offsetAlpha = 0.0 - } else { - offsetAlpha = 1.0 - } - case .unknown: - offsetAlpha = 1.0 - case .none: + switch offset { + case let .known(offset): + if offset < 40.0 { offsetAlpha = 0.0 - } + } else { + offsetAlpha = 1.0 + } + case .unknown: + offsetAlpha = 1.0 + case .none: + offsetAlpha = 0.0 } + strongSelf.chatDisplayNode.navigateButtons.displayDownButton = !offsetAlpha.isZero } } diff --git a/submodules/TelegramUI/TelegramUI/ChatControllerNode.swift b/submodules/TelegramUI/TelegramUI/ChatControllerNode.swift index e894672ebe..e8b0d009e0 100644 --- a/submodules/TelegramUI/TelegramUI/ChatControllerNode.swift +++ b/submodules/TelegramUI/TelegramUI/ChatControllerNode.swift @@ -1903,6 +1903,9 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { switch self.chatPresentationInterfaceState.mode { case .standard(previewing: true): + if let result = self.navigateButtons.hitTest(self.view.convert(point, to: self.navigateButtons.view), with: event) { + return result + } if self.bounds.contains(point) { return self.historyNode.view } diff --git a/submodules/TelegramUI/TelegramUI/NotificationContainerController.swift b/submodules/TelegramUI/TelegramUI/NotificationContainerController.swift index f68ff574a2..bf8dd951d1 100644 --- a/submodules/TelegramUI/TelegramUI/NotificationContainerController.swift +++ b/submodules/TelegramUI/TelegramUI/NotificationContainerController.swift @@ -15,6 +15,8 @@ public final class NotificationContainerController: ViewController { private var presentationData: PresentationData private var presentationDataDisposable: Disposable? + private var validLayout: ContainerViewLayout? + public init(context: AccountContext) { self.presentationData = context.sharedContext.currentPresentationData.with { $0 } @@ -61,7 +63,15 @@ public final class NotificationContainerController: ViewController { self.controllerNode.displayingItemsUpdated = { [weak self] value in if let strongSelf = self { - strongSelf.statusBar.statusBarStyle = value ? .Hide : .Ignore + var statusBarHidden = false + if value, let layout = strongSelf.validLayout { + if let statusBarHeight = layout.statusBarHeight, statusBarHeight > 20.0 { + statusBarHidden = false + } else { + statusBarHidden = true + } + } + strongSelf.statusBar.statusBarStyle = statusBarHidden ? .Hide : .Ignore if value { strongSelf.deferScreenEdgeGestures = [.top] } else { @@ -72,6 +82,8 @@ public final class NotificationContainerController: ViewController { } override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { + self.validLayout = layout + super.containerLayoutUpdated(layout, transition: transition) self.controllerNode.containerLayoutUpdated(layout, transition: transition) diff --git a/submodules/TelegramUI/TelegramUI/NotificationContainerControllerNode.swift b/submodules/TelegramUI/TelegramUI/NotificationContainerControllerNode.swift index 3fa4ed39c7..189ee12d1c 100644 --- a/submodules/TelegramUI/TelegramUI/NotificationContainerControllerNode.swift +++ b/submodules/TelegramUI/TelegramUI/NotificationContainerControllerNode.swift @@ -68,29 +68,19 @@ final class NotificationContainerControllerNode: ASDisplayNode { if let (item, topItemNode) = self.topItemAndNode { if item.groupingKey == key { self.topItemAndNode = nil + self.displayingItemsUpdated?(false) topItemNode.animateOut(completion: { [weak self, weak topItemNode] in topItemNode?.removeFromSupernode() - - if let strongSelf = self, strongSelf.topItemAndNode == nil { - strongSelf.displayingItemsUpdated?(false) - } }) } } } func enqueue(_ item: NotificationItem) { - var updatedDisplayingItems = false if let (_, topItemNode) = self.topItemAndNode { topItemNode.animateOut(completion: { [weak self, weak topItemNode] in topItemNode?.removeFromSupernode() - - if let strongSelf = self, strongSelf.topItemAndNode == nil { - strongSelf.displayingItemsUpdated?(false) - } }) - } else { - updatedDisplayingItems = true } var useCompactLayout = false @@ -138,9 +128,7 @@ final class NotificationContainerControllerNode: ASDisplayNode { containerNode.animateIn() } - if updatedDisplayingItems { - self.displayingItemsUpdated?(true) - } + self.displayingItemsUpdated?(true) self.resetTimeoutTimer() } @@ -172,12 +160,9 @@ final class NotificationContainerControllerNode: ASDisplayNode { if let strongSelf = self { if let (_, topItemNode) = strongSelf.topItemAndNode { strongSelf.topItemAndNode = nil + strongSelf.displayingItemsUpdated?(false) topItemNode.animateOut(completion: { [weak topItemNode] in topItemNode?.removeFromSupernode() - - if let strongSelf = self, strongSelf.topItemAndNode == nil { - strongSelf.displayingItemsUpdated?(false) - } }) } } diff --git a/submodules/TelegramUI/TelegramUI/SharedAccountContext.swift b/submodules/TelegramUI/TelegramUI/SharedAccountContext.swift index 3eb9b193aa..f495e02938 100644 --- a/submodules/TelegramUI/TelegramUI/SharedAccountContext.swift +++ b/submodules/TelegramUI/TelegramUI/SharedAccountContext.swift @@ -842,10 +842,13 @@ public final class SharedAccountContextImpl: SharedAccountContext { } else { text = presentationData.strings.Call_StatusBar("").0 } - - self.mainWindow?.setForceInCallStatusBar(text) + if let navigationController = self.mainWindow?.viewController as? NavigationController { + navigationController.setForceInCallStatusBar(text) + } } else { - self.mainWindow?.setForceInCallStatusBar(nil) + if let navigationController = self.mainWindow?.viewController as? NavigationController { + navigationController.setForceInCallStatusBar(nil) + } } } diff --git a/submodules/WalletUI/Sources/WalletSplashScreen.swift b/submodules/WalletUI/Sources/WalletSplashScreen.swift index a6de99fec9..afce794d44 100644 --- a/submodules/WalletUI/Sources/WalletSplashScreen.swift +++ b/submodules/WalletUI/Sources/WalletSplashScreen.swift @@ -94,16 +94,20 @@ public final class WalletSplashScreen: ViewController { return } strongSelf.sendGrams(walletInfo: walletInfo, decryptedSecret: decryptedSecret, address: address, amount: amount, textMessage: textMessage, forceIfDestinationNotInitialized: false, randomId: randomId, serverSalt: serverSalt) - }, error: { [weak self] _ in + }, error: { [weak self] error in guard let strongSelf = self else { return } - let text = strongSelf.presentationData.strings.Wallet_Send_ErrorDecryptionFailed - let controller = textAlertController(context: strongSelf.context, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: { - self?.dismiss() - })]) - strongSelf.present(controller, in: .window(.root)) - strongSelf.dismiss() + if case .cancelled = error { + strongSelf.dismiss() + } else { + let text = strongSelf.presentationData.strings.Wallet_Send_ErrorDecryptionFailed + let controller = textAlertController(context: strongSelf.context, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: { + self?.dismiss() + })]) + strongSelf.present(controller, in: .window(.root)) + strongSelf.dismiss() + } }) case .sent: self.navigationItem.setLeftBarButton(UIBarButtonItem(customDisplayNode: ASDisplayNode())!, animated: false) @@ -235,15 +239,18 @@ public final class WalletSplashScreen: ViewController { strongSelf.mode = .created(walletInfo, wordList) controller.dismiss() strongSelf.push(WalletWordDisplayScreen(context: strongSelf.context, tonContext: strongSelf.tonContext, walletInfo: walletInfo, wordList: wordList, mode: .check, walletCreatedPreloadState: strongSelf.walletCreatedPreloadState)) - }, error: { _ in + }, error: { error in guard let strongSelf = self else { return } controller.dismiss() - strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: strongSelf.presentationData.theme), title: strongSelf.presentationData.strings.Wallet_Created_ExportErrorTitle, text: strongSelf.presentationData.strings.Wallet_Created_ExportErrorText, actions: [ - TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: { - }) - ], actionLayout: .vertical), in: .window(.root)) + if case let .secretDecryptionFailed(.cancelled) = error { + } else { + strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: strongSelf.presentationData.theme), title: strongSelf.presentationData.strings.Wallet_Created_ExportErrorTitle, text: strongSelf.presentationData.strings.Wallet_Created_ExportErrorText, actions: [ + TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: { + }) + ], actionLayout: .vertical), in: .window(.root)) + } }) } case let .success(walletInfo): @@ -720,16 +727,7 @@ private final class WalletSplashScreenNode: ViewControllerTracingNode { let secondaryActionSize = self.secondaryActionTitleNode.updateLayout(CGSize(width: layout.size.width - sideInset * 2.0, height: layout.size.height)) let contentHeight = iconSize.height + iconSpacing + titleSize.height + titleSpacing + textSize.height - let contentVerticalOrigin = floor((layout.size.height - contentHeight - iconSize.height / 2.0) / 2.0) - - let iconFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - iconSize.width) / 2.0), y: contentVerticalOrigin), size: iconSize).offsetBy(dx: iconOffset.x, dy: iconOffset.y) - transition.updateFrameAdditive(node: self.iconNode, frame: iconFrame) - self.animationNode.updateLayout(size: iconFrame.size) - transition.updateFrameAdditive(node: self.animationNode, frame: iconFrame) - let titleFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - titleSize.width) / 2.0), y: iconFrame.maxY + iconSpacing), size: titleSize) - transition.updateFrameAdditive(node: self.titleNode, frame: titleFrame) - let textFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - textSize.width) / 2.0), y: titleFrame.maxY + titleSpacing), size: textSize) - transition.updateFrameAdditive(node: self.textNode, frame: textFrame) + var contentVerticalOrigin = floor((layout.size.height - contentHeight - iconSize.height / 2.0) / 2.0) let minimalBottomInset: CGFloat = 60.0 let bottomInset = layout.intrinsicInsets.bottom + max(minimalBottomInset, termsSize.height + termsSpacing * 2.0) @@ -740,12 +738,27 @@ private final class WalletSplashScreenNode: ViewControllerTracingNode { transition.updateFrame(node: self.buttonNode, frame: buttonFrame) self.buttonNode.updateLayout(width: buttonFrame.width, transition: transition) + var maxContentVerticalOrigin = buttonFrame.minY - 12.0 - contentHeight + if !secondaryActionSize.width.isZero { let secondaryActionFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - secondaryActionSize.width) / 2.0), y: buttonFrame.minY - 20.0 - secondaryActionSize.height), size: secondaryActionSize) transition.updateFrameAdditive(node: self.secondaryActionTitleNode, frame: secondaryActionFrame) transition.updateFrame(node: self.secondaryActionButtonNode, frame: secondaryActionFrame.insetBy(dx: -10.0, dy: -10.0)) + + maxContentVerticalOrigin = secondaryActionFrame.minY - 12.0 - contentHeight } + contentVerticalOrigin = min(contentVerticalOrigin, maxContentVerticalOrigin) + + let iconFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - iconSize.width) / 2.0), y: contentVerticalOrigin), size: iconSize).offsetBy(dx: iconOffset.x, dy: iconOffset.y) + transition.updateFrameAdditive(node: self.iconNode, frame: iconFrame) + self.animationNode.updateLayout(size: iconFrame.size) + transition.updateFrameAdditive(node: self.animationNode, frame: iconFrame) + let titleFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - titleSize.width) / 2.0), y: iconFrame.maxY + iconSpacing), size: titleSize) + transition.updateFrameAdditive(node: self.titleNode, frame: titleFrame) + let textFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - textSize.width) / 2.0), y: titleFrame.maxY + titleSpacing), size: textSize) + transition.updateFrameAdditive(node: self.textNode, frame: textFrame) + let termsFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - termsSize.width) / 2.0), y: buttonFrame.maxY + floor((layout.size.height - layout.intrinsicInsets.bottom - buttonFrame.maxY - termsSize.height) / 2.0)), size: termsSize) transition.updateFrameAdditive(node: self.termsNode, frame: termsFrame) } From 772f46135229c5644148ebd9725224a6d94d36a9 Mon Sep 17 00:00:00 2001 From: Peter <> Date: Thu, 3 Oct 2019 05:18:26 +0400 Subject: [PATCH 02/12] Fix passcode crashes --- .../Display/Display/Navigation/NavigationController.swift | 7 +++++++ submodules/Display/Display/WindowContent.swift | 5 ++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/submodules/Display/Display/Navigation/NavigationController.swift b/submodules/Display/Display/Navigation/NavigationController.swift index e8a48dc5d9..4dc05a9cd2 100644 --- a/submodules/Display/Display/Navigation/NavigationController.swift +++ b/submodules/Display/Display/Navigation/NavigationController.swift @@ -154,6 +154,13 @@ open class NavigationController: UINavigationController, ContainableController, private var _displayNode: ASDisplayNode? public var displayNode: ASDisplayNode { + if let value = self._displayNode { + return value + } + if !self.isViewLoaded { + self.loadView() + } + return self._displayNode! } diff --git a/submodules/Display/Display/WindowContent.swift b/submodules/Display/Display/WindowContent.swift index 1f654e78cc..39381f69eb 100644 --- a/submodules/Display/Display/WindowContent.swift +++ b/submodules/Display/Display/WindowContent.swift @@ -1082,12 +1082,11 @@ public class Window1 { } public func present(_ controller: ContainableController, on level: PresentationSurfaceLevel, blockInteraction: Bool = false, completion: @escaping () -> Void = {}) { - if let navigationController = self._rootController as? NavigationController, let controller = controller as? ViewController { + if level.rawValue <= 3, let navigationController = self._rootController as? NavigationController, let controller = controller as? ViewController { navigationController.presentOverlay(controller: controller, inGlobal: false) } else { - assertionFailure() + self.presentationContext.present(controller, on: level, blockInteraction: blockInteraction, completion: completion) } - //self.presentationContext.present(controller, on: level, blockInteraction: blockInteraction, completion: completion) } public func presentInGlobalOverlay(_ controller: ContainableController) { From ba3d2a2430538ed9d02a7bd98ea632f9aec55770 Mon Sep 17 00:00:00 2001 From: Peter <> Date: Thu, 3 Oct 2019 13:41:15 +0400 Subject: [PATCH 03/12] Fix inputHeight edge cases --- .../Navigation/NavigationContainer.swift | 12 +++++++++- .../Navigation/NavigationController.swift | 24 +++++++++++++++++-- .../Navigation/NavigationModalContainer.swift | 9 +++---- 3 files changed, 38 insertions(+), 7 deletions(-) diff --git a/submodules/Display/Display/Navigation/NavigationContainer.swift b/submodules/Display/Display/Navigation/NavigationContainer.swift index 82658ae960..69ef112ad3 100644 --- a/submodules/Display/Display/Navigation/NavigationContainer.swift +++ b/submodules/Display/Display/Navigation/NavigationContainer.swift @@ -306,7 +306,11 @@ final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelegate { var updatedStatusBarStyle = self.statusBarStyle if let top = self.state.top { - self.applyLayout(layout: layout, to: top, isMaster: true, transition: transition) + var updatedLayout = layout + if let topTransition = self.state.transition { + updatedLayout = updatedLayout.withUpdatedInputHeight(nil) + } + self.applyLayout(layout: updatedLayout, to: top, isMaster: true, transition: transition) updatedStatusBarStyle = top.value.statusBar.statusBarStyle } else { updatedStatusBarStyle = .Ignore @@ -364,6 +368,10 @@ final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelegate { guard let strongSelf = self, let topTransition = topTransition, strongSelf.state.transition === topTransition else { return } + + if viewTreeContainsFirstResponder(view: topTransition.previous.value.view) { + strongSelf.ignoreInputHeight = true + } strongSelf.keyboardViewManager?.dismissEditingWithoutAnimation(view: topTransition.previous.value.view) strongSelf.state.transition = nil @@ -376,6 +384,8 @@ final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelegate { strongSelf.applyLayout(layout: layout, to: toValue, isMaster: true, transition: .immediate) toValue.value.viewDidAppear(true) } + + strongSelf.ignoreInputHeight = false }) } else { if let fromValue = fromValue { diff --git a/submodules/Display/Display/Navigation/NavigationController.swift b/submodules/Display/Display/Navigation/NavigationController.swift index 4dc05a9cd2..8d1e364fe0 100644 --- a/submodules/Display/Display/Navigation/NavigationController.swift +++ b/submodules/Display/Display/Navigation/NavigationController.swift @@ -129,6 +129,7 @@ open class NavigationController: UINavigationController, ContainableController, private var validStatusBarStyle: NavigationStatusBarStyle? private var validStatusBarHidden: Bool = false + private var ignoreInputHeight: Bool = false private var currentStatusBarExternalHidden: Bool = false private var scheduledLayoutTransitionRequestId: Int = 0 @@ -257,6 +258,14 @@ open class NavigationController: UINavigationController, ContainableController, private func updateContainers(layout rawLayout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { var layout = rawLayout + if self.ignoreInputHeight { + if layout.inputHeight == nil { + self.ignoreInputHeight = false + } else { + layout = layout.withUpdatedInputHeight(nil) + } + } + if let globalScrollToTopNode = self.globalScrollToTopNode { globalScrollToTopNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -1.0), size: CGSize(width: layout.size.width, height: 1.0)) } @@ -317,14 +326,16 @@ open class NavigationController: UINavigationController, ContainableController, strongSelf.updateContainers(layout: layout, transition: transition) } } - modalContainer.interactivelyDismissed = { [weak self, weak modalContainer] in + modalContainer.interactivelyDismissed = { [weak self, weak modalContainer] hadInputFocus in guard let strongSelf = self, let modalContainer = modalContainer else { return } let controllers = strongSelf._viewControllers.filter { controller in return !modalContainer.container.controllers.contains(where: { $0 === controller }) } + strongSelf.ignoreInputHeight = hadInputFocus strongSelf.setViewControllers(controllers, animated: false) + strongSelf.ignoreInputHeight = false } } modalContainers.append(modalContainer) @@ -332,7 +343,12 @@ open class NavigationController: UINavigationController, ContainableController, for container in self.modalContainers { if !modalContainers.contains(where: { $0 === container }) { - transition = container.dismiss(transition: transition, completion: { [weak container] in + if viewTreeContainsFirstResponder(view: container.view) { + self.ignoreInputHeight = true + container.view.endEditing(true) + } + + transition = container.dismiss(transition: transition, completion: { [weak self, weak container] in container?.removeFromSupernode() }) } @@ -825,7 +841,11 @@ open class NavigationController: UINavigationController, ContainableController, public func filterController(_ controller: ViewController, animated: Bool) { let controllers = self.viewControllers.filter({ $0 !== controller }) if controllers.count != self.viewControllers.count { + if controller.isViewLoaded && viewTreeContainsFirstResponder(view: controller.view) { + self.ignoreInputHeight = true + } self.setViewControllers(controllers, animated: animated) + self.ignoreInputHeight = false } } diff --git a/submodules/Display/Display/Navigation/NavigationModalContainer.swift b/submodules/Display/Display/Navigation/NavigationModalContainer.swift index 22aa86011a..3cfcab03f7 100644 --- a/submodules/Display/Display/Navigation/NavigationModalContainer.swift +++ b/submodules/Display/Display/Navigation/NavigationModalContainer.swift @@ -16,7 +16,7 @@ final class NavigationModalContainer: ASDisplayNode, UIScrollViewDelegate, UIGes private(set) var dismissProgress: CGFloat = 0.0 var isReadyUpdated: (() -> Void)? var updateDismissProgress: ((CGFloat, ContainedViewLayoutTransition) -> Void)? - var interactivelyDismissed: (() -> Void)? + var interactivelyDismissed: ((Bool) -> Void)? private var ignoreScrolling = false private var isDismissed = false @@ -152,8 +152,9 @@ final class NavigationModalContainer: ASDisplayNode, UIScrollViewDelegate, UIGes guard let strongSelf = self else { return } + let hadInputFocus = viewTreeContainsFirstResponder(view: strongSelf.view) strongSelf.keyboardViewManager?.dismissEditingWithoutAnimation(view: strongSelf.view) - strongSelf.interactivelyDismissed?() + strongSelf.interactivelyDismissed?(hadInputFocus) }) } else { self.horizontalDismissOffset = nil @@ -194,7 +195,7 @@ final class NavigationModalContainer: ASDisplayNode, UIScrollViewDelegate, UIGes return } if targetOffset == 0.0 { - strongSelf.interactivelyDismissed?() + strongSelf.interactivelyDismissed?(false) } }) self.ignoreScrolling = false @@ -255,7 +256,7 @@ final class NavigationModalContainer: ASDisplayNode, UIScrollViewDelegate, UIGes return } if targetOffset == 0.0 { - strongSelf.interactivelyDismissed?() + strongSelf.interactivelyDismissed?(false) } }) self.ignoreScrolling = false From d27fb1fdcefc3318666b005d475d83f62a573e61 Mon Sep 17 00:00:00 2001 From: Peter <> Date: Thu, 3 Oct 2019 16:37:13 +0400 Subject: [PATCH 04/12] Fix keyboard --- .../xcschemes/Telegram_Buck.xcscheme | 2 - submodules/CloudData/Sources/CloudData.swift | 3 +- ...onSequenceCountrySelectionController.swift | 5 +- ...quenceCountrySelectionControllerNode.swift | 1 - .../Display/ActionSheetController.swift | 1 + .../Navigation/NavigationContainer.swift | 29 +++-- .../Navigation/NavigationController.swift | 2 +- .../InstantPageReferenceController.swift | 2 - .../Sources/JoinLinkPreviewController.swift | 4 +- .../LanguageLinkPreviewController.swift | 4 +- .../LegacyComponents/TGCameraController.m | 6 +- .../MtProtoKit/MTBackupAddressSignals.m | 115 ++++++++++++++++-- .../MTProtoKit/MTHttpRequestOperation.m | 2 +- .../Sources/EditSettingsController.swift | 2 +- .../Sources/ShareController.swift | 13 +- .../TelegramCore/TelegramCore/Network.swift | 2 +- ...orizationSequenceCodeEntryController.swift | 2 + ...ationSequencePasswordEntryController.swift | 2 + ...rizationSequencePhoneEntryController.swift | 6 +- ...uthorizationSequenceSignUpController.swift | 2 + .../ChatScheduleTimeController.swift | 4 +- .../OverlayAudioPlayerController.swift | 2 - 22 files changed, 166 insertions(+), 45 deletions(-) diff --git a/Telegram_Buck.xcworkspace/xcshareddata/xcschemes/Telegram_Buck.xcscheme b/Telegram_Buck.xcworkspace/xcshareddata/xcschemes/Telegram_Buck.xcscheme index b9d704e93d..a3a3833570 100644 --- a/Telegram_Buck.xcworkspace/xcshareddata/xcschemes/Telegram_Buck.xcscheme +++ b/Telegram_Buck.xcworkspace/xcshareddata/xcschemes/Telegram_Buck.xcscheme @@ -2574,8 +2574,6 @@ useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" debugDocumentVersioning = "YES" - stopOnEveryThreadSanitizerIssue = "YES" - stopOnEveryMainThreadCheckerIssue = "YES" debugServiceExtension = "internal" allowLocationSimulation = "YES"> Signal { public func cloudDataAdditionalAddressSource(phoneNumber: Signal) -> Signal { return phoneNumber |> take(1) - |> mapToSignal { _ -> Signal in - let phoneNumber: String? = "7950" + |> mapToSignal { phoneNumber -> Signal in var prefix = "" if let phoneNumber = phoneNumber, phoneNumber.count >= 1 { prefix = String(phoneNumber[phoneNumber.startIndex ..< phoneNumber.index(after: phoneNumber.startIndex)]) diff --git a/submodules/CountrySelectionUI/Sources/AuthorizationSequenceCountrySelectionController.swift b/submodules/CountrySelectionUI/Sources/AuthorizationSequenceCountrySelectionController.swift index e5a634f6de..0f40f80bb1 100644 --- a/submodules/CountrySelectionUI/Sources/AuthorizationSequenceCountrySelectionController.swift +++ b/submodules/CountrySelectionUI/Sources/AuthorizationSequenceCountrySelectionController.swift @@ -83,7 +83,7 @@ private final class AuthorizationSequenceCountrySelectionNavigationContentNode: self.addSubnode(self.searchBar) self.searchBar.cancel = { [weak self] in - self?.searchBar.deactivate(clear: false) + //self?.searchBar.deactivate(clear: false) self?.cancel() } @@ -159,6 +159,8 @@ public final class AuthorizationSequenceCountrySelectionController: ViewControll super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: NavigationBarTheme(rootControllerTheme: theme), strings: NavigationBarStrings(presentationStrings: strings))) + self.navigationPresentation = .modal + self.statusBar.statusBarStyle = theme.rootController.statusBarStyle.style let navigationContentNode = AuthorizationSequenceCountrySelectionNavigationContentNode(theme: theme, strings: strings, cancel: { [weak self] in @@ -191,7 +193,6 @@ public final class AuthorizationSequenceCountrySelectionController: ViewControll override public func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) - self.controllerNode.animateIn() self.navigationContentNode?.activate() } diff --git a/submodules/CountrySelectionUI/Sources/AuthorizationSequenceCountrySelectionControllerNode.swift b/submodules/CountrySelectionUI/Sources/AuthorizationSequenceCountrySelectionControllerNode.swift index 02e1095c8d..6ef8c17e6c 100644 --- a/submodules/CountrySelectionUI/Sources/AuthorizationSequenceCountrySelectionControllerNode.swift +++ b/submodules/CountrySelectionUI/Sources/AuthorizationSequenceCountrySelectionControllerNode.swift @@ -111,7 +111,6 @@ final class AuthorizationSequenceCountrySelectionControllerNode: ASDisplayNode, } self.sections = sections var sectionTitles = sections.map { $0.0 } - sectionTitles.insert(UITableView.indexSearch, at: 0) self.sectionTitles = sectionTitles super.init() diff --git a/submodules/Display/Display/ActionSheetController.swift b/submodules/Display/Display/ActionSheetController.swift index 8fd76c318a..790465062a 100644 --- a/submodules/Display/Display/ActionSheetController.swift +++ b/submodules/Display/Display/ActionSheetController.swift @@ -25,6 +25,7 @@ open class ActionSheetController: ViewController, PresentableController, Standal super.init(navigationBarPresentationData: nil) + self.statusBar.statusBarStyle = .Ignore self.blocksBackgroundWhenInOverlay = true } diff --git a/submodules/Display/Display/Navigation/NavigationContainer.swift b/submodules/Display/Display/Navigation/NavigationContainer.swift index 69ef112ad3..975497b759 100644 --- a/submodules/Display/Display/Navigation/NavigationContainer.swift +++ b/submodules/Display/Display/Navigation/NavigationContainer.swift @@ -173,7 +173,11 @@ final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelegate { topController.viewWillDisappear(true) let topNode = topController.displayNode - bottomController.containerLayoutUpdated(layout.withUpdatedInputHeight(nil), transition: .immediate) + var bottomControllerLayout = layout + if bottomController.view.disableAutomaticKeyboardHandling.isEmpty { + bottomControllerLayout = bottomControllerLayout.withUpdatedInputHeight(nil) + } + bottomController.containerLayoutUpdated(bottomControllerLayout, transition: .immediate) bottomController.viewWillAppear(true) let bottomNode = bottomController.displayNode @@ -274,7 +278,11 @@ final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelegate { } else { transitionType = .pop } - self.state.pending = PendingChild(value: self.makeChild(layout: layout.withUpdatedInputHeight(nil), value: last), transitionType: transitionType, transition: transition, update: { [weak self] pendingChild in + var updatedLayout = layout + if last.view.disableAutomaticKeyboardHandling.isEmpty { + updatedLayout = updatedLayout.withUpdatedInputHeight(nil) + } + self.state.pending = PendingChild(value: self.makeChild(layout: updatedLayout, value: last), transitionType: transitionType, transition: transition, update: { [weak self] pendingChild in self?.pendingChildIsReady(pendingChild) }) } @@ -289,7 +297,11 @@ final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelegate { self.state.pending = nil let previous = self.state.top self.state.top = pending.value - self.topTransition(from: previous, to: pending.value, transitionType: pending.transitionType, layout: layout.withUpdatedInputHeight(nil), transition: pending.transition) + var updatedLayout = layout + if pending.value.value.view.disableAutomaticKeyboardHandling.isEmpty { + updatedLayout = updatedLayout.withUpdatedInputHeight(nil) + } + self.topTransition(from: previous, to: pending.value, transitionType: pending.transitionType, layout: updatedLayout, transition: pending.transition) statusBarTransition = pending.transition if !self.isReady { self.isReady = true @@ -307,7 +319,7 @@ final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelegate { var updatedStatusBarStyle = self.statusBarStyle if let top = self.state.top { var updatedLayout = layout - if let topTransition = self.state.transition { + if let topTransition = self.state.transition, top.value.view.disableAutomaticKeyboardHandling.isEmpty { updatedLayout = updatedLayout.withUpdatedInputHeight(nil) } self.applyLayout(layout: updatedLayout, to: top, isMaster: true, transition: transition) @@ -408,7 +420,10 @@ final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelegate { } private func makeChild(layout: ContainerViewLayout, value: ViewController) -> Child { - let updatedLayout = layout.withUpdatedInputHeight(nil) + var updatedLayout = layout + if value.view.disableAutomaticKeyboardHandling.isEmpty { + updatedLayout = updatedLayout.withUpdatedInputHeight(nil) + } value.containerLayoutUpdated(updatedLayout, transition: .immediate) return Child(value: value, layout: updatedLayout) } @@ -430,7 +445,7 @@ final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelegate { break } if updatedLayout.inputHeight != nil { - if !self.canHaveKeyboardFocus { + if !self.canHaveKeyboardFocus && child.value.view.disableAutomaticKeyboardHandling.isEmpty { updatedLayout = updatedLayout.withUpdatedInputHeight(nil) } } @@ -439,7 +454,7 @@ final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelegate { shouldSyncKeyboard = true } - if updatedLayout.inputHeight != nil { + if updatedLayout.inputHeight != nil && child.value.view.disableAutomaticKeyboardHandling.isEmpty { if !self.canHaveKeyboardFocus || self.ignoreInputHeight { updatedLayout = updatedLayout.withUpdatedInputHeight(nil) } diff --git a/submodules/Display/Display/Navigation/NavigationController.swift b/submodules/Display/Display/Navigation/NavigationController.swift index 8d1e364fe0..ea862cf43e 100644 --- a/submodules/Display/Display/Navigation/NavigationController.swift +++ b/submodules/Display/Display/Navigation/NavigationController.swift @@ -1078,7 +1078,7 @@ open class NavigationController: UINavigationController, ContainableController, } if let layout = self.validLayout { self.containerLayoutUpdated(layout, transition: transition) - inCallStatusBar.updateState(statusBar: nil, withSafeInsets: false, inCallText: forceInCallStatusBarText, animated: false) + inCallStatusBar.updateState(statusBar: nil, withSafeInsets: !layout.safeInsets.top.isZero, inCallText: forceInCallStatusBarText, animated: false) } } else if let inCallStatusBar = self.inCallStatusBar { self.inCallStatusBar = nil diff --git a/submodules/InstantPageUI/Sources/InstantPageReferenceController.swift b/submodules/InstantPageUI/Sources/InstantPageReferenceController.swift index 2f89939908..02ef3e2080 100644 --- a/submodules/InstantPageUI/Sources/InstantPageReferenceController.swift +++ b/submodules/InstantPageUI/Sources/InstantPageReferenceController.swift @@ -52,8 +52,6 @@ final class InstantPageReferenceController: ViewController { override public func loadView() { super.loadView() - - self.statusBar.removeFromSupernode() } override public func viewDidAppear(_ animated: Bool) { diff --git a/submodules/JoinLinkPreviewUI/Sources/JoinLinkPreviewController.swift b/submodules/JoinLinkPreviewUI/Sources/JoinLinkPreviewController.swift index 692cf1e83f..7332e5b9ac 100644 --- a/submodules/JoinLinkPreviewUI/Sources/JoinLinkPreviewController.swift +++ b/submodules/JoinLinkPreviewUI/Sources/JoinLinkPreviewController.swift @@ -31,6 +31,8 @@ public final class JoinLinkPreviewController: ViewController { self.presentationData = context.sharedContext.currentPresentationData.with { $0 } super.init(navigationBarPresentationData: nil) + + self.statusBar.statusBarStyle = .Ignore } required public init(coder aDecoder: NSCoder) { @@ -76,8 +78,6 @@ public final class JoinLinkPreviewController: ViewController { override public func loadView() { super.loadView() - - self.statusBar.removeFromSupernode() } override public func viewDidAppear(_ animated: Bool) { diff --git a/submodules/LanguageLinkPreviewUI/Sources/LanguageLinkPreviewController.swift b/submodules/LanguageLinkPreviewUI/Sources/LanguageLinkPreviewController.swift index ad210a0ce0..1d604ca476 100644 --- a/submodules/LanguageLinkPreviewUI/Sources/LanguageLinkPreviewController.swift +++ b/submodules/LanguageLinkPreviewUI/Sources/LanguageLinkPreviewController.swift @@ -30,6 +30,8 @@ public final class LanguageLinkPreviewController: ViewController { self.presentationData = context.sharedContext.currentPresentationData.with { $0 } super.init(navigationBarPresentationData: nil) + + self.statusBar.statusBarStyle = .Ignore } required public init(coder aDecoder: NSCoder) { @@ -85,8 +87,6 @@ public final class LanguageLinkPreviewController: ViewController { override public func loadView() { super.loadView() - - self.statusBar.removeFromSupernode() } override public func viewDidAppear(_ animated: Bool) { diff --git a/submodules/LegacyComponents/LegacyComponents/TGCameraController.m b/submodules/LegacyComponents/LegacyComponents/TGCameraController.m index 6c104bdb28..37b5a2b97b 100644 --- a/submodules/LegacyComponents/LegacyComponents/TGCameraController.m +++ b/submodules/LegacyComponents/LegacyComponents/TGCameraController.m @@ -739,7 +739,7 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus [UIView animateWithDuration:0.3f animations:^ { - [_context setApplicationStatusBarAlpha:1.0f]; + //[_context setApplicationStatusBarAlpha:1.0f]; }]; } @@ -1816,7 +1816,7 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus [UIView animateWithDuration:0.3f animations:^ { - [_context setApplicationStatusBarAlpha:1.0f]; + //[_context setApplicationStatusBarAlpha:1.0f]; }]; [self setInterfaceHidden:true animated:true]; @@ -1892,7 +1892,7 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus { _finishedWithResult = true; - [_context setApplicationStatusBarAlpha:1.0f]; + //[_context setApplicationStatusBarAlpha:1.0f]; self.view.hidden = true; diff --git a/submodules/MtProtoKit/MTBackupAddressSignals.m b/submodules/MtProtoKit/MTBackupAddressSignals.m index db3a478091..94dec7b1e7 100644 --- a/submodules/MtProtoKit/MTBackupAddressSignals.m +++ b/submodules/MtProtoKit/MTBackupAddressSignals.m @@ -71,19 +71,23 @@ static NSData *base64_decode(NSString *str) { + (MTSignal *)fetchBackupIpsResolveGoogle:(bool)isTesting phoneNumber:(NSString *)phoneNumber currentContext:(MTContext *)currentContext addressOverride:(NSString *)addressOverride { NSArray *hosts = @[ - @"google.com", - @"www.google.com", - @"google.ru" + @[@"dns.google.com", @""], + @[@"www.google.com", @"dns.google.com"], ]; - NSDictionary *headers = @{@"Host": @"dns.google.com"}; NSMutableArray *signals = [[NSMutableArray alloc] init]; - for (NSString *host in hosts) { + for (NSArray *hostAndHostname in hosts) { + NSString *host = hostAndHostname[0]; + NSString *hostName = hostAndHostname[1]; + NSMutableDictionary *headers = [[NSMutableDictionary alloc] init]; + if ([hostName length] != 0) { + headers[@"Host"] = hostName; + } NSString *apvHost = @"apv3.stel.com"; if (addressOverride != nil) { apvHost = addressOverride; } - MTSignal *signal = [[[MTHttpRequestOperation dataForHttpUrl:[NSURL URLWithString:[NSString stringWithFormat:@"https://%@/resolve?name=%@&type=16", host, isTesting ? @"tapv3.stel.com" : apvHost]] headers:headers] mapToSignal:^MTSignal *(NSData *data) { + MTSignal *signal = [[[MTHttpRequestOperation dataForHttpUrl:[NSURL URLWithString:[NSString stringWithFormat:@"https://%@/resolve?name=%@&type=16&random_padding=%@", host, isTesting ? @"tapv3.stel.com" : apvHost, makeRandomPadding()]] headers:headers] mapToSignal:^MTSignal *(NSData *data) { NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; if ([dict respondsToSelector:@selector(objectForKey:)]) { NSArray *answer = dict[@"Answer"]; @@ -132,6 +136,90 @@ static NSData *base64_decode(NSString *str) { return [[MTSignal mergeSignals:signals] take:1]; } +static NSString *makeRandomPadding() { + char validCharacters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + int maxIndex = sizeof(validCharacters) - 1; + + int minPadding = 13; + int maxPadding = 128; + int padding = minPadding + arc4random_uniform(maxPadding - minPadding); + NSMutableData *result = [[NSMutableData alloc] initWithLength:padding]; + for (NSUInteger i = 0; i < result.length; i++) { + int index = arc4random_uniform(maxIndex); + assert(index >= 0 && index < maxIndex); + ((uint8_t *)(result.mutableBytes))[i] = validCharacters[index]; + } + NSString *string = [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding]; + return string; +} + ++ (MTSignal *)fetchBackupIpsResolveCloudflare:(bool)isTesting phoneNumber:(NSString *)phoneNumber currentContext:(MTContext *)currentContext addressOverride:(NSString *)addressOverride { + NSArray *hosts = @[ + @[@"mozilla.cloudflare-dns.com", @""], + ]; + + NSMutableArray *signals = [[NSMutableArray alloc] init]; + for (NSArray *hostAndHostname in hosts) { + NSString *host = hostAndHostname[0]; + NSString *hostName = hostAndHostname[1]; + NSMutableDictionary *headers = [[NSMutableDictionary alloc] init]; + headers[@"accept"] = @"application/dns-json"; + if ([hostName length] != 0) { + headers[@"Host"] = hostName; + } + NSString *apvHost = @"apv3.stel.com"; + if (addressOverride != nil) { + apvHost = addressOverride; + } + MTSignal *signal = [[[MTHttpRequestOperation dataForHttpUrl:[NSURL URLWithString:[NSString stringWithFormat:@"https://%@/dns-query?name=%@&type=16&random_padding=%@", host, isTesting ? @"tapv3.stel.com" : apvHost, makeRandomPadding()]] headers:headers] mapToSignal:^MTSignal *(NSData *data) { + NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; + if ([dict respondsToSelector:@selector(objectForKey:)]) { + NSArray *answer = dict[@"Answer"]; + NSMutableArray *strings = [[NSMutableArray alloc] init]; + if ([answer respondsToSelector:@selector(objectAtIndex:)]) { + for (NSDictionary *value in answer) { + if ([value respondsToSelector:@selector(objectForKey:)]) { + NSString *part = value[@"data"]; + if ([part respondsToSelector:@selector(characterAtIndex:)]) { + [strings addObject:part]; + } + } + } + [strings sortUsingComparator:^NSComparisonResult(NSString *lhs, NSString *rhs) { + if (lhs.length > rhs.length) { + return NSOrderedAscending; + } else { + return NSOrderedDescending; + } + }]; + + NSString *finalString = @""; + for (NSString *string in strings) { + finalString = [finalString stringByAppendingString:[string stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"="]]]; + } + + NSData *result = base64_decode(finalString); + NSMutableData *finalData = [[NSMutableData alloc] initWithData:result]; + [finalData setLength:256]; + MTBackupDatacenterData *datacenterData = MTIPDataDecode(finalData, phoneNumber); + if (datacenterData != nil && [self checkIpData:datacenterData timestamp:(int32_t)[currentContext globalTime] source:@"resolveCloudflare"]) { + return [MTSignal single:datacenterData]; + } + } + } + return [MTSignal complete]; + }] catch:^MTSignal *(__unused id error) { + return [MTSignal complete]; + }]; + if (signals.count != 0) { + signal = [signal delay:signals.count onQueue:[[MTQueue alloc] init]]; + } + [signals addObject:signal]; + } + + return [[MTSignal mergeSignals:signals] take:1]; +} + + (MTSignal *)fetchConfigFromAddress:(MTBackupDatacenterAddress *)address currentContext:(MTContext *)currentContext { MTApiEnvironment *apiEnvironment = [currentContext.apiEnvironment copy]; @@ -209,12 +297,23 @@ static NSData *base64_decode(NSString *str) { + (MTSignal * _Nonnull)fetchBackupIps:(bool)isTestingEnvironment currentContext:(MTContext * _Nonnull)currentContext additionalSource:(MTSignal * _Nullable)additionalSource phoneNumber:(NSString * _Nullable)phoneNumber { NSMutableArray *signals = [[NSMutableArray alloc] init]; - [signals addObject:[self fetchBackupIpsResolveGoogle:isTestingEnvironment phoneNumber:phoneNumber currentContext:currentContext addressOverride:currentContext.apiEnvironment.accessHostOverride]]; + //[signals addObject:[self fetchBackupIpsResolveGoogle:isTestingEnvironment phoneNumber:phoneNumber currentContext:currentContext addressOverride:currentContext.apiEnvironment.accessHostOverride]]; + //[signals addObject:[self fetchBackupIpsResolveCloudflare:isTestingEnvironment phoneNumber:phoneNumber currentContext:currentContext addressOverride:currentContext.apiEnvironment.accessHostOverride]]; if (additionalSource != nil) { /*#if DEBUG [signals removeAllObjects]; #endif*/ - [signals addObject:additionalSource]; + [signals addObject:[additionalSource mapToSignal:^MTSignal *(MTBackupDatacenterData *datacenterData) { + if (![datacenterData isKindOfClass:[MTBackupDatacenterData class]]) { + return [MTSignal complete]; + } + MTBackupDatacenterData *datacenterData = MTIPDataDecode(finalData, phoneNumber); + if (datacenterData != nil && [self checkIpData:datacenterData timestamp:(int32_t)[currentContext globalTime] source:@"resolveExternal"]) { + return [MTSignal single:datacenterData]; + } else { + return [MTSignal complete]; + } + }]]; } return [[[MTSignal mergeSignals:signals] take:1] mapToSignal:^MTSignal *(MTBackupDatacenterData *data) { diff --git a/submodules/MtProtoKit/MTProtoKit/MTHttpRequestOperation.m b/submodules/MtProtoKit/MTProtoKit/MTHttpRequestOperation.m index 82ddcb0f82..0e1a47f41b 100644 --- a/submodules/MtProtoKit/MTProtoKit/MTHttpRequestOperation.m +++ b/submodules/MtProtoKit/MTProtoKit/MTHttpRequestOperation.m @@ -36,7 +36,7 @@ [subscriber putCompletion]; } failure:^(__unused NSOperation *operation, __unused NSError *error) { - [subscriber putError:nil]; + [subscriber putError:error]; }]; [operation start]; diff --git a/submodules/SettingsUI/Sources/EditSettingsController.swift b/submodules/SettingsUI/Sources/EditSettingsController.swift index ee04356ba7..05cecda448 100644 --- a/submodules/SettingsUI/Sources/EditSettingsController.swift +++ b/submodules/SettingsUI/Sources/EditSettingsController.swift @@ -447,7 +447,7 @@ func editSettingsController(context: AccountContext, currentName: ItemListAvatar (controller?.navigationController as? NavigationController)?.pushViewController(value) } presentControllerImpl = { [weak controller] value, arguments in - controller?.present(value, in: .window(.root), with: arguments ?? ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) + controller?.present(value, in: .window(.root), with: arguments) } dismissImpl = { [weak controller] in let _ = (controller?.navigationController as? NavigationController)?.popViewController(animated: true) diff --git a/submodules/ShareController/Sources/ShareController.swift b/submodules/ShareController/Sources/ShareController.swift index 086182f34c..2b9b0f6026 100644 --- a/submodules/ShareController/Sources/ShareController.swift +++ b/submodules/ShareController/Sources/ShareController.swift @@ -203,6 +203,11 @@ public final class ShareController: ViewController { return self.displayNode as! ShareControllerNode } + private let _ready = Promise() + override public var ready: Promise { + return self._ready + } + private var animatedIn = false private let sharedContext: SharedAccountContext @@ -242,6 +247,8 @@ public final class ShareController: ViewController { super.init(navigationBarPresentationData: nil) + self.statusBar.statusBarStyle = .Ignore + switch subject { case let .url(text): self.defaultAction = ShareControllerAction(title: self.presentationData.strings.ShareMenu_CopyShareLink, action: { [weak self] in @@ -567,7 +574,7 @@ public final class ShareController: ViewController { return .preparing case let .done(items): if let strongSelf = self, !items.isEmpty { - strongSelf.ready.set(.single(true)) + strongSelf._ready.set(.single(true)) var activityItems: [Any] = [] for item in items { switch item { @@ -632,13 +639,11 @@ public final class ShareController: ViewController { strongSelf.controllerNode.updatePeers(account: strongSelf.currentAccount, switchableAccounts: strongSelf.switchableAccounts, peers: next.0, accountPeer: next.1, defaultAction: strongSelf.defaultAction) } })) - self.ready.set(self.controllerNode.ready.get()) + self._ready.set(self.controllerNode.ready.get()) } override public func loadView() { super.loadView() - - self.statusBar.removeFromSupernode() } override public func viewDidAppear(_ animated: Bool) { diff --git a/submodules/TelegramCore/TelegramCore/Network.swift b/submodules/TelegramCore/TelegramCore/Network.swift index 29c8b45d51..42ff256212 100644 --- a/submodules/TelegramCore/TelegramCore/Network.swift +++ b/submodules/TelegramCore/TelegramCore/Network.swift @@ -500,7 +500,7 @@ func initializedNetwork(arguments: NetworkInitializationArguments, supplementary context.setDiscoverBackupAddressListSignal(MTBackupAddressSignals.fetchBackupIps(testingEnvironment, currentContext: context, additionalSource: wrappedAdditionalSource, phoneNumber: phoneNumber)) #if DEBUG - //let _ = MTBackupAddressSignals.fetchBackupIps(testingEnvironment, currentContext: context, additionalSource: wrappedAdditionalSource, phoneNumber: phoneNumber).start(next: nil) + let _ = MTBackupAddressSignals.fetchBackupIps(testingEnvironment, currentContext: context, additionalSource: wrappedAdditionalSource, phoneNumber: phoneNumber).start(next: nil) #endif let mtProto = MTProto(context: context, datacenterId: datacenterId, usageCalculationInfo: usageCalculationInfo(basePath: basePath, category: nil))! diff --git a/submodules/TelegramUI/TelegramUI/AuthorizationSequenceCodeEntryController.swift b/submodules/TelegramUI/TelegramUI/AuthorizationSequenceCodeEntryController.swift index 7f894be7a6..f82156a376 100644 --- a/submodules/TelegramUI/TelegramUI/AuthorizationSequenceCodeEntryController.swift +++ b/submodules/TelegramUI/TelegramUI/AuthorizationSequenceCodeEntryController.swift @@ -70,6 +70,8 @@ final class AuthorizationSequenceCodeEntryController: ViewController { self.displayNode = AuthorizationSequenceCodeEntryControllerNode(strings: self.strings, theme: self.theme) self.displayNodeDidLoad() + self.controllerNode.view.disableAutomaticKeyboardHandling = [.forward, .backward] + self.controllerNode.loginWithCode = { [weak self] code in self?.continueWithCode(code) } diff --git a/submodules/TelegramUI/TelegramUI/AuthorizationSequencePasswordEntryController.swift b/submodules/TelegramUI/TelegramUI/AuthorizationSequencePasswordEntryController.swift index 5d6523cc89..8c744c5e3b 100644 --- a/submodules/TelegramUI/TelegramUI/AuthorizationSequencePasswordEntryController.swift +++ b/submodules/TelegramUI/TelegramUI/AuthorizationSequencePasswordEntryController.swift @@ -74,6 +74,8 @@ final class AuthorizationSequencePasswordEntryController: ViewController { self.displayNode = AuthorizationSequencePasswordEntryControllerNode(strings: self.strings, theme: self.theme) self.displayNodeDidLoad() + self.controllerNode.view.disableAutomaticKeyboardHandling = [.forward, .backward] + self.controllerNode.loginWithCode = { [weak self] _ in self?.nextPressed() } diff --git a/submodules/TelegramUI/TelegramUI/AuthorizationSequencePhoneEntryController.swift b/submodules/TelegramUI/TelegramUI/AuthorizationSequencePhoneEntryController.swift index 5321ea1cab..cc5f9298be 100644 --- a/submodules/TelegramUI/TelegramUI/AuthorizationSequencePhoneEntryController.swift +++ b/submodules/TelegramUI/TelegramUI/AuthorizationSequencePhoneEntryController.swift @@ -106,6 +106,9 @@ final class AuthorizationSequencePhoneEntryController: ViewController { self.controllerNode.codeAndNumber = (code, name, number) } self.displayNodeDidLoad() + + self.controllerNode.view.disableAutomaticKeyboardHandling = [.forward, .backward] + self.controllerNode.selectCountryCode = { [weak self] in if let strongSelf = self { let controller = AuthorizationSequenceCountrySelectionController(strings: strongSelf.strings, theme: strongSelf.theme) @@ -118,8 +121,7 @@ final class AuthorizationSequencePhoneEntryController: ViewController { controller.dismissed = { self?.controllerNode.activateInput() } - strongSelf.controllerNode.view.endEditing(true) - strongSelf.present(controller, in: .window(.root)) + strongSelf.push(controller) } } self.controllerNode.checkPhone = { [weak self] in diff --git a/submodules/TelegramUI/TelegramUI/AuthorizationSequenceSignUpController.swift b/submodules/TelegramUI/TelegramUI/AuthorizationSequenceSignUpController.swift index e7d751f90f..11ccd23f80 100644 --- a/submodules/TelegramUI/TelegramUI/AuthorizationSequenceSignUpController.swift +++ b/submodules/TelegramUI/TelegramUI/AuthorizationSequenceSignUpController.swift @@ -93,6 +93,8 @@ final class AuthorizationSequenceSignUpController: ViewController { }) self.displayNodeDidLoad() + self.controllerNode.view.disableAutomaticKeyboardHandling = [.forward, .backward] + self.controllerNode.signUpWithName = { [weak self] _, _ in self?.nextPressed() } diff --git a/submodules/TelegramUI/TelegramUI/ChatScheduleTimeController.swift b/submodules/TelegramUI/TelegramUI/ChatScheduleTimeController.swift index 36a6aea0d8..6d3c765d1b 100644 --- a/submodules/TelegramUI/TelegramUI/ChatScheduleTimeController.swift +++ b/submodules/TelegramUI/TelegramUI/ChatScheduleTimeController.swift @@ -38,6 +38,8 @@ final class ChatScheduleTimeController: ViewController { super.init(navigationBarPresentationData: nil) + self.statusBar.statusBarStyle = .Ignore + self.blocksBackgroundWhenInOverlay = true self.presentationDataDisposable = (context.sharedContext.presentationData @@ -74,8 +76,6 @@ final class ChatScheduleTimeController: ViewController { override public func loadView() { super.loadView() - - self.statusBar.removeFromSupernode() } override public func viewDidAppear(_ animated: Bool) { diff --git a/submodules/TelegramUI/TelegramUI/OverlayAudioPlayerController.swift b/submodules/TelegramUI/TelegramUI/OverlayAudioPlayerController.swift index 22ebc5062e..49468c7175 100644 --- a/submodules/TelegramUI/TelegramUI/OverlayAudioPlayerController.swift +++ b/submodules/TelegramUI/TelegramUI/OverlayAudioPlayerController.swift @@ -79,8 +79,6 @@ final class OverlayAudioPlayerControllerImpl: ViewController, OverlayAudioPlayer override public func loadView() { super.loadView() - - self.statusBar.removeFromSupernode() } override public func viewDidAppear(_ animated: Bool) { From 2328a24d3f108c33869dc135390bf91c37606b47 Mon Sep 17 00:00:00 2001 From: Peter <> Date: Thu, 3 Oct 2019 18:49:38 +0400 Subject: [PATCH 05/12] Wallet errors --- Telegram-iOS/en.lproj/Localizable.strings | 5 + submodules/CloudData/Sources/CloudData.swift | 117 +- .../Sources/CreatePollController.swift | 2 +- .../Navigation/NavigationController.swift | 2 +- .../Sources/GalleryControllerNode.swift | 4 +- .../MtProtoKit/MTBackupAddressSignals.m | 1 - .../MtProtoKit/MTProtoKit/MTEncryption.m | 3 + submodules/MtProtoKit/TON/TON.h | 1 + submodules/MtProtoKit/TON/TON.mm | 26 +- .../SwiftSignalKit/Signal_Catch.swift | 49 + .../TelegramCore/TelegramCore/Network.swift | 28 +- .../TelegramCore/TelegramCore/Wallets.swift | 148 +- .../Sources/PresentationStrings.swift | 5093 +++++++++-------- .../TelegramUI/TelegramUI/AppDelegate.swift | 4 - .../Resources/PresentationStrings.mapping | Bin 132028 -> 132237 bytes .../WalletUI/Sources/WalletInfoScreen.swift | 11 +- .../Sources/WalletSettingsScreen.swift | 2 +- .../WalletUI/Sources/WalletSplashScreen.swift | 10 +- submodules/WalletUI/Sources/WalletUtils.swift | 2 +- .../ton/tonlib-src/crypto/CMakeLists.txt | 5 + .../tonlib-src/crypto/block/block-auto.cpp | 91 +- .../ton/tonlib-src/crypto/block/block-auto.h | 34 +- .../tonlib-src/crypto/block/block-parse.cpp | 95 +- .../ton/tonlib-src/crypto/block/block-parse.h | 7 + .../ton/tonlib-src/crypto/block/block.cpp | 8 +- .../ton/tonlib-src/crypto/block/block.h | 3 + .../ton/tonlib-src/crypto/block/block.tlb | 7 +- .../tonlib-src/crypto/block/transaction.cpp | 71 +- .../ton/tonlib-src/crypto/block/transaction.h | 4 + .../ton/tonlib-src/crypto/fift/SourceLookup.h | 2 +- .../ton/tonlib-src/crypto/fift/lib/Fift.fif | 2 +- .../ton/tonlib-src/crypto/fift/words.cpp | 52 +- .../ton/tonlib-src/crypto/func/codegen.cpp | 4 +- .../ton/tonlib-src/crypto/parser/srcread.cpp | 5 + .../crypto/smartcont/gen-zerostate-test.fif | 8 +- .../crypto/smartcont/gen-zerostate.fif | 8 +- .../crypto/smartcont/highload-wallet-code.fc | 41 + .../crypto/smartcont/highload-wallet-code.fif | 79 + .../smartcont/highload-wallet-v2-code.fc | 65 + .../smartcont/highload-wallet-v2-code.fif | 134 + .../crypto/smartcont/highload-wallet-v2.fif | 69 + .../crypto/smartcont/highload-wallet.fif | 68 + .../smartcont/new-highload-wallet-v2.fif | 47 + .../crypto/smartcont/new-highload-wallet.fif | 44 + .../crypto/smartcont/new-pinger.fif | 2 +- .../crypto/smartcont/new-testgiver.fif | 2 +- .../crypto/smartcont/new-wallet-v2.fif | 4 +- .../crypto/smartcont/new-wallet.fif | 4 +- .../ton/tonlib-src/crypto/smartcont/stdlib.fc | 2 + .../crypto/smartcont/update-config-smc.fif | 14 +- .../crypto/smartcont/update-config.fif | 14 +- .../crypto/smartcont/update-elector-smc.fif | 14 +- .../tonlib-src/crypto/smartcont/wallet-v2.fif | 2 +- .../tonlib-src/crypto/smartcont/wallet.fif | 2 +- .../tonlib-src/crypto/vm/cells/CellSlice.cpp | 20 + .../tonlib-src/crypto/vm/cells/CellSlice.h | 2 + .../crypto/vm/cells/MerkleProof.cpp | 6 +- .../tonlib-src/crypto/vm/cells/MerkleProof.h | 5 +- .../tonlib-src/lite-client/lite-client.cpp | 6 +- .../ton/tonlib-src/tdactor/td/actor/common.h | 2 +- .../tdactor/td/actor/core/ActorExecutor.cpp | 4 +- .../tdactor/td/actor/core/ActorExecutor.h | 4 +- .../ton/tonlib-src/tdutils/td/utils/Status.h | 48 +- .../tonlib-src/tdutils/td/utils/tl_helpers.h | 16 +- .../tonlib-src/tdutils/td/utils/tl_parsers.h | 10 + .../tl/generate/auto/tl/ton_api.cpp | 161 +- .../tonlib-src/tl/generate/auto/tl/ton_api.h | 88 +- .../tl/generate/auto/tl/ton_api.hpp | 32 + .../tl/generate/auto/tl/ton_api_json.cpp | 90 +- .../tl/generate/auto/tl/ton_api_json.h | 8 + .../tl/generate/auto/tl/tonlib_api.cpp | 77 +- .../tl/generate/auto/tl/tonlib_api.h | 77 +- .../tl/generate/auto/tl/tonlib_api.hpp | 29 + .../tl/generate/auto/tl/tonlib_api_json.cpp | 112 +- .../tl/generate/auto/tl/tonlib_api_json.h | 8 + .../tonlib-src/tl/generate/scheme/ton_api.tl | 3 + .../tonlib-src/tl/generate/scheme/ton_api.tlo | Bin 53872 -> 54392 bytes .../tl/generate/scheme/tonlib_api.tl | 15 +- .../tl/generate/scheme/tonlib_api.tlo | Bin 12496 -> 13000 bytes .../ton/tonlib-src/tonlib/CMakeLists.txt | 4 + .../ton/tonlib-src/tonlib/test/offline.cpp | 39 +- .../ton/tonlib-src/tonlib/test/online.cpp | 6 +- .../tonlib/tonlib/.TonlibClient.cpp.swp | Bin 90112 -> 0 bytes .../tonlib/tonlib/.TonlibError.h.swp | Bin 0 -> 24576 bytes .../tonlib-src/tonlib/tonlib/.Wallet.cpp.swp | Bin 16384 -> 16384 bytes .../tonlib-src/tonlib/tonlib/CellString.cpp | 64 + .../ton/tonlib-src/tonlib/tonlib/CellString.h | 22 + .../tonlib-src/tonlib/tonlib/ExtClient.cpp | 4 +- .../ton/tonlib-src/tonlib/tonlib/ExtClient.h | 35 +- .../tonlib/tonlib/ExtClientOutbound.cpp | 5 +- .../tonlib/tonlib/GenericAccount.cpp | 7 +- .../tonlib-src/tonlib/tonlib/GenericAccount.h | 6 +- .../tonlib-src/tonlib/tonlib/KeyStorage.cpp | 86 +- .../ton/tonlib-src/tonlib/tonlib/KeyStorage.h | 10 +- .../ton/tonlib-src/tonlib/tonlib/KeyValue.cpp | 124 + .../ton/tonlib-src/tonlib/tonlib/KeyValue.h | 19 + .../tonlib-src/tonlib/tonlib/LastBlock.cpp | 179 +- .../ton/tonlib-src/tonlib/tonlib/LastBlock.h | 59 +- .../tonlib/tonlib/LastBlockStorage.cpp | 23 +- .../tonlib/tonlib/LastBlockStorage.h | 7 +- .../ton/tonlib-src/tonlib/tonlib/Logging.cpp | 5 +- .../tonlib-src/tonlib/tonlib/TestGiver.cpp | 11 +- .../ton/tonlib-src/tonlib/tonlib/TestGiver.h | 8 +- .../tonlib-src/tonlib/tonlib/TestWallet.cpp | 23 +- .../ton/tonlib-src/tonlib/tonlib/TestWallet.h | 14 +- .../tonlib-src/tonlib/tonlib/TonlibClient.cpp | 665 ++- .../tonlib-src/tonlib/tonlib/TonlibClient.h | 8 +- .../tonlib-src/tonlib/tonlib/TonlibError.h | 157 + .../ton/tonlib-src/tonlib/tonlib/Wallet.cpp | 24 +- .../ton/tonlib-src/tonlib/tonlib/Wallet.h | 14 +- .../tonlib/tonlib/keys/DecryptedKey.cpp | 3 +- .../tonlib/tonlib/keys/EncryptedKey.cpp | 1 - .../tonlib/tonlib/keys/EncryptedKey.h | 2 +- .../tonlib/tonlib/keys/SimpleEncryption.cpp | 2 +- .../tonlib-src/tonlib/tonlib/tonlib-cli.cpp | 38 +- .../ton/tonlib-src/tonlib/tonlib/utils.cpp | 4 + .../ton/tonlib-src/tonlib/tonlib/utils.h | 15 + 117 files changed, 5759 insertions(+), 3278 deletions(-) create mode 100644 submodules/ton/tonlib-src/crypto/smartcont/highload-wallet-code.fc create mode 100644 submodules/ton/tonlib-src/crypto/smartcont/highload-wallet-code.fif create mode 100644 submodules/ton/tonlib-src/crypto/smartcont/highload-wallet-v2-code.fc create mode 100644 submodules/ton/tonlib-src/crypto/smartcont/highload-wallet-v2-code.fif create mode 100644 submodules/ton/tonlib-src/crypto/smartcont/highload-wallet-v2.fif create mode 100644 submodules/ton/tonlib-src/crypto/smartcont/highload-wallet.fif create mode 100644 submodules/ton/tonlib-src/crypto/smartcont/new-highload-wallet-v2.fif create mode 100644 submodules/ton/tonlib-src/crypto/smartcont/new-highload-wallet.fif delete mode 100644 submodules/ton/tonlib-src/tonlib/tonlib/.TonlibClient.cpp.swp create mode 100644 submodules/ton/tonlib-src/tonlib/tonlib/.TonlibError.h.swp create mode 100644 submodules/ton/tonlib-src/tonlib/tonlib/CellString.cpp create mode 100644 submodules/ton/tonlib-src/tonlib/tonlib/CellString.h create mode 100644 submodules/ton/tonlib-src/tonlib/tonlib/KeyValue.cpp create mode 100644 submodules/ton/tonlib-src/tonlib/tonlib/KeyValue.h create mode 100644 submodules/ton/tonlib-src/tonlib/tonlib/TonlibError.h diff --git a/Telegram-iOS/en.lproj/Localizable.strings b/Telegram-iOS/en.lproj/Localizable.strings index 0656169f6c..d411d4c1c9 100644 --- a/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram-iOS/en.lproj/Localizable.strings @@ -4780,6 +4780,7 @@ Any member of this group will be able to see messages in the channel."; "Wallet.Info.Send" = "Send"; "Wallet.Info.RefreshErrorTitle" = "An Error Occurred"; "Wallet.Info.RefreshErrorText" = "The wallet state can not be retrieved at this time. Please try again later."; +"Wallet.Info.RefreshErrorNetworkText" = "The wallet state can not be retrieved at this time. Please try again later."; "Wallet.Info.UnknownTransaction" = "Empty Transaction"; "Wallet.Info.TransactionTo" = "to"; "Wallet.Info.TransactionFrom" = "from"; @@ -4881,8 +4882,12 @@ Any member of this group will be able to see messages in the channel."; "Wallet.Words.NotDoneOk" = "OK, Sorry"; "Wallet.Words.NotDoneResponse" = "Apologies Accepted"; +"Wallet.Send.NetworkError" = "Network Error"; +"Wallet.Send.ErrorNotEnoughFunds" = "Not Enough Funds"; "Wallet.Send.ErrorInvalidAddress" = "Invalid wallet address. Please correct and try again."; "Wallet.Send.ErrorDecryptionFailed" = "Please make sure that your device has a passcode set in iOS Settings and try again."; +"Wallet.Send.UninitializedTitle" = "Warning"; +"Wallet.Send.UninitializedText" = "This address belongs to an empty wallet. Are you sure you want to transfer grams to it?"; "Wallet.Send.SendAnyway" = "Send Anyway"; "Wallet.Receive.CreateInvoice" = "Create Invoice"; diff --git a/submodules/CloudData/Sources/CloudData.swift b/submodules/CloudData/Sources/CloudData.swift index cc4d4338f5..28a79576ff 100644 --- a/submodules/CloudData/Sources/CloudData.swift +++ b/submodules/CloudData/Sources/CloudData.swift @@ -47,32 +47,47 @@ private func fetchRawData(prefix: String) -> Signal { } @available(iOS 10.0, *) -public func cloudDataAdditionalAddressSource(phoneNumber: Signal) -> Signal { - return phoneNumber - |> take(1) - |> mapToSignal { phoneNumber -> Signal in - var prefix = "" - if let phoneNumber = phoneNumber, phoneNumber.count >= 1 { - prefix = String(phoneNumber[phoneNumber.startIndex ..< phoneNumber.index(after: phoneNumber.startIndex)]) - } - return fetchRawData(prefix: prefix) - |> map { data -> MTBackupDatacenterData? in - if let datacenterData = MTIPDataDecode(data, phoneNumber ?? "") { - return datacenterData - } else { - return nil +private final class CloudDataPrefixContext { + private let prefix: String + private let value = Promise() + + private var lastRequestTimestamp: Double? + + init(prefix: String) { + self.prefix = prefix + } + + private func fetch() { + let fetchSignal = ( + fetchRawData(prefix: self.prefix) + |> map(Optional.init) + |> `catch` { error -> Signal in + switch error { + case .networkUnavailable: + return .complete() + default: + return .single(nil) + } } + |> restart + ) + |> take(1) + self.value.set(fetchSignal) + } + + func get() -> Signal { + var shouldFetch = false + let timestamp = CFAbsoluteTimeGetCurrent() + if let lastRequestTimestamp = self.lastRequestTimestamp { + shouldFetch = timestamp >= lastRequestTimestamp + 1.0 * 60.0 + } else { + shouldFetch = true } - |> `catch` { error -> Signal in - return .complete() - } - |> mapToSignal { data -> Signal in - if let data = data { - return .single(data) - } else { - return .complete() - } + if shouldFetch { + self.lastRequestTimestamp = timestamp + self.fetch() } + return self.value.get() } } @@ -80,32 +95,25 @@ public func cloudDataAdditionalAddressSource(phoneNumber: Signal Signal { + let context: CloudDataPrefixContext + if let current = self.prefixContexts[prefix] { + context = current + } else { + context = CloudDataPrefixContext(prefix: prefix) } - changesOperation.recordZoneWithIDWasDeletedBlock = { _ in - - } - changesOperation.changeTokenUpdatedBlock = { _ in - print("changeTokenUpdatedBlock") - } - changesOperation.fetchDatabaseChangesCompletionBlock = { serverChangeToken, isMoreComing, error in - print("done") - } - publicDatabase.add(changesOperation)*/ + return context.get() } } public protocol CloudDataContext { - + func get(phoneNumber: Signal) -> Signal } @available(iOS 10.0, *) @@ -119,4 +127,29 @@ public final class CloudDataContextImpl: CloudDataContext { return CloudDataContextObject(queue: queue) }) } + + public func get(phoneNumber: Signal) -> Signal { + return phoneNumber + |> take(1) + |> mapToSignal { phoneNumber -> Signal in + var prefix = "" + if let phoneNumber = phoneNumber, phoneNumber.count >= 1 { + prefix = String(phoneNumber[phoneNumber.startIndex ..< phoneNumber.index(after: phoneNumber.startIndex)]) + } + return Signal { subscriber in + let disposable = MetaDisposable() + self.impl.with { impl in + disposable.set(impl.get(prefix: prefix).start(next: { data in + if let data = data, let datacenterData = MTIPDataDecode(data, phoneNumber ?? "") { + subscriber.putNext(datacenterData) + subscriber.putCompletion() + } else { + subscriber.putCompletion() + } + })) + } + return disposable + } + } + } } diff --git a/submodules/ComposePollUI/Sources/CreatePollController.swift b/submodules/ComposePollUI/Sources/CreatePollController.swift index 160152c04c..59df335199 100644 --- a/submodules/ComposePollUI/Sources/CreatePollController.swift +++ b/submodules/ComposePollUI/Sources/CreatePollController.swift @@ -392,7 +392,7 @@ public func createPollController(context: AccountContext, peerId: PeerId, comple controller?.present(c, in: .window(.root), with: a) } dismissImpl = { [weak controller] in - controller?.view.endEditing(true) + //controller?.view.endEditing(true) controller?.dismiss() } ensureTextVisibleImpl = { [weak controller] in diff --git a/submodules/Display/Display/Navigation/NavigationController.swift b/submodules/Display/Display/Navigation/NavigationController.swift index ea862cf43e..429db1abae 100644 --- a/submodules/Display/Display/Navigation/NavigationController.swift +++ b/submodules/Display/Display/Navigation/NavigationController.swift @@ -401,8 +401,8 @@ open class NavigationController: UINavigationController, ContainableController, } if self.currentTopVisibleOverlayContainerStatusBar !== topVisibleOverlayContainerWithStatusBar { - self.currentTopVisibleOverlayContainerStatusBar = topVisibleOverlayContainerWithStatusBar animateStatusBarStyleTransition = true + self.currentTopVisibleOverlayContainerStatusBar = topVisibleOverlayContainerWithStatusBar } var previousModalContainer: NavigationModalContainer? diff --git a/submodules/GalleryUI/Sources/GalleryControllerNode.swift b/submodules/GalleryUI/Sources/GalleryControllerNode.swift index 6cdd05663a..31a920962c 100644 --- a/submodules/GalleryUI/Sources/GalleryControllerNode.swift +++ b/submodules/GalleryUI/Sources/GalleryControllerNode.swift @@ -375,9 +375,9 @@ open class GalleryControllerNode: ASDisplayNode, UIScrollViewDelegate, UIGesture if !self.areControlsHidden { if transition < 0.5 { - self.statusBar?.updateAlpha(0.0, transition: .animated(duration: 0.3, curve: .easeInOut)) + self.statusBar?.statusBarStyle = .Ignore } else { - self.statusBar?.updateAlpha(1.0, transition: .animated(duration: 0.3, curve: .easeInOut)) + self.statusBar?.statusBarStyle = .White } self.navigationBar?.alpha = transition self.footerNode.alpha = transition diff --git a/submodules/MtProtoKit/MTBackupAddressSignals.m b/submodules/MtProtoKit/MTBackupAddressSignals.m index 94dec7b1e7..e71cafdf18 100644 --- a/submodules/MtProtoKit/MTBackupAddressSignals.m +++ b/submodules/MtProtoKit/MTBackupAddressSignals.m @@ -307,7 +307,6 @@ static NSString *makeRandomPadding() { if (![datacenterData isKindOfClass:[MTBackupDatacenterData class]]) { return [MTSignal complete]; } - MTBackupDatacenterData *datacenterData = MTIPDataDecode(finalData, phoneNumber); if (datacenterData != nil && [self checkIpData:datacenterData timestamp:(int32_t)[currentContext globalTime] source:@"resolveExternal"]) { return [MTSignal single:datacenterData]; } else { diff --git a/submodules/MtProtoKit/MTProtoKit/MTEncryption.m b/submodules/MtProtoKit/MTProtoKit/MTEncryption.m index 4e778873f9..0d8e1ff568 100644 --- a/submodules/MtProtoKit/MTProtoKit/MTEncryption.m +++ b/submodules/MtProtoKit/MTProtoKit/MTEncryption.m @@ -964,6 +964,9 @@ static NSData *decrypt_TL_data(unsigned char buffer[256]) { @end MTBackupDatacenterData *MTIPDataDecode(NSData *data, NSString *phoneNumber) { + if (data.length < 256) { + return nil; + } unsigned char buffer[256]; memcpy(buffer, data.bytes, 256); NSData *result = decrypt_TL_data(buffer); diff --git a/submodules/MtProtoKit/TON/TON.h b/submodules/MtProtoKit/TON/TON.h index 5a53464b47..e385edf3d3 100644 --- a/submodules/MtProtoKit/TON/TON.h +++ b/submodules/MtProtoKit/TON/TON.h @@ -92,6 +92,7 @@ NS_ASSUME_NONNULL_BEGIN - (MTSignal *)exportKey:(TONKey *)key localPassword:(NSData *)localPassword; - (MTSignal *)importKeyWithLocalPassword:(NSData *)localPassword mnemonicPassword:(NSData *)mnemonicPassword wordList:(NSArray *)wordList; - (MTSignal *)deleteKey:(TONKey *)key; +- (MTSignal *)deleteAllKeys; - (MTSignal *)getTransactionListWithAddress:(NSString * _Nonnull)address lt:(int64_t)lt hash:(NSData * _Nonnull)hash; @end diff --git a/submodules/MtProtoKit/TON/TON.mm b/submodules/MtProtoKit/TON/TON.mm index 4624a00048..e76a4b01c1 100644 --- a/submodules/MtProtoKit/TON/TON.mm +++ b/submodules/MtProtoKit/TON/TON.mm @@ -328,7 +328,9 @@ typedef enum { false, false ), - keystoreDirectory.UTF8String + make_object( + keystoreDirectory.UTF8String + ) )); _client->send({ requestId, std::move(query) }); @@ -636,6 +638,28 @@ typedef enum { }] startOn:[MTQueue mainQueue]] deliverOn:[MTQueue mainQueue]]; } +- (MTSignal *)deleteAllKeys { + return [[[[MTSignal alloc] initWithGenerator:^id(MTSubscriber *subscriber) { + uint64_t requestId = _nextRequestId; + _nextRequestId += 1; + + _requestHandlers[@(requestId)] = [[TONRequestHandler alloc] initWithCompletion:^(tonlib_api::object_ptr &object) { + if (object->get_id() == tonlib_api::error::ID) { + auto error = tonlib_api::move_object_as(object); + [subscriber putError:[[TONError alloc] initWithText:[[NSString alloc] initWithUTF8String:error->message_.c_str()]]]; + } else { + [subscriber putCompletion]; + } + }]; + + auto query = make_object(); + _client->send({ requestId, std::move(query) }); + + return [[MTBlockDisposable alloc] initWithBlock:^{ + }]; + }] startOn:[MTQueue mainQueue]] deliverOn:[MTQueue mainQueue]]; +} + - (MTSignal *)getTransactionListWithAddress:(NSString * _Nonnull)address lt:(int64_t)lt hash:(NSData * _Nonnull)hash { return [[[[MTSignal alloc] initWithGenerator:^id(MTSubscriber *subscriber) { NSData *addressData = [address dataUsingEncoding:NSUTF8StringEncoding]; diff --git a/submodules/SSignalKit/SwiftSignalKit/Signal_Catch.swift b/submodules/SSignalKit/SwiftSignalKit/Signal_Catch.swift index 896b41b5ac..077c97d7ef 100644 --- a/submodules/SSignalKit/SwiftSignalKit/Signal_Catch.swift +++ b/submodules/SSignalKit/SwiftSignalKit/Signal_Catch.swift @@ -135,6 +135,55 @@ public func retry(_ delayIncrement: Double, maxDelay: Double, onQueue queu } } +public func retry(retryOnError: @escaping (E) -> Bool, delayIncrement: Double, maxDelay: Double, maxRetries: Int, onQueue queue: Queue) -> (_ signal: Signal) -> Signal { + return { signal in + return Signal { subscriber in + let shouldRetry = Atomic(value: true) + let currentDelay = Atomic<(Double, Int)>(value: (0.0, 0)) + let currentDisposable = MetaDisposable() + + let start = recursiveFunction { recurse in + let currentShouldRetry = shouldRetry.with { value in + return value + } + if currentShouldRetry { + let disposable = signal.start(next: { next in + subscriber.putNext(next) + }, error: { error in + if !retryOnError(error) { + subscriber.putError(error) + } else { + let (delay, count) = currentDelay.modify { value, count in + return (min(maxDelay, value + delayIncrement), count + 1) + } + + if count >= maxRetries { + subscriber.putError(error) + } else { + let time: DispatchTime = DispatchTime.now() + Double(delay) + queue.queue.asyncAfter(deadline: time, execute: { + recurse() + }) + } + } + }, completed: { + let _ = shouldRetry.swap(false) + subscriber.putCompletion() + }) + currentDisposable.set(disposable) + } + } + + start() + + return ActionDisposable { + currentDisposable.dispose() + let _ = shouldRetry.swap(false) + } + } + } +} + public func restartIfError(_ signal: Signal) -> Signal { return Signal { subscriber in let shouldRetry = Atomic(value: true) diff --git a/submodules/TelegramCore/TelegramCore/Network.swift b/submodules/TelegramCore/TelegramCore/Network.swift index 42ff256212..0ca9734570 100644 --- a/submodules/TelegramCore/TelegramCore/Network.swift +++ b/submodules/TelegramCore/TelegramCore/Network.swift @@ -417,6 +417,8 @@ public struct NetworkInitializationArguments { } } +private let cloudDataContext = makeCloudDataContext() + func initializedNetwork(arguments: NetworkInitializationArguments, supplementary: Bool, datacenterId: Int, keychain: Keychain, basePath: String, testingEnvironment: Bool, languageCode: String?, proxySettings: ProxySettings?, networkSettings: NetworkSettings?, phoneNumber: String?) -> Signal { return Signal { subscriber in let queue = Queue() @@ -484,17 +486,18 @@ func initializedNetwork(arguments: NetworkInitializationArguments, supplementary var wrappedAdditionalSource: MTSignal? if #available(iOS 10.0, *) { - let additionalSource = cloudDataAdditionalAddressSource(phoneNumber: .single(phoneNumber ?? "")) - wrappedAdditionalSource = MTSignal(generator: { subscriber in - let disposable = additionalSource.start(next: { value in - subscriber?.putNext(value) - }, completed: { - subscriber?.putCompletion() + if let cloudDataContext = cloudDataContext { + wrappedAdditionalSource = MTSignal(generator: { subscriber in + let disposable = cloudDataContext.get(phoneNumber: .single(phoneNumber)).start(next: { value in + subscriber?.putNext(value) + }, completed: { + subscriber?.putCompletion() + }) + return MTBlockDisposable(block: { + disposable.dispose() + }) }) - return MTBlockDisposable(block: { - disposable.dispose() - }) - }) + } } context.setDiscoverBackupAddressListSignal(MTBackupAddressSignals.fetchBackupIps(testingEnvironment, currentContext: context, additionalSource: wrappedAdditionalSource, phoneNumber: phoneNumber)) @@ -1010,7 +1013,8 @@ public final class Network: NSObject, MTRequestMessageServiceDelegate { } public func retryRequest(signal: Signal) -> Signal { - return signal |> retry(0.2, maxDelay: 5.0, onQueue: Queue.concurrentDefaultQueue()) + return signal + |> retry(0.2, maxDelay: 5.0, onQueue: Queue.concurrentDefaultQueue()) } class Keychain: NSObject, MTKeychain { @@ -1045,7 +1049,7 @@ class Keychain: NSObject, MTKeychain { } } -public func makeCloudDataContext() -> Any? { +func makeCloudDataContext() -> CloudDataContext? { if #available(iOS 10.0, *) { return CloudDataContextImpl() } else { diff --git a/submodules/TelegramCore/TelegramCore/Wallets.swift b/submodules/TelegramCore/TelegramCore/Wallets.swift index 64738ea8bd..163856e8bd 100644 --- a/submodules/TelegramCore/TelegramCore/Wallets.swift +++ b/submodules/TelegramCore/TelegramCore/Wallets.swift @@ -219,8 +219,16 @@ public final class TonInstance { return } subscriber.putNext(state) - }, error: { _ in - subscriber.putError(.generic) + }, error: { error in + if let error = error as? TONError { + if error.text.hasPrefix("LITE_SERVER_") { + subscriber.putError(.network) + } else { + subscriber.putError(.generic) + } + } else { + subscriber.putError(.generic) + } }, completed: { subscriber.putCompletion() }) @@ -241,7 +249,7 @@ public final class TonInstance { } } - fileprivate func walletLastTransactionId(address: String) -> Signal { + fileprivate func walletLastTransactionId(address: String) -> Signal { return Signal { subscriber in let disposable = MetaDisposable() @@ -253,7 +261,16 @@ public final class TonInstance { return } subscriber.putNext(state.lastTransactionId.flatMap(WalletTransactionId.init(tonTransactionId:))) - }, error: { _ in + }, error: { error in + if let error = error as? TONError { + if error.text.hasPrefix("ДITE_SERVER_") { + subscriber.putError(.network) + } else { + subscriber.putError(.generic) + } + } else { + subscriber.putError(.generic) + } }, completed: { subscriber.putCompletion() }) @@ -279,7 +296,16 @@ public final class TonInstance { return } subscriber.putNext(transactions.map(WalletTransaction.init(tonTransaction:))) - }, error: { _ in + }, error: { error in + if let error = error as? TONError { + if error.text.hasPrefix("LITE_SERVER_") { + subscriber.putError(.network) + } else { + subscriber.putError(.generic) + } + } else { + subscriber.putError(.generic) + } }, completed: { subscriber.putCompletion() }) @@ -308,10 +334,16 @@ public final class TonInstance { subscriber.putCompletion() }, error: { error in if let error = error as? TONError { - if error.text == "Failed to parse account address" { + if error.text.hasPrefix("INVALID_ACCOUNT_ADDRESS") { subscriber.putError(.invalidAddress) } else if error.text.hasPrefix("DANGEROUS_TRANSACTION") { subscriber.putError(.destinationIsNotInitialized) + } else if error.text.hasPrefix("MESSAGE_TOO_LONG") { + subscriber.putError(.messageTooLong) + } else if error.text.hasPrefix("NOT_ENOUGH_FUNDS") { + subscriber.putError(.notEnoughFunds) + } else if error.text.hasPrefix("LITE_SERVER_") { + subscriber.putError(.network) } else { subscriber.putError(.generic) } @@ -364,6 +396,29 @@ public final class TonInstance { } } + fileprivate func deleteAllLocalWalletsData() -> Signal { + return Signal { subscriber in + let disposable = MetaDisposable() + + self.impl.with { impl in + impl.withInstance { ton in + let cancel = ton.deleteAllKeys().start(next: { _ in + assertionFailure() + }, error: { _ in + subscriber.putError(.generic) + }, completed: { + subscriber.putCompletion() + }) + disposable.set(ActionDisposable { + cancel?.dispose() + }) + } + } + + return disposable + } + } + fileprivate func deleteLocalWalletData(walletInfo: WalletInfo, keychain: TonKeychain, serverSalt: Data) -> Signal { return keychain.decrypt(walletInfo.encryptedSecret) |> mapError { error -> DeleteLocalWalletDataError in @@ -580,6 +635,24 @@ public func importWallet(postbox: Postbox, network: Network, tonInstance: TonIns } } +public enum DeleteAllLocalWalletsDataError { + case generic +} + +public func deleteAllLocalWalletsData(postbox: Postbox, network: Network, tonInstance: TonInstance) -> Signal { + return tonInstance.deleteAllLocalWalletsData() + |> then( + postbox.transaction { transaction -> Void in + transaction.updatePreferencesEntry(key: PreferencesKeys.walletCollection, { current in + let walletCollection = (current as? WalletCollection) ?? WalletCollection(wallets: []) + return walletCollection + }) + } + |> castError(DeleteAllLocalWalletsDataError.self) + |> ignoreValues + ) +} + public enum DeleteLocalWalletDataError { case generic case secretDecryptionFailed(TonKeychainDecryptDataError) @@ -642,6 +715,7 @@ public func walletAddress(publicKey: WalletPublicKey, tonInstance: TonInstance) private enum GetWalletStateError { case generic + case network } private func getWalletState(address: String, tonInstance: TonInstance) -> Signal<(WalletState, Int64), GetWalletStateError> { @@ -650,6 +724,7 @@ private func getWalletState(address: String, tonInstance: TonInstance) -> Signal public enum GetCombinedWalletStateError { case generic + case network } public enum CombinedWalletStateResult { @@ -682,8 +757,19 @@ public func getCombinedWalletState(postbox: Postbox, subject: CombinedWalletStat |> castError(GetCombinedWalletStateError.self) |> mapToSignal { address -> Signal in return getWalletState(address: address, tonInstance: tonInstance) - |> mapError { _ -> GetCombinedWalletStateError in - return .generic + |> retryTonRequest(isNetworkError: { error in + if case .network = error { + return true + } else { + return false + } + }) + |> mapError { error -> GetCombinedWalletStateError in + if case .network = error { + return .network + } else { + return .generic + } } |> mapToSignal { walletState, syncUtime -> Signal in let topTransactions: Signal<[WalletTransaction], GetCombinedWalletStateError> @@ -691,8 +777,12 @@ public func getCombinedWalletState(postbox: Postbox, subject: CombinedWalletStat topTransactions = .single(cachedState?.topTransactions ?? []) } else { topTransactions = getWalletTransactions(address: address, previousId: nil, tonInstance: tonInstance) - |> mapError { _ -> GetCombinedWalletStateError in - return .generic + |> mapError { error -> GetCombinedWalletStateError in + if case .network = error { + return .network + } else { + return .generic + } } } return topTransactions @@ -744,6 +834,9 @@ public enum SendGramsFromWalletError { case secretDecryptionFailed case invalidAddress case destinationIsNotInitialized + case messageTooLong + case notEnoughFunds + case network } public func sendGramsFromWallet(network: Network, tonInstance: TonInstance, walletInfo: WalletInfo, decryptedSecret: Data, serverSalt: Data, toAddress: String, amount: Int64, textMessage: String, forceIfDestinationNotInitialized: Bool, timeout: Int32, randomId: Int64) -> Signal { @@ -862,6 +955,7 @@ private extension WalletTransaction { public enum GetWalletTransactionsError { case generic + case network } public func getWalletTransactions(address: String, previousId: WalletTransactionId?, tonInstance: TonInstance) -> Signal<[WalletTransaction], GetWalletTransactionsError> { @@ -885,18 +979,50 @@ public func getWalletTransactions(address: String, previousId: WalletTransaction } } +private func retryTonRequest(isNetworkError: @escaping (E) -> Bool) -> (Signal) -> Signal { + return { signal in + return signal + |> retry(retryOnError: isNetworkError, delayIncrement: 0.2, maxDelay: 5.0, maxRetries: 3, onQueue: Queue.concurrentDefaultQueue()) + } +} + +private enum WalletLastTransactionIdError { + case generic + case network +} + private func getWalletTransactionsOnce(address: String, previousId: WalletTransactionId?, tonInstance: TonInstance) -> Signal<[WalletTransaction], GetWalletTransactionsError> { let previousIdValue: Signal if let previousId = previousId { previousIdValue = .single(previousId) } else { previousIdValue = tonInstance.walletLastTransactionId(address: address) - |> castError(GetWalletTransactionsError.self) + |> retryTonRequest(isNetworkError: { error in + if case .network = error { + return true + } else { + return false + } + }) + |> mapError { error -> GetWalletTransactionsError in + if case .network = error { + return .network + } else { + return .generic + } + } } return previousIdValue |> mapToSignal { previousId in if let previousId = previousId { return tonInstance.getWalletTransactions(address: address, previousId: previousId) + |> retryTonRequest(isNetworkError: { error in + if case .network = error { + return true + } else { + return false + } + }) } else { return .single([]) } diff --git a/submodules/TelegramPresentationData/Sources/PresentationStrings.swift b/submodules/TelegramPresentationData/Sources/PresentationStrings.swift index 6f15434f38..249d2dce77 100644 --- a/submodules/TelegramPresentationData/Sources/PresentationStrings.swift +++ b/submodules/TelegramPresentationData/Sources/PresentationStrings.swift @@ -1717,3196 +1717,3201 @@ public final class PresentationStrings { return formatWithArgumentRanges(self._s[1427]!, self._r[1427]!, [_1, _2]) } public var Passport_Phone_UseTelegramNumberHelp: String { return self._s[1428]! } - public var SettingsSearch_Synonyms_Data_Title: String { return self._s[1431]! } - public var Passport_DeletePassport: String { return self._s[1432]! } - public var Appearance_AppIconFilled: String { return self._s[1433]! } - public var Privacy_Calls_P2PAlways: String { return self._s[1434]! } - public var Month_ShortDecember: String { return self._s[1435]! } - public var Channel_AdminLog_CanEditMessages: String { return self._s[1437]! } + public var Wallet_Send_ErrorNotEnoughFunds: String { return self._s[1431]! } + public var SettingsSearch_Synonyms_Data_Title: String { return self._s[1432]! } + public var Passport_DeletePassport: String { return self._s[1433]! } + public var Appearance_AppIconFilled: String { return self._s[1434]! } + public var Privacy_Calls_P2PAlways: String { return self._s[1435]! } + public var Month_ShortDecember: String { return self._s[1436]! } + public var Channel_AdminLog_CanEditMessages: String { return self._s[1438]! } public func Contacts_AccessDeniedHelpLandscape(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1438]!, self._r[1438]!, [_0]) + return formatWithArgumentRanges(self._s[1439]!, self._r[1439]!, [_0]) } - public var Channel_Stickers_Searching: String { return self._s[1439]! } - public var Conversation_EncryptedDescription1: String { return self._s[1440]! } - public var Conversation_EncryptedDescription2: String { return self._s[1441]! } - public var PasscodeSettings_PasscodeOptions: String { return self._s[1442]! } - public var Conversation_EncryptedDescription3: String { return self._s[1443]! } - public var PhotoEditor_SharpenTool: String { return self._s[1444]! } + public var Channel_Stickers_Searching: String { return self._s[1440]! } + public var Conversation_EncryptedDescription1: String { return self._s[1441]! } + public var Conversation_EncryptedDescription2: String { return self._s[1442]! } + public var PasscodeSettings_PasscodeOptions: String { return self._s[1443]! } + public var Conversation_EncryptedDescription3: String { return self._s[1444]! } + public var PhotoEditor_SharpenTool: String { return self._s[1445]! } public func Conversation_AddNameToContacts(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1445]!, self._r[1445]!, [_0]) + return formatWithArgumentRanges(self._s[1446]!, self._r[1446]!, [_0]) } - public var Conversation_EncryptedDescription4: String { return self._s[1447]! } - public var Channel_Members_AddMembers: String { return self._s[1448]! } - public var Wallpaper_Search: String { return self._s[1449]! } - public var Weekday_Friday: String { return self._s[1450]! } - public var Privacy_ContactsSync: String { return self._s[1451]! } - public var SettingsSearch_Synonyms_Privacy_Data_ContactsReset: String { return self._s[1452]! } - public var ApplyLanguage_ChangeLanguageAction: String { return self._s[1453]! } + public var Conversation_EncryptedDescription4: String { return self._s[1448]! } + public var Channel_Members_AddMembers: String { return self._s[1449]! } + public var Wallpaper_Search: String { return self._s[1450]! } + public var Weekday_Friday: String { return self._s[1451]! } + public var Privacy_ContactsSync: String { return self._s[1452]! } + public var SettingsSearch_Synonyms_Privacy_Data_ContactsReset: String { return self._s[1453]! } + public var ApplyLanguage_ChangeLanguageAction: String { return self._s[1454]! } public func Channel_Management_RestrictedBy(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1454]!, self._r[1454]!, [_0]) + return formatWithArgumentRanges(self._s[1455]!, self._r[1455]!, [_0]) } - public var GroupInfo_Permissions_Removed: String { return self._s[1455]! } - public var Passport_Identity_GenderMale: String { return self._s[1456]! } + public var GroupInfo_Permissions_Removed: String { return self._s[1456]! } + public var Passport_Identity_GenderMale: String { return self._s[1457]! } public func Call_StatusBar(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1457]!, self._r[1457]!, [_0]) + return formatWithArgumentRanges(self._s[1458]!, self._r[1458]!, [_0]) } - public var Updated_JustNow: String { return self._s[1458]! } - public var Notifications_PermissionsKeepDisabled: String { return self._s[1459]! } - public var Conversation_JumpToDate: String { return self._s[1460]! } - public var Contacts_GlobalSearch: String { return self._s[1461]! } - public var AutoDownloadSettings_ResetHelp: String { return self._s[1462]! } - public var SettingsSearch_Synonyms_FAQ: String { return self._s[1463]! } - public var Profile_MessageLifetime1d: String { return self._s[1464]! } + public var Updated_JustNow: String { return self._s[1459]! } + public var Notifications_PermissionsKeepDisabled: String { return self._s[1460]! } + public var Conversation_JumpToDate: String { return self._s[1461]! } + public var Contacts_GlobalSearch: String { return self._s[1462]! } + public var AutoDownloadSettings_ResetHelp: String { return self._s[1463]! } + public var SettingsSearch_Synonyms_FAQ: String { return self._s[1464]! } + public var Profile_MessageLifetime1d: String { return self._s[1465]! } public func MESSAGE_INVOICE(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1465]!, self._r[1465]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1466]!, self._r[1466]!, [_1, _2]) } - public var StickerPack_BuiltinPackName: String { return self._s[1468]! } + public var StickerPack_BuiltinPackName: String { return self._s[1469]! } public func PUSH_CHAT_MESSAGE_AUDIO(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1469]!, self._r[1469]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1470]!, self._r[1470]!, [_1, _2]) } - public var VoiceOver_Chat_RecordModeVoiceMessageInfo: String { return self._s[1470]! } - public var Passport_InfoTitle: String { return self._s[1472]! } - public var Notifications_PermissionsUnreachableText: String { return self._s[1473]! } + public var VoiceOver_Chat_RecordModeVoiceMessageInfo: String { return self._s[1471]! } + public var Passport_InfoTitle: String { return self._s[1473]! } + public var Notifications_PermissionsUnreachableText: String { return self._s[1474]! } public func NetworkUsageSettings_CellularUsageSince(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1477]!, self._r[1477]!, [_0]) + return formatWithArgumentRanges(self._s[1478]!, self._r[1478]!, [_0]) } public func PUSH_CHAT_MESSAGE_GEO(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1478]!, self._r[1478]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1479]!, self._r[1479]!, [_1, _2]) } - public var Passport_Address_TypePassportRegistrationUploadScan: String { return self._s[1479]! } - public var Profile_BotInfo: String { return self._s[1480]! } - public var Watch_Compose_CreateMessage: String { return self._s[1481]! } - public var AutoDownloadSettings_VoiceMessagesInfo: String { return self._s[1482]! } - public var Month_ShortNovember: String { return self._s[1483]! } - public var Conversation_ScamWarning: String { return self._s[1484]! } - public var Wallpaper_SetCustomBackground: String { return self._s[1485]! } - public var Passport_Identity_TranslationsHelp: String { return self._s[1486]! } - public var NotificationsSound_Chime: String { return self._s[1487]! } - public var Passport_Language_ko: String { return self._s[1489]! } - public var InviteText_URL: String { return self._s[1490]! } - public var TextFormat_Monospace: String { return self._s[1491]! } + public var Passport_Address_TypePassportRegistrationUploadScan: String { return self._s[1480]! } + public var Profile_BotInfo: String { return self._s[1481]! } + public var Watch_Compose_CreateMessage: String { return self._s[1482]! } + public var AutoDownloadSettings_VoiceMessagesInfo: String { return self._s[1483]! } + public var Month_ShortNovember: String { return self._s[1484]! } + public var Conversation_ScamWarning: String { return self._s[1485]! } + public var Wallpaper_SetCustomBackground: String { return self._s[1486]! } + public var Passport_Identity_TranslationsHelp: String { return self._s[1487]! } + public var NotificationsSound_Chime: String { return self._s[1488]! } + public var Passport_Language_ko: String { return self._s[1490]! } + public var InviteText_URL: String { return self._s[1491]! } + public var TextFormat_Monospace: String { return self._s[1492]! } public func Time_PreciseDate_m11(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1492]!, self._r[1492]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1493]!, self._r[1493]!, [_1, _2, _3]) } - public var EditTheme_Edit_BottomInfo: String { return self._s[1493]! } + public var EditTheme_Edit_BottomInfo: String { return self._s[1494]! } public func Login_WillSendSms(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1494]!, self._r[1494]!, [_0]) + return formatWithArgumentRanges(self._s[1495]!, self._r[1495]!, [_0]) } public func Watch_Time_ShortWeekdayAt(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1495]!, self._r[1495]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1496]!, self._r[1496]!, [_1, _2]) } - public var Wallet_Words_Title: String { return self._s[1497]! } - public var EditTheme_CreateTitle: String { return self._s[1499]! } - public var Passport_InfoLearnMore: String { return self._s[1500]! } - public var TwoStepAuth_EmailPlaceholder: String { return self._s[1501]! } - public var Passport_Identity_AddIdentityCard: String { return self._s[1502]! } - public var Your_card_has_expired: String { return self._s[1503]! } - public var StickerPacksSettings_StickerPacksSection: String { return self._s[1504]! } - public var GroupInfo_InviteLink_Help: String { return self._s[1505]! } - public var Conversation_Report: String { return self._s[1509]! } - public var Notifications_MessageNotificationsSound: String { return self._s[1510]! } - public var Notification_MessageLifetime1m: String { return self._s[1511]! } - public var Privacy_ContactsTitle: String { return self._s[1512]! } - public var Conversation_ShareMyContactInfo: String { return self._s[1513]! } - public var Wallet_WordCheck_Title: String { return self._s[1514]! } - public var ChannelMembers_WhoCanAddMembersAdminsHelp: String { return self._s[1515]! } - public var Channel_Members_Title: String { return self._s[1516]! } - public var Map_OpenInWaze: String { return self._s[1517]! } - public var Login_PhoneBannedError: String { return self._s[1518]! } + public var Wallet_Words_Title: String { return self._s[1498]! } + public var EditTheme_CreateTitle: String { return self._s[1500]! } + public var Passport_InfoLearnMore: String { return self._s[1501]! } + public var TwoStepAuth_EmailPlaceholder: String { return self._s[1502]! } + public var Passport_Identity_AddIdentityCard: String { return self._s[1503]! } + public var Your_card_has_expired: String { return self._s[1504]! } + public var StickerPacksSettings_StickerPacksSection: String { return self._s[1505]! } + public var GroupInfo_InviteLink_Help: String { return self._s[1506]! } + public var Conversation_Report: String { return self._s[1510]! } + public var Notifications_MessageNotificationsSound: String { return self._s[1511]! } + public var Notification_MessageLifetime1m: String { return self._s[1512]! } + public var Privacy_ContactsTitle: String { return self._s[1513]! } + public var Conversation_ShareMyContactInfo: String { return self._s[1514]! } + public var Wallet_WordCheck_Title: String { return self._s[1515]! } + public var ChannelMembers_WhoCanAddMembersAdminsHelp: String { return self._s[1516]! } + public var Channel_Members_Title: String { return self._s[1517]! } + public var Map_OpenInWaze: String { return self._s[1518]! } + public var Login_PhoneBannedError: String { return self._s[1519]! } public func LiveLocationUpdated_YesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1519]!, self._r[1519]!, [_0]) + return formatWithArgumentRanges(self._s[1520]!, self._r[1520]!, [_0]) } - public var Group_Management_AddModeratorHelp: String { return self._s[1520]! } - public var AutoDownloadSettings_WifiTitle: String { return self._s[1521]! } - public var Common_OK: String { return self._s[1522]! } - public var Passport_Address_TypeBankStatementUploadScan: String { return self._s[1523]! } - public var Wallet_Words_NotDoneResponse: String { return self._s[1524]! } - public var Cache_Music: String { return self._s[1525]! } - public var SettingsSearch_Synonyms_EditProfile_PhoneNumber: String { return self._s[1526]! } - public var PasscodeSettings_UnlockWithTouchId: String { return self._s[1527]! } - public var TwoStepAuth_HintPlaceholder: String { return self._s[1528]! } + public var Group_Management_AddModeratorHelp: String { return self._s[1521]! } + public var AutoDownloadSettings_WifiTitle: String { return self._s[1522]! } + public var Common_OK: String { return self._s[1523]! } + public var Passport_Address_TypeBankStatementUploadScan: String { return self._s[1524]! } + public var Wallet_Words_NotDoneResponse: String { return self._s[1525]! } + public var Cache_Music: String { return self._s[1526]! } + public var SettingsSearch_Synonyms_EditProfile_PhoneNumber: String { return self._s[1527]! } + public var PasscodeSettings_UnlockWithTouchId: String { return self._s[1528]! } + public var TwoStepAuth_HintPlaceholder: String { return self._s[1529]! } public func PUSH_PINNED_INVOICE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1529]!, self._r[1529]!, [_1]) + return formatWithArgumentRanges(self._s[1530]!, self._r[1530]!, [_1]) } public func Passport_RequestHeader(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1530]!, self._r[1530]!, [_0]) - } - public func VoiceOver_Chat_ContactOrganization(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[1531]!, self._r[1531]!, [_0]) } - public var Watch_MessageView_ViewOnPhone: String { return self._s[1533]! } - public var Privacy_Calls_CustomShareHelp: String { return self._s[1534]! } - public var Wallet_Receive_CreateInvoiceInfo: String { return self._s[1536]! } - public var ChangePhoneNumberNumber_Title: String { return self._s[1537]! } - public var State_ConnectingToProxyInfo: String { return self._s[1538]! } - public var Message_VideoMessage: String { return self._s[1540]! } - public var ChannelInfo_DeleteChannel: String { return self._s[1541]! } - public var ContactInfo_PhoneLabelOther: String { return self._s[1542]! } - public var Channel_EditAdmin_CannotEdit: String { return self._s[1543]! } - public var Passport_DeleteAddressConfirmation: String { return self._s[1544]! } - public var WallpaperPreview_SwipeBottomText: String { return self._s[1545]! } - public var Activity_RecordingAudio: String { return self._s[1546]! } - public var SettingsSearch_Synonyms_Watch: String { return self._s[1547]! } - public var PasscodeSettings_TryAgainIn1Minute: String { return self._s[1548]! } - public var Wallet_Info_Address: String { return self._s[1549]! } + public func VoiceOver_Chat_ContactOrganization(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[1532]!, self._r[1532]!, [_0]) + } + public var Watch_MessageView_ViewOnPhone: String { return self._s[1534]! } + public var Privacy_Calls_CustomShareHelp: String { return self._s[1535]! } + public var Wallet_Receive_CreateInvoiceInfo: String { return self._s[1537]! } + public var ChangePhoneNumberNumber_Title: String { return self._s[1538]! } + public var State_ConnectingToProxyInfo: String { return self._s[1539]! } + public var Message_VideoMessage: String { return self._s[1541]! } + public var ChannelInfo_DeleteChannel: String { return self._s[1542]! } + public var ContactInfo_PhoneLabelOther: String { return self._s[1543]! } + public var Channel_EditAdmin_CannotEdit: String { return self._s[1544]! } + public var Passport_DeleteAddressConfirmation: String { return self._s[1545]! } + public var WallpaperPreview_SwipeBottomText: String { return self._s[1546]! } + public var Activity_RecordingAudio: String { return self._s[1547]! } + public var SettingsSearch_Synonyms_Watch: String { return self._s[1548]! } + public var PasscodeSettings_TryAgainIn1Minute: String { return self._s[1549]! } + public var Wallet_Info_Address: String { return self._s[1550]! } public func Notification_ChangedGroupName(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1551]!, self._r[1551]!, [_0, _1]) + return formatWithArgumentRanges(self._s[1552]!, self._r[1552]!, [_0, _1]) } public func EmptyGroupInfo_Line1(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1555]!, self._r[1555]!, [_0]) + return formatWithArgumentRanges(self._s[1556]!, self._r[1556]!, [_0]) } - public var Conversation_ApplyLocalization: String { return self._s[1556]! } - public var UserInfo_AddPhone: String { return self._s[1557]! } - public var Map_ShareLiveLocationHelp: String { return self._s[1558]! } + public var Conversation_ApplyLocalization: String { return self._s[1557]! } + public var UserInfo_AddPhone: String { return self._s[1558]! } + public var Map_ShareLiveLocationHelp: String { return self._s[1559]! } public func Passport_Identity_NativeNameGenericHelp(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1559]!, self._r[1559]!, [_0]) + return formatWithArgumentRanges(self._s[1560]!, self._r[1560]!, [_0]) } - public var Passport_Scans: String { return self._s[1561]! } - public var BlockedUsers_Unblock: String { return self._s[1562]! } + public var Passport_Scans: String { return self._s[1562]! } + public var BlockedUsers_Unblock: String { return self._s[1563]! } public func PUSH_ENCRYPTION_REQUEST(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1563]!, self._r[1563]!, [_1]) + return formatWithArgumentRanges(self._s[1564]!, self._r[1564]!, [_1]) } - public var Channel_Management_LabelCreator: String { return self._s[1564]! } - public var Conversation_ReportSpamAndLeave: String { return self._s[1565]! } - public var SettingsSearch_Synonyms_EditProfile_Bio: String { return self._s[1566]! } - public var ChatList_UndoArchiveMultipleTitle: String { return self._s[1567]! } - public var Passport_Identity_NativeNameGenericTitle: String { return self._s[1568]! } + public var Channel_Management_LabelCreator: String { return self._s[1565]! } + public var Conversation_ReportSpamAndLeave: String { return self._s[1566]! } + public var SettingsSearch_Synonyms_EditProfile_Bio: String { return self._s[1567]! } + public var ChatList_UndoArchiveMultipleTitle: String { return self._s[1568]! } + public var Passport_Identity_NativeNameGenericTitle: String { return self._s[1569]! } public func Login_EmailPhoneBody(_ _0: String, _ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1569]!, self._r[1569]!, [_0, _1, _2]) + return formatWithArgumentRanges(self._s[1570]!, self._r[1570]!, [_0, _1, _2]) } - public var Login_PhoneNumberHelp: String { return self._s[1570]! } - public var LastSeen_ALongTimeAgo: String { return self._s[1571]! } - public var Channel_AdminLog_CanPinMessages: String { return self._s[1572]! } - public var ChannelIntro_CreateChannel: String { return self._s[1573]! } - public var Conversation_UnreadMessages: String { return self._s[1574]! } - public var SettingsSearch_Synonyms_Stickers_ArchivedPacks: String { return self._s[1575]! } - public var Channel_AdminLog_EmptyText: String { return self._s[1576]! } - public var Theme_Context_Apply: String { return self._s[1577]! } - public var Notification_GroupActivated: String { return self._s[1578]! } - public var NotificationSettings_ContactJoinedInfo: String { return self._s[1579]! } - public var Wallet_Intro_CreateWallet: String { return self._s[1580]! } + public var Login_PhoneNumberHelp: String { return self._s[1571]! } + public var LastSeen_ALongTimeAgo: String { return self._s[1572]! } + public var Channel_AdminLog_CanPinMessages: String { return self._s[1573]! } + public var ChannelIntro_CreateChannel: String { return self._s[1574]! } + public var Conversation_UnreadMessages: String { return self._s[1575]! } + public var SettingsSearch_Synonyms_Stickers_ArchivedPacks: String { return self._s[1576]! } + public var Channel_AdminLog_EmptyText: String { return self._s[1577]! } + public var Theme_Context_Apply: String { return self._s[1578]! } + public var Notification_GroupActivated: String { return self._s[1579]! } + public var NotificationSettings_ContactJoinedInfo: String { return self._s[1580]! } + public var Wallet_Intro_CreateWallet: String { return self._s[1581]! } public func Notification_PinnedContactMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1581]!, self._r[1581]!, [_0]) + return formatWithArgumentRanges(self._s[1582]!, self._r[1582]!, [_0]) } public func DownloadingStatus(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1582]!, self._r[1582]!, [_0, _1]) + return formatWithArgumentRanges(self._s[1583]!, self._r[1583]!, [_0, _1]) } - public var GroupInfo_ConvertToSupergroup: String { return self._s[1584]! } + public var GroupInfo_ConvertToSupergroup: String { return self._s[1585]! } public func PrivacyPolicy_AgeVerificationMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1585]!, self._r[1585]!, [_0]) + return formatWithArgumentRanges(self._s[1586]!, self._r[1586]!, [_0]) } - public var Undo_DeletedChannel: String { return self._s[1586]! } - public var CallFeedback_AddComment: String { return self._s[1587]! } + public var Undo_DeletedChannel: String { return self._s[1587]! } + public var CallFeedback_AddComment: String { return self._s[1588]! } public func Conversation_OpenBotLinkAllowMessages(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1588]!, self._r[1588]!, [_0]) + return formatWithArgumentRanges(self._s[1589]!, self._r[1589]!, [_0]) } - public var Document_TargetConfirmationFormat: String { return self._s[1589]! } + public var Document_TargetConfirmationFormat: String { return self._s[1590]! } public func Call_StatusOngoing(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1590]!, self._r[1590]!, [_0]) + return formatWithArgumentRanges(self._s[1591]!, self._r[1591]!, [_0]) } - public var LogoutOptions_SetPasscodeTitle: String { return self._s[1591]! } + public var LogoutOptions_SetPasscodeTitle: String { return self._s[1592]! } public func PUSH_CHAT_MESSAGE_GAME_SCORE(_ _1: String, _ _2: String, _ _3: String, _ _4: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1592]!, self._r[1592]!, [_1, _2, _3, _4]) + return formatWithArgumentRanges(self._s[1593]!, self._r[1593]!, [_1, _2, _3, _4]) } - public var Wallet_SecureStorageChanged_PasscodeText: String { return self._s[1593]! } - public var Theme_ErrorNotFound: String { return self._s[1594]! } - public var Contacts_SortByName: String { return self._s[1595]! } - public var SettingsSearch_Synonyms_Privacy_Forwards: String { return self._s[1596]! } + public var Wallet_SecureStorageChanged_PasscodeText: String { return self._s[1594]! } + public var Theme_ErrorNotFound: String { return self._s[1595]! } + public var Contacts_SortByName: String { return self._s[1596]! } + public var SettingsSearch_Synonyms_Privacy_Forwards: String { return self._s[1597]! } public func CHAT_MESSAGE_INVOICE(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1598]!, self._r[1598]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1599]!, self._r[1599]!, [_1, _2, _3]) } - public var Notification_Exceptions_RemoveFromExceptions: String { return self._s[1599]! } - public var ScheduledMessages_EditTime: String { return self._s[1600]! } - public var Conversation_ClearSelfHistory: String { return self._s[1601]! } - public var Checkout_NewCard_PostcodePlaceholder: String { return self._s[1602]! } - public var PasscodeSettings_DoNotMatch: String { return self._s[1603]! } - public var Stickers_SuggestNone: String { return self._s[1604]! } - public var ChatSettings_Cache: String { return self._s[1605]! } - public var Settings_SaveIncomingPhotos: String { return self._s[1606]! } - public var Media_ShareThisPhoto: String { return self._s[1607]! } - public var Chat_SlowmodeTooltipPending: String { return self._s[1608]! } - public var InfoPlist_NSContactsUsageDescription: String { return self._s[1609]! } - public var Conversation_ContextMenuCopyLink: String { return self._s[1610]! } - public var PrivacyPolicy_AgeVerificationTitle: String { return self._s[1611]! } - public var SettingsSearch_Synonyms_Stickers_Masks: String { return self._s[1612]! } - public var TwoStepAuth_SetupPasswordEnterPasswordNew: String { return self._s[1613]! } + public var Notification_Exceptions_RemoveFromExceptions: String { return self._s[1600]! } + public var ScheduledMessages_EditTime: String { return self._s[1601]! } + public var Conversation_ClearSelfHistory: String { return self._s[1602]! } + public var Checkout_NewCard_PostcodePlaceholder: String { return self._s[1603]! } + public var PasscodeSettings_DoNotMatch: String { return self._s[1604]! } + public var Stickers_SuggestNone: String { return self._s[1605]! } + public var ChatSettings_Cache: String { return self._s[1606]! } + public var Settings_SaveIncomingPhotos: String { return self._s[1607]! } + public var Media_ShareThisPhoto: String { return self._s[1608]! } + public var Chat_SlowmodeTooltipPending: String { return self._s[1609]! } + public var InfoPlist_NSContactsUsageDescription: String { return self._s[1610]! } + public var Conversation_ContextMenuCopyLink: String { return self._s[1611]! } + public var PrivacyPolicy_AgeVerificationTitle: String { return self._s[1612]! } + public var SettingsSearch_Synonyms_Stickers_Masks: String { return self._s[1613]! } + public var TwoStepAuth_SetupPasswordEnterPasswordNew: String { return self._s[1614]! } public func Wallet_SecureStorageReset_BiometryText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1614]!, self._r[1614]!, [_0]) + return formatWithArgumentRanges(self._s[1615]!, self._r[1615]!, [_0]) } - public var Permissions_CellularDataTitle_v0: String { return self._s[1615]! } - public var WallpaperSearch_ColorWhite: String { return self._s[1617]! } - public var Channel_AdminLog_DefaultRestrictionsUpdated: String { return self._s[1618]! } - public var Conversation_ErrorInaccessibleMessage: String { return self._s[1619]! } - public var Map_OpenIn: String { return self._s[1620]! } + public var Permissions_CellularDataTitle_v0: String { return self._s[1616]! } + public var WallpaperSearch_ColorWhite: String { return self._s[1618]! } + public var Channel_AdminLog_DefaultRestrictionsUpdated: String { return self._s[1619]! } + public var Conversation_ErrorInaccessibleMessage: String { return self._s[1620]! } + public var Map_OpenIn: String { return self._s[1621]! } public func PUSH_PHONE_CALL_MISSED(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1623]!, self._r[1623]!, [_1]) + return formatWithArgumentRanges(self._s[1624]!, self._r[1624]!, [_1]) } public func ChannelInfo_AddParticipantConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1624]!, self._r[1624]!, [_0]) + return formatWithArgumentRanges(self._s[1625]!, self._r[1625]!, [_0]) } - public var GroupInfo_Permissions_SlowmodeHeader: String { return self._s[1625]! } - public var MessagePoll_LabelClosed: String { return self._s[1626]! } - public var GroupPermission_PermissionGloballyDisabled: String { return self._s[1628]! } - public var Wallet_Send_SendAnyway: String { return self._s[1629]! } - public var Passport_Identity_MiddleNamePlaceholder: String { return self._s[1630]! } - public var UserInfo_FirstNamePlaceholder: String { return self._s[1631]! } - public var PrivacyLastSeenSettings_WhoCanSeeMyTimestamp: String { return self._s[1632]! } - public var Login_SelectCountry_Title: String { return self._s[1634]! } - public var Channel_EditAdmin_PermissionBanUsers: String { return self._s[1635]! } + public var GroupInfo_Permissions_SlowmodeHeader: String { return self._s[1626]! } + public var MessagePoll_LabelClosed: String { return self._s[1627]! } + public var GroupPermission_PermissionGloballyDisabled: String { return self._s[1629]! } + public var Wallet_Send_SendAnyway: String { return self._s[1630]! } + public var Passport_Identity_MiddleNamePlaceholder: String { return self._s[1631]! } + public var UserInfo_FirstNamePlaceholder: String { return self._s[1632]! } + public var PrivacyLastSeenSettings_WhoCanSeeMyTimestamp: String { return self._s[1633]! } + public var Login_SelectCountry_Title: String { return self._s[1635]! } + public var Channel_EditAdmin_PermissionBanUsers: String { return self._s[1636]! } public func Conversation_OpenBotLinkLogin(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1636]!, self._r[1636]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1637]!, self._r[1637]!, [_1, _2]) } - public var Channel_AdminLog_ChangeInfo: String { return self._s[1637]! } - public var Watch_Suggestion_BRB: String { return self._s[1638]! } - public var Passport_Identity_EditIdentityCard: String { return self._s[1639]! } - public var Contacts_PermissionsTitle: String { return self._s[1640]! } - public var Conversation_RestrictedInline: String { return self._s[1641]! } - public var StickerPack_ViewPack: String { return self._s[1643]! } + public var Channel_AdminLog_ChangeInfo: String { return self._s[1638]! } + public var Watch_Suggestion_BRB: String { return self._s[1639]! } + public var Passport_Identity_EditIdentityCard: String { return self._s[1640]! } + public var Contacts_PermissionsTitle: String { return self._s[1641]! } + public var Conversation_RestrictedInline: String { return self._s[1642]! } + public var StickerPack_ViewPack: String { return self._s[1644]! } public func Update_AppVersion(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1644]!, self._r[1644]!, [_0]) + return formatWithArgumentRanges(self._s[1645]!, self._r[1645]!, [_0]) } - public var Compose_NewChannel: String { return self._s[1646]! } - public var ChatSettings_AutoDownloadSettings_TypePhoto: String { return self._s[1649]! } - public var Conversation_ReportSpamGroupConfirmation: String { return self._s[1651]! } - public var Channel_Info_Stickers: String { return self._s[1652]! } - public var AutoNightTheme_PreferredTheme: String { return self._s[1653]! } - public var PrivacyPolicy_AgeVerificationAgree: String { return self._s[1654]! } - public var Passport_DeletePersonalDetails: String { return self._s[1655]! } - public var LogoutOptions_AddAccountTitle: String { return self._s[1656]! } - public var Channel_DiscussionGroupInfo: String { return self._s[1657]! } - public var Group_EditAdmin_RankOwnerPlaceholder: String { return self._s[1658]! } - public var Conversation_SearchNoResults: String { return self._s[1660]! } - public var MessagePoll_LabelAnonymous: String { return self._s[1661]! } - public var Channel_Members_AddAdminErrorNotAMember: String { return self._s[1662]! } - public var Login_Code: String { return self._s[1663]! } - public var EditTheme_Create_BottomInfo: String { return self._s[1664]! } - public var Watch_Suggestion_WhatsUp: String { return self._s[1665]! } - public var Weekday_ShortThursday: String { return self._s[1666]! } - public var Resolve_ErrorNotFound: String { return self._s[1668]! } - public var LastSeen_Offline: String { return self._s[1670]! } - public var PeopleNearby_NoMembers: String { return self._s[1671]! } - public var GroupPermission_AddMembersNotAvailable: String { return self._s[1672]! } - public var Privacy_Calls_AlwaysAllow_Title: String { return self._s[1673]! } - public var GroupInfo_Title: String { return self._s[1675]! } - public var NotificationsSound_Note: String { return self._s[1676]! } - public var Conversation_EditingMessagePanelTitle: String { return self._s[1677]! } - public var Watch_Message_Poll: String { return self._s[1679]! } - public var Privacy_Calls: String { return self._s[1680]! } + public var Compose_NewChannel: String { return self._s[1647]! } + public var ChatSettings_AutoDownloadSettings_TypePhoto: String { return self._s[1650]! } + public var Conversation_ReportSpamGroupConfirmation: String { return self._s[1652]! } + public var Channel_Info_Stickers: String { return self._s[1653]! } + public var AutoNightTheme_PreferredTheme: String { return self._s[1654]! } + public var PrivacyPolicy_AgeVerificationAgree: String { return self._s[1655]! } + public var Passport_DeletePersonalDetails: String { return self._s[1656]! } + public var LogoutOptions_AddAccountTitle: String { return self._s[1657]! } + public var Channel_DiscussionGroupInfo: String { return self._s[1658]! } + public var Group_EditAdmin_RankOwnerPlaceholder: String { return self._s[1659]! } + public var Conversation_SearchNoResults: String { return self._s[1661]! } + public var MessagePoll_LabelAnonymous: String { return self._s[1662]! } + public var Channel_Members_AddAdminErrorNotAMember: String { return self._s[1663]! } + public var Login_Code: String { return self._s[1664]! } + public var EditTheme_Create_BottomInfo: String { return self._s[1665]! } + public var Watch_Suggestion_WhatsUp: String { return self._s[1666]! } + public var Weekday_ShortThursday: String { return self._s[1667]! } + public var Resolve_ErrorNotFound: String { return self._s[1669]! } + public var LastSeen_Offline: String { return self._s[1671]! } + public var PeopleNearby_NoMembers: String { return self._s[1672]! } + public var GroupPermission_AddMembersNotAvailable: String { return self._s[1673]! } + public var Privacy_Calls_AlwaysAllow_Title: String { return self._s[1674]! } + public var GroupInfo_Title: String { return self._s[1676]! } + public var NotificationsSound_Note: String { return self._s[1677]! } + public var Conversation_EditingMessagePanelTitle: String { return self._s[1678]! } + public var Watch_Message_Poll: String { return self._s[1680]! } + public var Privacy_Calls: String { return self._s[1681]! } public func Channel_AdminLog_MessageRankUsername(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1681]!, self._r[1681]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1682]!, self._r[1682]!, [_1, _2, _3]) } - public var Month_ShortAugust: String { return self._s[1682]! } - public var TwoStepAuth_SetPasswordHelp: String { return self._s[1683]! } - public var Notifications_Reset: String { return self._s[1684]! } - public var Conversation_Pin: String { return self._s[1685]! } - public var Passport_Language_lv: String { return self._s[1686]! } - public var Permissions_PeopleNearbyAllowInSettings_v0: String { return self._s[1687]! } - public var BlockedUsers_Info: String { return self._s[1688]! } - public var SettingsSearch_Synonyms_Data_AutoplayVideos: String { return self._s[1690]! } - public var Watch_Conversation_Unblock: String { return self._s[1692]! } + public var Month_ShortAugust: String { return self._s[1683]! } + public var TwoStepAuth_SetPasswordHelp: String { return self._s[1684]! } + public var Notifications_Reset: String { return self._s[1685]! } + public var Conversation_Pin: String { return self._s[1686]! } + public var Passport_Language_lv: String { return self._s[1687]! } + public var Permissions_PeopleNearbyAllowInSettings_v0: String { return self._s[1688]! } + public var BlockedUsers_Info: String { return self._s[1689]! } + public var SettingsSearch_Synonyms_Data_AutoplayVideos: String { return self._s[1691]! } + public var Watch_Conversation_Unblock: String { return self._s[1693]! } public func Time_MonthOfYear_m9(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1693]!, self._r[1693]!, [_0]) + return formatWithArgumentRanges(self._s[1694]!, self._r[1694]!, [_0]) } - public var CloudStorage_Title: String { return self._s[1694]! } - public var GroupInfo_DeleteAndExitConfirmation: String { return self._s[1695]! } + public var CloudStorage_Title: String { return self._s[1695]! } + public var GroupInfo_DeleteAndExitConfirmation: String { return self._s[1696]! } public func NetworkUsageSettings_WifiUsageSince(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1696]!, self._r[1696]!, [_0]) + return formatWithArgumentRanges(self._s[1697]!, self._r[1697]!, [_0]) } - public var Channel_AdminLogFilter_AdminsTitle: String { return self._s[1697]! } - public var Watch_Suggestion_OnMyWay: String { return self._s[1698]! } - public var TwoStepAuth_RecoveryEmailTitle: String { return self._s[1699]! } - public var Passport_Address_EditBankStatement: String { return self._s[1700]! } + public var Channel_AdminLogFilter_AdminsTitle: String { return self._s[1698]! } + public var Watch_Suggestion_OnMyWay: String { return self._s[1699]! } + public var TwoStepAuth_RecoveryEmailTitle: String { return self._s[1700]! } + public var Passport_Address_EditBankStatement: String { return self._s[1701]! } public func Channel_AdminLog_MessageChangedUnlinkedGroup(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1701]!, self._r[1701]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1702]!, self._r[1702]!, [_1, _2]) } - public var ChatSettings_DownloadInBackgroundInfo: String { return self._s[1702]! } - public var ShareMenu_Comment: String { return self._s[1703]! } - public var Permissions_ContactsTitle_v0: String { return self._s[1704]! } - public var Notifications_PermissionsTitle: String { return self._s[1705]! } - public var GroupPermission_NoSendLinks: String { return self._s[1706]! } - public var Privacy_Forwards_NeverAllow_Title: String { return self._s[1707]! } - public var Wallet_SecureStorageChanged_ImportWallet: String { return self._s[1708]! } - public var Settings_Support: String { return self._s[1709]! } - public var Notifications_ChannelNotificationsSound: String { return self._s[1710]! } - public var SettingsSearch_Synonyms_Data_AutoDownloadReset: String { return self._s[1711]! } - public var Privacy_Forwards_Preview: String { return self._s[1712]! } - public var GroupPermission_ApplyAlertAction: String { return self._s[1713]! } - public var Watch_Stickers_StickerPacks: String { return self._s[1714]! } - public var Common_Select: String { return self._s[1716]! } - public var CheckoutInfo_ErrorEmailInvalid: String { return self._s[1717]! } - public var WallpaperSearch_ColorGray: String { return self._s[1719]! } - public var ChatAdmins_AllMembersAreAdminsOffHelp: String { return self._s[1720]! } - public var PasscodeSettings_AutoLock_IfAwayFor_5hours: String { return self._s[1721]! } - public var Appearance_PreviewReplyAuthor: String { return self._s[1722]! } - public var TwoStepAuth_RecoveryTitle: String { return self._s[1723]! } - public var Widget_AuthRequired: String { return self._s[1724]! } - public var Camera_FlashOn: String { return self._s[1725]! } - public var Conversation_ContextMenuLookUp: String { return self._s[1726]! } - public var Channel_Stickers_NotFoundHelp: String { return self._s[1727]! } - public var Watch_Suggestion_OK: String { return self._s[1728]! } + public var ChatSettings_DownloadInBackgroundInfo: String { return self._s[1703]! } + public var ShareMenu_Comment: String { return self._s[1704]! } + public var Permissions_ContactsTitle_v0: String { return self._s[1705]! } + public var Notifications_PermissionsTitle: String { return self._s[1706]! } + public var GroupPermission_NoSendLinks: String { return self._s[1707]! } + public var Privacy_Forwards_NeverAllow_Title: String { return self._s[1708]! } + public var Wallet_SecureStorageChanged_ImportWallet: String { return self._s[1709]! } + public var Settings_Support: String { return self._s[1710]! } + public var Notifications_ChannelNotificationsSound: String { return self._s[1711]! } + public var SettingsSearch_Synonyms_Data_AutoDownloadReset: String { return self._s[1712]! } + public var Privacy_Forwards_Preview: String { return self._s[1713]! } + public var GroupPermission_ApplyAlertAction: String { return self._s[1714]! } + public var Watch_Stickers_StickerPacks: String { return self._s[1715]! } + public var Common_Select: String { return self._s[1717]! } + public var CheckoutInfo_ErrorEmailInvalid: String { return self._s[1718]! } + public var WallpaperSearch_ColorGray: String { return self._s[1720]! } + public var ChatAdmins_AllMembersAreAdminsOffHelp: String { return self._s[1721]! } + public var PasscodeSettings_AutoLock_IfAwayFor_5hours: String { return self._s[1722]! } + public var Appearance_PreviewReplyAuthor: String { return self._s[1723]! } + public var TwoStepAuth_RecoveryTitle: String { return self._s[1724]! } + public var Widget_AuthRequired: String { return self._s[1725]! } + public var Camera_FlashOn: String { return self._s[1726]! } + public var Conversation_ContextMenuLookUp: String { return self._s[1727]! } + public var Channel_Stickers_NotFoundHelp: String { return self._s[1728]! } + public var Watch_Suggestion_OK: String { return self._s[1729]! } public func Username_LinkHint(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1730]!, self._r[1730]!, [_0]) + return formatWithArgumentRanges(self._s[1731]!, self._r[1731]!, [_0]) } public func Notification_PinnedLiveLocationMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1732]!, self._r[1732]!, [_0]) + return formatWithArgumentRanges(self._s[1733]!, self._r[1733]!, [_0]) } - public var TextFormat_Strikethrough: String { return self._s[1733]! } - public var DialogList_AdLabel: String { return self._s[1734]! } - public var WatchRemote_NotificationText: String { return self._s[1735]! } - public var SettingsSearch_Synonyms_Notifications_MessageNotificationsAlert: String { return self._s[1736]! } - public var Conversation_ReportSpam: String { return self._s[1737]! } - public var SettingsSearch_Synonyms_Privacy_Data_TopPeers: String { return self._s[1738]! } - public var Settings_LogoutConfirmationTitle: String { return self._s[1740]! } - public var PhoneLabel_Title: String { return self._s[1741]! } - public var Passport_Address_EditRentalAgreement: String { return self._s[1742]! } - public var Settings_ChangePhoneNumber: String { return self._s[1743]! } - public var Notifications_ExceptionsTitle: String { return self._s[1744]! } - public var Notifications_AlertTones: String { return self._s[1745]! } - public var Call_ReportIncludeLogDescription: String { return self._s[1746]! } - public var SettingsSearch_Synonyms_Notifications_ResetAllNotifications: String { return self._s[1747]! } - public var AutoDownloadSettings_PrivateChats: String { return self._s[1748]! } - public var VoiceOver_Chat_Photo: String { return self._s[1750]! } - public var TwoStepAuth_AddHintTitle: String { return self._s[1751]! } - public var ReportPeer_ReasonOther: String { return self._s[1752]! } - public var ChatList_Context_JoinChannel: String { return self._s[1753]! } - public var KeyCommand_ScrollDown: String { return self._s[1755]! } - public var Conversation_ScheduleMessage_Title: String { return self._s[1756]! } + public var TextFormat_Strikethrough: String { return self._s[1734]! } + public var DialogList_AdLabel: String { return self._s[1735]! } + public var WatchRemote_NotificationText: String { return self._s[1736]! } + public var SettingsSearch_Synonyms_Notifications_MessageNotificationsAlert: String { return self._s[1737]! } + public var Conversation_ReportSpam: String { return self._s[1738]! } + public var SettingsSearch_Synonyms_Privacy_Data_TopPeers: String { return self._s[1739]! } + public var Settings_LogoutConfirmationTitle: String { return self._s[1741]! } + public var PhoneLabel_Title: String { return self._s[1742]! } + public var Passport_Address_EditRentalAgreement: String { return self._s[1743]! } + public var Settings_ChangePhoneNumber: String { return self._s[1744]! } + public var Notifications_ExceptionsTitle: String { return self._s[1745]! } + public var Notifications_AlertTones: String { return self._s[1746]! } + public var Call_ReportIncludeLogDescription: String { return self._s[1747]! } + public var SettingsSearch_Synonyms_Notifications_ResetAllNotifications: String { return self._s[1748]! } + public var AutoDownloadSettings_PrivateChats: String { return self._s[1749]! } + public var VoiceOver_Chat_Photo: String { return self._s[1751]! } + public var TwoStepAuth_AddHintTitle: String { return self._s[1752]! } + public var ReportPeer_ReasonOther: String { return self._s[1753]! } + public var ChatList_Context_JoinChannel: String { return self._s[1754]! } + public var KeyCommand_ScrollDown: String { return self._s[1756]! } + public var Conversation_ScheduleMessage_Title: String { return self._s[1757]! } public func Login_BannedPhoneSubject(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1757]!, self._r[1757]!, [_0]) + return formatWithArgumentRanges(self._s[1758]!, self._r[1758]!, [_0]) } - public var NetworkUsageSettings_MediaVideoDataSection: String { return self._s[1758]! } - public var ChannelInfo_DeleteGroupConfirmation: String { return self._s[1759]! } - public var AuthSessions_LogOut: String { return self._s[1760]! } - public var Passport_Identity_TypeInternalPassport: String { return self._s[1761]! } - public var ChatSettings_AutoDownloadVoiceMessages: String { return self._s[1762]! } - public var Passport_Phone_Title: String { return self._s[1763]! } - public var ContactList_Context_StartSecretChat: String { return self._s[1764]! } - public var Settings_PhoneNumber: String { return self._s[1765]! } + public var NetworkUsageSettings_MediaVideoDataSection: String { return self._s[1759]! } + public var ChannelInfo_DeleteGroupConfirmation: String { return self._s[1760]! } + public var AuthSessions_LogOut: String { return self._s[1761]! } + public var Passport_Identity_TypeInternalPassport: String { return self._s[1762]! } + public var ChatSettings_AutoDownloadVoiceMessages: String { return self._s[1763]! } + public var Passport_Phone_Title: String { return self._s[1764]! } + public var ContactList_Context_StartSecretChat: String { return self._s[1765]! } + public var Settings_PhoneNumber: String { return self._s[1766]! } public func Conversation_ScheduleMessage_SendToday(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1766]!, self._r[1766]!, [_0]) + return formatWithArgumentRanges(self._s[1767]!, self._r[1767]!, [_0]) } - public var NotificationsSound_Alert: String { return self._s[1767]! } - public var Wallet_SecureStorageChanged_CreateWallet: String { return self._s[1768]! } - public var WebSearch_SearchNoResults: String { return self._s[1769]! } - public var Privacy_ProfilePhoto_AlwaysShareWith_Title: String { return self._s[1771]! } - public var LogoutOptions_AlternativeOptionsSection: String { return self._s[1772]! } - public var SettingsSearch_Synonyms_Passport: String { return self._s[1773]! } - public var PhotoEditor_CurvesTool: String { return self._s[1774]! } - public var Checkout_PaymentMethod: String { return self._s[1776]! } + public var NotificationsSound_Alert: String { return self._s[1768]! } + public var Wallet_SecureStorageChanged_CreateWallet: String { return self._s[1769]! } + public var WebSearch_SearchNoResults: String { return self._s[1770]! } + public var Privacy_ProfilePhoto_AlwaysShareWith_Title: String { return self._s[1772]! } + public var LogoutOptions_AlternativeOptionsSection: String { return self._s[1773]! } + public var SettingsSearch_Synonyms_Passport: String { return self._s[1774]! } + public var PhotoEditor_CurvesTool: String { return self._s[1775]! } + public var Checkout_PaymentMethod: String { return self._s[1777]! } public func PUSH_CHAT_ADD_YOU(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1777]!, self._r[1777]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1778]!, self._r[1778]!, [_1, _2]) } - public var Contacts_AccessDeniedError: String { return self._s[1778]! } - public var Camera_PhotoMode: String { return self._s[1781]! } - public var EditTheme_Expand_Preview_IncomingText: String { return self._s[1782]! } + public var Contacts_AccessDeniedError: String { return self._s[1779]! } + public var Camera_PhotoMode: String { return self._s[1782]! } + public var EditTheme_Expand_Preview_IncomingText: String { return self._s[1783]! } public func Updated_TodayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1783]!, self._r[1783]!, [_0]) + return formatWithArgumentRanges(self._s[1784]!, self._r[1784]!, [_0]) } - public var Passport_Address_AddUtilityBill: String { return self._s[1785]! } - public var CallSettings_OnMobile: String { return self._s[1786]! } - public var Tour_Text2: String { return self._s[1787]! } + public var Passport_Address_AddUtilityBill: String { return self._s[1786]! } + public var CallSettings_OnMobile: String { return self._s[1787]! } + public var Tour_Text2: String { return self._s[1788]! } public func PUSH_CHAT_MESSAGE_ROUND(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1788]!, self._r[1788]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1789]!, self._r[1789]!, [_1, _2]) } - public var DialogList_EncryptionProcessing: String { return self._s[1790]! } - public var Permissions_Skip: String { return self._s[1791]! } - public var Wallet_Words_NotDoneOk: String { return self._s[1792]! } - public var SecretImage_Title: String { return self._s[1793]! } - public var Watch_MessageView_Title: String { return self._s[1794]! } - public var Channel_DiscussionGroupAdd: String { return self._s[1795]! } - public var AttachmentMenu_Poll: String { return self._s[1796]! } + public var DialogList_EncryptionProcessing: String { return self._s[1791]! } + public var Permissions_Skip: String { return self._s[1792]! } + public var Wallet_Words_NotDoneOk: String { return self._s[1793]! } + public var SecretImage_Title: String { return self._s[1794]! } + public var Watch_MessageView_Title: String { return self._s[1795]! } + public var Channel_DiscussionGroupAdd: String { return self._s[1796]! } + public var AttachmentMenu_Poll: String { return self._s[1797]! } public func Notification_GroupInviter(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1797]!, self._r[1797]!, [_0]) + return formatWithArgumentRanges(self._s[1798]!, self._r[1798]!, [_0]) } public func Channel_DiscussionGroup_PrivateChannelLink(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1798]!, self._r[1798]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1799]!, self._r[1799]!, [_1, _2]) } - public var Notification_CallCanceled: String { return self._s[1799]! } - public var WallpaperPreview_Title: String { return self._s[1800]! } - public var Privacy_PaymentsClear_PaymentInfo: String { return self._s[1801]! } - public var Settings_ProxyConnecting: String { return self._s[1802]! } - public var Settings_CheckPhoneNumberText: String { return self._s[1804]! } - public var VoiceOver_Chat_YourVideo: String { return self._s[1805]! } - public var Wallet_Intro_Title: String { return self._s[1806]! } - public var Profile_MessageLifetime5s: String { return self._s[1807]! } - public var Username_InvalidCharacters: String { return self._s[1808]! } - public var VoiceOver_Media_PlaybackRateFast: String { return self._s[1809]! } - public var ScheduledMessages_ClearAll: String { return self._s[1810]! } - public var WallpaperPreview_CropBottomText: String { return self._s[1811]! } - public var AutoDownloadSettings_LimitBySize: String { return self._s[1812]! } - public var Settings_AddAccount: String { return self._s[1813]! } - public var Notification_CreatedChannel: String { return self._s[1816]! } + public var Notification_CallCanceled: String { return self._s[1800]! } + public var WallpaperPreview_Title: String { return self._s[1801]! } + public var Privacy_PaymentsClear_PaymentInfo: String { return self._s[1802]! } + public var Settings_ProxyConnecting: String { return self._s[1803]! } + public var Settings_CheckPhoneNumberText: String { return self._s[1805]! } + public var VoiceOver_Chat_YourVideo: String { return self._s[1806]! } + public var Wallet_Intro_Title: String { return self._s[1807]! } + public var Profile_MessageLifetime5s: String { return self._s[1808]! } + public var Username_InvalidCharacters: String { return self._s[1809]! } + public var VoiceOver_Media_PlaybackRateFast: String { return self._s[1810]! } + public var ScheduledMessages_ClearAll: String { return self._s[1811]! } + public var WallpaperPreview_CropBottomText: String { return self._s[1812]! } + public var AutoDownloadSettings_LimitBySize: String { return self._s[1813]! } + public var Settings_AddAccount: String { return self._s[1814]! } + public var Notification_CreatedChannel: String { return self._s[1817]! } public func PUSH_CHAT_DELETE_MEMBER(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1817]!, self._r[1817]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1818]!, self._r[1818]!, [_1, _2, _3]) } - public var Passcode_AppLockedAlert: String { return self._s[1819]! } - public var StickerPacksSettings_AnimatedStickersInfo: String { return self._s[1820]! } - public var VoiceOver_Media_PlaybackStop: String { return self._s[1821]! } - public var Contacts_TopSection: String { return self._s[1822]! } + public var Passcode_AppLockedAlert: String { return self._s[1820]! } + public var StickerPacksSettings_AnimatedStickersInfo: String { return self._s[1821]! } + public var VoiceOver_Media_PlaybackStop: String { return self._s[1822]! } + public var Contacts_TopSection: String { return self._s[1823]! } public func Conversation_SetReminder_RemindOn(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1823]!, self._r[1823]!, [_0, _1]) + return formatWithArgumentRanges(self._s[1824]!, self._r[1824]!, [_0, _1]) } - public var Wallet_Info_Receive: String { return self._s[1824]! } - public var Wallet_Completed_ViewWallet: String { return self._s[1825]! } + public var Wallet_Info_Receive: String { return self._s[1825]! } + public var Wallet_Completed_ViewWallet: String { return self._s[1826]! } public func Time_MonthOfYear_m6(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1826]!, self._r[1826]!, [_0]) + return formatWithArgumentRanges(self._s[1827]!, self._r[1827]!, [_0]) } - public var ReportPeer_ReasonSpam: String { return self._s[1827]! } - public var UserInfo_TapToCall: String { return self._s[1828]! } - public var Conversation_ForwardAuthorHiddenTooltip: String { return self._s[1830]! } - public var AutoDownloadSettings_DataUsageCustom: String { return self._s[1831]! } - public var Common_Search: String { return self._s[1832]! } - public var ScheduledMessages_EmptyPlaceholder: String { return self._s[1833]! } + public var ReportPeer_ReasonSpam: String { return self._s[1828]! } + public var UserInfo_TapToCall: String { return self._s[1829]! } + public var Conversation_ForwardAuthorHiddenTooltip: String { return self._s[1831]! } + public var AutoDownloadSettings_DataUsageCustom: String { return self._s[1832]! } + public var Common_Search: String { return self._s[1833]! } + public var ScheduledMessages_EmptyPlaceholder: String { return self._s[1834]! } public func Channel_AdminLog_MessageChangedGroupGeoLocation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1834]!, self._r[1834]!, [_0]) + return formatWithArgumentRanges(self._s[1835]!, self._r[1835]!, [_0]) } - public var AuthSessions_IncompleteAttemptsInfo: String { return self._s[1835]! } - public var Message_InvoiceLabel: String { return self._s[1836]! } - public var Conversation_InputTextPlaceholder: String { return self._s[1837]! } - public var NetworkUsageSettings_MediaImageDataSection: String { return self._s[1838]! } + public var AuthSessions_IncompleteAttemptsInfo: String { return self._s[1836]! } + public var Message_InvoiceLabel: String { return self._s[1837]! } + public var Conversation_InputTextPlaceholder: String { return self._s[1838]! } + public var NetworkUsageSettings_MediaImageDataSection: String { return self._s[1839]! } public func Passport_Address_UploadOneOfScan(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1839]!, self._r[1839]!, [_0]) + return formatWithArgumentRanges(self._s[1840]!, self._r[1840]!, [_0]) } - public var Conversation_Info: String { return self._s[1840]! } - public var Login_InfoDeletePhoto: String { return self._s[1841]! } - public var Passport_Language_vi: String { return self._s[1843]! } - public var UserInfo_ScamUserWarning: String { return self._s[1844]! } - public var Conversation_Search: String { return self._s[1845]! } - public var DialogList_DeleteBotConversationConfirmation: String { return self._s[1847]! } + public var Conversation_Info: String { return self._s[1841]! } + public var Login_InfoDeletePhoto: String { return self._s[1842]! } + public var Passport_Language_vi: String { return self._s[1844]! } + public var UserInfo_ScamUserWarning: String { return self._s[1845]! } + public var Conversation_Search: String { return self._s[1846]! } + public var DialogList_DeleteBotConversationConfirmation: String { return self._s[1848]! } public func Updated_AtDate(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1848]!, self._r[1848]!, [_0]) + return formatWithArgumentRanges(self._s[1849]!, self._r[1849]!, [_0]) } - public var ReportPeer_ReasonPornography: String { return self._s[1849]! } - public var AutoDownloadSettings_PhotosTitle: String { return self._s[1850]! } - public var Conversation_SendMessageErrorGroupRestricted: String { return self._s[1851]! } - public var Map_LiveLocationGroupDescription: String { return self._s[1852]! } - public var Channel_Setup_TypeHeader: String { return self._s[1853]! } - public var AuthSessions_LoggedIn: String { return self._s[1854]! } - public var Privacy_Forwards_AlwaysAllow_Title: String { return self._s[1855]! } - public var Login_SmsRequestState3: String { return self._s[1856]! } - public var Passport_Address_EditUtilityBill: String { return self._s[1857]! } - public var Appearance_ReduceMotionInfo: String { return self._s[1858]! } - public var Join_ChannelsTooMuch: String { return self._s[1859]! } - public var Channel_Edit_LinkItem: String { return self._s[1860]! } - public var Privacy_Calls_P2PNever: String { return self._s[1861]! } - public var Conversation_AddToReadingList: String { return self._s[1863]! } - public var Share_MultipleMessagesDisabled: String { return self._s[1864]! } - public var Message_Animation: String { return self._s[1865]! } - public var Conversation_DefaultRestrictedMedia: String { return self._s[1866]! } - public var Map_Unknown: String { return self._s[1867]! } - public var AutoDownloadSettings_LastDelimeter: String { return self._s[1868]! } + public var ReportPeer_ReasonPornography: String { return self._s[1850]! } + public var AutoDownloadSettings_PhotosTitle: String { return self._s[1851]! } + public var Conversation_SendMessageErrorGroupRestricted: String { return self._s[1852]! } + public var Map_LiveLocationGroupDescription: String { return self._s[1853]! } + public var Channel_Setup_TypeHeader: String { return self._s[1854]! } + public var AuthSessions_LoggedIn: String { return self._s[1855]! } + public var Privacy_Forwards_AlwaysAllow_Title: String { return self._s[1856]! } + public var Login_SmsRequestState3: String { return self._s[1857]! } + public var Passport_Address_EditUtilityBill: String { return self._s[1858]! } + public var Appearance_ReduceMotionInfo: String { return self._s[1859]! } + public var Join_ChannelsTooMuch: String { return self._s[1860]! } + public var Channel_Edit_LinkItem: String { return self._s[1861]! } + public var Privacy_Calls_P2PNever: String { return self._s[1862]! } + public var Conversation_AddToReadingList: String { return self._s[1864]! } + public var Share_MultipleMessagesDisabled: String { return self._s[1865]! } + public var Message_Animation: String { return self._s[1866]! } + public var Conversation_DefaultRestrictedMedia: String { return self._s[1867]! } + public var Map_Unknown: String { return self._s[1868]! } + public var AutoDownloadSettings_LastDelimeter: String { return self._s[1869]! } public func PUSH_PINNED_TEXT(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1869]!, self._r[1869]!, [_1, _2]) - } - public func Passport_FieldOneOf_Or(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[1870]!, self._r[1870]!, [_1, _2]) } - public var Call_StatusRequesting: String { return self._s[1871]! } - public var Conversation_SecretChatContextBotAlert: String { return self._s[1872]! } - public var SocksProxySetup_ProxyStatusChecking: String { return self._s[1873]! } + public func Passport_FieldOneOf_Or(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[1871]!, self._r[1871]!, [_1, _2]) + } + public var Call_StatusRequesting: String { return self._s[1872]! } + public var Conversation_SecretChatContextBotAlert: String { return self._s[1873]! } + public var SocksProxySetup_ProxyStatusChecking: String { return self._s[1874]! } public func PUSH_CHAT_MESSAGE_DOC(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1874]!, self._r[1874]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1875]!, self._r[1875]!, [_1, _2]) } public func Notification_PinnedLocationMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1875]!, self._r[1875]!, [_0]) + return formatWithArgumentRanges(self._s[1876]!, self._r[1876]!, [_0]) } - public var Update_Skip: String { return self._s[1876]! } - public var Group_Username_RemoveExistingUsernamesInfo: String { return self._s[1877]! } - public var Message_PinnedPollMessage: String { return self._s[1878]! } - public var BlockedUsers_Title: String { return self._s[1879]! } + public var Update_Skip: String { return self._s[1877]! } + public var Group_Username_RemoveExistingUsernamesInfo: String { return self._s[1878]! } + public var Message_PinnedPollMessage: String { return self._s[1879]! } + public var BlockedUsers_Title: String { return self._s[1880]! } public func PUSH_CHANNEL_MESSAGE_AUDIO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1880]!, self._r[1880]!, [_1]) + return formatWithArgumentRanges(self._s[1881]!, self._r[1881]!, [_1]) } - public var Username_CheckingUsername: String { return self._s[1881]! } - public var NotificationsSound_Bell: String { return self._s[1882]! } - public var Conversation_SendMessageErrorFlood: String { return self._s[1883]! } - public var Weekday_Monday: String { return self._s[1884]! } - public var SettingsSearch_Synonyms_Notifications_DisplayNamesOnLockScreen: String { return self._s[1885]! } - public var ChannelMembers_ChannelAdminsTitle: String { return self._s[1886]! } - public var ChatSettings_Groups: String { return self._s[1887]! } + public var Username_CheckingUsername: String { return self._s[1882]! } + public var NotificationsSound_Bell: String { return self._s[1883]! } + public var Conversation_SendMessageErrorFlood: String { return self._s[1884]! } + public var Weekday_Monday: String { return self._s[1885]! } + public var SettingsSearch_Synonyms_Notifications_DisplayNamesOnLockScreen: String { return self._s[1886]! } + public var ChannelMembers_ChannelAdminsTitle: String { return self._s[1887]! } + public var ChatSettings_Groups: String { return self._s[1888]! } public func Conversation_SetReminder_RemindTomorrow(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1888]!, self._r[1888]!, [_0]) + return formatWithArgumentRanges(self._s[1889]!, self._r[1889]!, [_0]) } - public var Your_card_was_declined: String { return self._s[1889]! } - public var TwoStepAuth_EnterPasswordHelp: String { return self._s[1891]! } - public var ChatList_Unmute: String { return self._s[1892]! } - public var PhotoEditor_CurvesAll: String { return self._s[1893]! } - public var Weekday_ShortTuesday: String { return self._s[1894]! } - public var DialogList_Read: String { return self._s[1895]! } - public var Appearance_AppIconClassic: String { return self._s[1896]! } - public var ChannelMembers_WhoCanAddMembers_AllMembers: String { return self._s[1897]! } - public var Passport_Identity_Gender: String { return self._s[1898]! } + public var Your_card_was_declined: String { return self._s[1890]! } + public var TwoStepAuth_EnterPasswordHelp: String { return self._s[1892]! } + public var ChatList_Unmute: String { return self._s[1893]! } + public var PhotoEditor_CurvesAll: String { return self._s[1894]! } + public var Weekday_ShortTuesday: String { return self._s[1895]! } + public var DialogList_Read: String { return self._s[1896]! } + public var Appearance_AppIconClassic: String { return self._s[1897]! } + public var ChannelMembers_WhoCanAddMembers_AllMembers: String { return self._s[1898]! } + public var Passport_Identity_Gender: String { return self._s[1899]! } public func Target_ShareGameConfirmationPrivate(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1899]!, self._r[1899]!, [_0]) + return formatWithArgumentRanges(self._s[1900]!, self._r[1900]!, [_0]) } - public var Target_SelectGroup: String { return self._s[1900]! } + public var Target_SelectGroup: String { return self._s[1901]! } public func DialogList_EncryptedChatStartedIncoming(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1902]!, self._r[1902]!, [_0]) + return formatWithArgumentRanges(self._s[1903]!, self._r[1903]!, [_0]) } - public var Passport_Language_en: String { return self._s[1903]! } - public var AutoDownloadSettings_AutodownloadPhotos: String { return self._s[1904]! } - public var Channel_Username_CreatePublicLinkHelp: String { return self._s[1905]! } - public var Login_CancelPhoneVerificationContinue: String { return self._s[1906]! } - public var ScheduledMessages_SendNow: String { return self._s[1907]! } - public var Checkout_NewCard_PaymentCard: String { return self._s[1909]! } - public var Login_InfoHelp: String { return self._s[1910]! } - public var Contacts_PermissionsSuppressWarningTitle: String { return self._s[1911]! } - public var SettingsSearch_Synonyms_Stickers_FeaturedPacks: String { return self._s[1912]! } + public var Passport_Language_en: String { return self._s[1904]! } + public var AutoDownloadSettings_AutodownloadPhotos: String { return self._s[1905]! } + public var Channel_Username_CreatePublicLinkHelp: String { return self._s[1906]! } + public var Login_CancelPhoneVerificationContinue: String { return self._s[1907]! } + public var ScheduledMessages_SendNow: String { return self._s[1908]! } + public var Checkout_NewCard_PaymentCard: String { return self._s[1910]! } + public var Login_InfoHelp: String { return self._s[1911]! } + public var Contacts_PermissionsSuppressWarningTitle: String { return self._s[1912]! } + public var SettingsSearch_Synonyms_Stickers_FeaturedPacks: String { return self._s[1913]! } public func Channel_AdminLog_MessageChangedLinkedChannel(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1913]!, self._r[1913]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1914]!, self._r[1914]!, [_1, _2]) } - public var SocksProxySetup_AddProxy: String { return self._s[1916]! } - public var CreatePoll_Title: String { return self._s[1917]! } - public var Conversation_ViewTheme: String { return self._s[1918]! } - public var SettingsSearch_Synonyms_Privacy_Data_SecretChatLinkPreview: String { return self._s[1919]! } - public var PasscodeSettings_SimplePasscodeHelp: String { return self._s[1920]! } - public var UserInfo_GroupsInCommon: String { return self._s[1921]! } - public var Call_AudioRouteHide: String { return self._s[1922]! } - public var ContactInfo_PhoneLabelMobile: String { return self._s[1924]! } + public var SocksProxySetup_AddProxy: String { return self._s[1917]! } + public var CreatePoll_Title: String { return self._s[1918]! } + public var Conversation_ViewTheme: String { return self._s[1919]! } + public var SettingsSearch_Synonyms_Privacy_Data_SecretChatLinkPreview: String { return self._s[1920]! } + public var PasscodeSettings_SimplePasscodeHelp: String { return self._s[1921]! } + public var UserInfo_GroupsInCommon: String { return self._s[1922]! } + public var Call_AudioRouteHide: String { return self._s[1923]! } + public var ContactInfo_PhoneLabelMobile: String { return self._s[1925]! } public func ChatList_LeaveGroupConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1925]!, self._r[1925]!, [_0]) + return formatWithArgumentRanges(self._s[1926]!, self._r[1926]!, [_0]) } - public var TextFormat_Bold: String { return self._s[1926]! } - public var FastTwoStepSetup_EmailSection: String { return self._s[1927]! } - public var Notifications_Title: String { return self._s[1928]! } - public var Group_Username_InvalidTooShort: String { return self._s[1929]! } - public var Channel_ErrorAddTooMuch: String { return self._s[1930]! } + public var TextFormat_Bold: String { return self._s[1927]! } + public var FastTwoStepSetup_EmailSection: String { return self._s[1928]! } + public var Notifications_Title: String { return self._s[1929]! } + public var Group_Username_InvalidTooShort: String { return self._s[1930]! } + public var Channel_ErrorAddTooMuch: String { return self._s[1931]! } public func DialogList_MultipleTypingSuffix(_ _0: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1931]!, self._r[1931]!, ["\(_0)"]) + return formatWithArgumentRanges(self._s[1932]!, self._r[1932]!, ["\(_0)"]) } - public var VoiceOver_DiscardPreparedContent: String { return self._s[1933]! } - public var Stickers_SuggestAdded: String { return self._s[1934]! } - public var Login_CountryCode: String { return self._s[1935]! } - public var ChatSettings_AutoPlayVideos: String { return self._s[1936]! } - public var Map_GetDirections: String { return self._s[1937]! } - public var Wallet_Receive_ShareInvoiceUrl: String { return self._s[1938]! } - public var Login_PhoneFloodError: String { return self._s[1939]! } + public var VoiceOver_DiscardPreparedContent: String { return self._s[1934]! } + public var Stickers_SuggestAdded: String { return self._s[1935]! } + public var Login_CountryCode: String { return self._s[1936]! } + public var ChatSettings_AutoPlayVideos: String { return self._s[1937]! } + public var Map_GetDirections: String { return self._s[1938]! } + public var Wallet_Receive_ShareInvoiceUrl: String { return self._s[1939]! } + public var Login_PhoneFloodError: String { return self._s[1940]! } public func Time_MonthOfYear_m3(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1940]!, self._r[1940]!, [_0]) + return formatWithArgumentRanges(self._s[1941]!, self._r[1941]!, [_0]) } - public var Settings_SetUsername: String { return self._s[1942]! } - public var Group_Location_ChangeLocation: String { return self._s[1943]! } - public var Notification_GroupInviterSelf: String { return self._s[1944]! } - public var InstantPage_TapToOpenLink: String { return self._s[1945]! } + public var Settings_SetUsername: String { return self._s[1943]! } + public var Group_Location_ChangeLocation: String { return self._s[1944]! } + public var Notification_GroupInviterSelf: String { return self._s[1945]! } + public var InstantPage_TapToOpenLink: String { return self._s[1946]! } public func Notification_ChannelInviter(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1946]!, self._r[1946]!, [_0]) + return formatWithArgumentRanges(self._s[1947]!, self._r[1947]!, [_0]) } - public var Watch_Suggestion_TalkLater: String { return self._s[1947]! } - public var SecretChat_Title: String { return self._s[1948]! } - public var Group_UpgradeNoticeText1: String { return self._s[1949]! } - public var AuthSessions_Title: String { return self._s[1950]! } + public var Watch_Suggestion_TalkLater: String { return self._s[1948]! } + public var SecretChat_Title: String { return self._s[1949]! } + public var Group_UpgradeNoticeText1: String { return self._s[1950]! } + public var AuthSessions_Title: String { return self._s[1951]! } public func TextFormat_AddLinkText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1951]!, self._r[1951]!, [_0]) + return formatWithArgumentRanges(self._s[1952]!, self._r[1952]!, [_0]) } - public var PhotoEditor_CropAuto: String { return self._s[1952]! } - public var Channel_About_Title: String { return self._s[1953]! } - public var FastTwoStepSetup_EmailHelp: String { return self._s[1954]! } + public var PhotoEditor_CropAuto: String { return self._s[1953]! } + public var Channel_About_Title: String { return self._s[1954]! } + public var FastTwoStepSetup_EmailHelp: String { return self._s[1955]! } public func Conversation_Bytes(_ _0: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1956]!, self._r[1956]!, ["\(_0)"]) + return formatWithArgumentRanges(self._s[1957]!, self._r[1957]!, ["\(_0)"]) } - public var VoiceOver_MessageContextReport: String { return self._s[1957]! } - public var Conversation_PinMessageAlert_OnlyPin: String { return self._s[1959]! } - public var Group_Setup_HistoryVisibleHelp: String { return self._s[1960]! } + public var VoiceOver_MessageContextReport: String { return self._s[1958]! } + public var Conversation_PinMessageAlert_OnlyPin: String { return self._s[1960]! } + public var Group_Setup_HistoryVisibleHelp: String { return self._s[1961]! } public func PUSH_MESSAGE_GIF(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1961]!, self._r[1961]!, [_1]) + return formatWithArgumentRanges(self._s[1962]!, self._r[1962]!, [_1]) } public func SharedMedia_SearchNoResultsDescription(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1963]!, self._r[1963]!, [_0]) - } - public func TwoStepAuth_RecoveryEmailUnavailable(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[1964]!, self._r[1964]!, [_0]) } - public var Privacy_PaymentsClearInfoHelp: String { return self._s[1965]! } - public var Presence_online: String { return self._s[1967]! } - public var PasscodeSettings_Title: String { return self._s[1968]! } - public var Passport_Identity_ExpiryDatePlaceholder: String { return self._s[1969]! } - public var Web_OpenExternal: String { return self._s[1970]! } - public var AutoDownloadSettings_AutoDownload: String { return self._s[1972]! } - public var Channel_OwnershipTransfer_EnterPasswordText: String { return self._s[1973]! } - public var LocalGroup_Title: String { return self._s[1974]! } + public func TwoStepAuth_RecoveryEmailUnavailable(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[1965]!, self._r[1965]!, [_0]) + } + public var Privacy_PaymentsClearInfoHelp: String { return self._s[1966]! } + public var Presence_online: String { return self._s[1968]! } + public var PasscodeSettings_Title: String { return self._s[1969]! } + public var Passport_Identity_ExpiryDatePlaceholder: String { return self._s[1970]! } + public var Web_OpenExternal: String { return self._s[1971]! } + public var AutoDownloadSettings_AutoDownload: String { return self._s[1973]! } + public var Channel_OwnershipTransfer_EnterPasswordText: String { return self._s[1974]! } + public var LocalGroup_Title: String { return self._s[1975]! } public func AutoNightTheme_AutomaticHelp(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1975]!, self._r[1975]!, [_0]) + return formatWithArgumentRanges(self._s[1976]!, self._r[1976]!, [_0]) } - public var FastTwoStepSetup_PasswordConfirmationPlaceholder: String { return self._s[1976]! } - public var Map_YouAreHere: String { return self._s[1977]! } + public var FastTwoStepSetup_PasswordConfirmationPlaceholder: String { return self._s[1977]! } + public var Map_YouAreHere: String { return self._s[1978]! } public func AuthSessions_Message(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1978]!, self._r[1978]!, [_0]) - } - public func ChatList_DeleteChatConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[1979]!, self._r[1979]!, [_0]) } - public var PrivacyLastSeenSettings_AlwaysShareWith: String { return self._s[1980]! } - public var Target_InviteToGroupErrorAlreadyInvited: String { return self._s[1981]! } - public func AuthSessions_AppUnofficial(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1982]!, self._r[1982]!, [_0]) + public func ChatList_DeleteChatConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[1980]!, self._r[1980]!, [_0]) } - public func DialogList_LiveLocationSharingTo(_ _0: String) -> (String, [(Int, NSRange)]) { + public var PrivacyLastSeenSettings_AlwaysShareWith: String { return self._s[1981]! } + public var Target_InviteToGroupErrorAlreadyInvited: String { return self._s[1982]! } + public func AuthSessions_AppUnofficial(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[1983]!, self._r[1983]!, [_0]) } - public var SocksProxySetup_Username: String { return self._s[1984]! } - public var Bot_Start: String { return self._s[1985]! } - public func Channel_AdminLog_EmptyFilterQueryText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1986]!, self._r[1986]!, [_0]) + public func DialogList_LiveLocationSharingTo(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[1984]!, self._r[1984]!, [_0]) } - public func Channel_AdminLog_MessagePinned(_ _0: String) -> (String, [(Int, NSRange)]) { + public var SocksProxySetup_Username: String { return self._s[1985]! } + public var Bot_Start: String { return self._s[1986]! } + public func Channel_AdminLog_EmptyFilterQueryText(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[1987]!, self._r[1987]!, [_0]) } - public var Contacts_SortByPresence: String { return self._s[1988]! } - public var AccentColor_Title: String { return self._s[1990]! } - public var Conversation_DiscardVoiceMessageTitle: String { return self._s[1991]! } + public func Channel_AdminLog_MessagePinned(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[1988]!, self._r[1988]!, [_0]) + } + public var Contacts_SortByPresence: String { return self._s[1989]! } + public var AccentColor_Title: String { return self._s[1991]! } + public var Conversation_DiscardVoiceMessageTitle: String { return self._s[1992]! } public func PUSH_CHAT_CREATED(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1992]!, self._r[1992]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1993]!, self._r[1993]!, [_1, _2]) } public func PrivacySettings_LastSeenContactsMinus(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1993]!, self._r[1993]!, [_0]) + return formatWithArgumentRanges(self._s[1994]!, self._r[1994]!, [_0]) } public func Channel_AdminLog_MessageChangedLinkedGroup(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1994]!, self._r[1994]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1995]!, self._r[1995]!, [_1, _2]) } - public var Passport_Email_EnterOtherEmail: String { return self._s[1995]! } - public var Login_InfoAvatarPhoto: String { return self._s[1996]! } - public var Privacy_PaymentsClear_ShippingInfo: String { return self._s[1997]! } - public var Tour_Title4: String { return self._s[1998]! } - public var Passport_Identity_Translation: String { return self._s[1999]! } - public var SettingsSearch_Synonyms_Notifications_ContactJoined: String { return self._s[2000]! } - public var Login_TermsOfServiceLabel: String { return self._s[2002]! } - public var Passport_Language_it: String { return self._s[2003]! } - public var KeyCommand_JumpToNextUnreadChat: String { return self._s[2004]! } - public var Passport_Identity_SelfieHelp: String { return self._s[2005]! } - public var Conversation_ClearAll: String { return self._s[2007]! } - public var Channel_OwnershipTransfer_Title: String { return self._s[2009]! } - public var TwoStepAuth_FloodError: String { return self._s[2010]! } + public var Passport_Email_EnterOtherEmail: String { return self._s[1996]! } + public var Login_InfoAvatarPhoto: String { return self._s[1997]! } + public var Privacy_PaymentsClear_ShippingInfo: String { return self._s[1998]! } + public var Tour_Title4: String { return self._s[1999]! } + public var Passport_Identity_Translation: String { return self._s[2000]! } + public var SettingsSearch_Synonyms_Notifications_ContactJoined: String { return self._s[2001]! } + public var Login_TermsOfServiceLabel: String { return self._s[2003]! } + public var Passport_Language_it: String { return self._s[2004]! } + public var KeyCommand_JumpToNextUnreadChat: String { return self._s[2005]! } + public var Passport_Identity_SelfieHelp: String { return self._s[2006]! } + public var Conversation_ClearAll: String { return self._s[2008]! } + public var Wallet_Send_UninitializedText: String { return self._s[2010]! } + public var Channel_OwnershipTransfer_Title: String { return self._s[2011]! } + public var TwoStepAuth_FloodError: String { return self._s[2012]! } public func PUSH_CHANNEL_MESSAGE_GEO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2011]!, self._r[2011]!, [_1]) + return formatWithArgumentRanges(self._s[2013]!, self._r[2013]!, [_1]) } - public var Paint_Delete: String { return self._s[2012]! } + public var Paint_Delete: String { return self._s[2014]! } public func Wallet_Sent_Text(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2013]!, self._r[2013]!, [_0]) + return formatWithArgumentRanges(self._s[2015]!, self._r[2015]!, [_0]) } - public var Privacy_AddNewPeer: String { return self._s[2014]! } + public var Privacy_AddNewPeer: String { return self._s[2016]! } public func Channel_AdminLog_MessageRank(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2015]!, self._r[2015]!, [_1]) + return formatWithArgumentRanges(self._s[2017]!, self._r[2017]!, [_1]) } - public var LogoutOptions_SetPasscodeText: String { return self._s[2016]! } + public var LogoutOptions_SetPasscodeText: String { return self._s[2018]! } public func Passport_AcceptHelp(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2017]!, self._r[2017]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2019]!, self._r[2019]!, [_1, _2]) } - public var Message_PinnedAudioMessage: String { return self._s[2018]! } + public var Message_PinnedAudioMessage: String { return self._s[2020]! } public func Watch_Time_ShortTodayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2019]!, self._r[2019]!, [_0]) + return formatWithArgumentRanges(self._s[2021]!, self._r[2021]!, [_0]) } - public var Notification_Mute1hMin: String { return self._s[2020]! } - public var Notifications_GroupNotificationsSound: String { return self._s[2021]! } - public var SocksProxySetup_ShareProxyList: String { return self._s[2022]! } - public var Conversation_MessageEditedLabel: String { return self._s[2023]! } - public var Notification_Exceptions_AlwaysOff: String { return self._s[2024]! } - public var Notification_Exceptions_NewException_MessagePreviewHeader: String { return self._s[2025]! } + public var Notification_Mute1hMin: String { return self._s[2022]! } + public var Notifications_GroupNotificationsSound: String { return self._s[2023]! } + public var SocksProxySetup_ShareProxyList: String { return self._s[2024]! } + public var Conversation_MessageEditedLabel: String { return self._s[2025]! } + public var Notification_Exceptions_AlwaysOff: String { return self._s[2026]! } + public var Notification_Exceptions_NewException_MessagePreviewHeader: String { return self._s[2027]! } public func Channel_AdminLog_MessageAdmin(_ _0: String, _ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2026]!, self._r[2026]!, [_0, _1, _2]) + return formatWithArgumentRanges(self._s[2028]!, self._r[2028]!, [_0, _1, _2]) } - public var NetworkUsageSettings_ResetStats: String { return self._s[2027]! } + public var NetworkUsageSettings_ResetStats: String { return self._s[2029]! } public func PUSH_MESSAGE_GEOLIVE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2028]!, self._r[2028]!, [_1]) + return formatWithArgumentRanges(self._s[2030]!, self._r[2030]!, [_1]) } - public var AccessDenied_LocationTracking: String { return self._s[2029]! } - public var Month_GenOctober: String { return self._s[2030]! } - public var GroupInfo_InviteLink_RevokeAlert_Revoke: String { return self._s[2031]! } - public var EnterPasscode_EnterPasscode: String { return self._s[2032]! } - public var MediaPicker_TimerTooltip: String { return self._s[2034]! } - public var SharedMedia_TitleAll: String { return self._s[2035]! } - public var SettingsSearch_Synonyms_Notifications_ChannelNotificationsExceptions: String { return self._s[2038]! } - public var Conversation_RestrictedMedia: String { return self._s[2039]! } - public var AccessDenied_PhotosRestricted: String { return self._s[2040]! } - public var Privacy_Forwards_WhoCanForward: String { return self._s[2042]! } - public var ChangePhoneNumberCode_Called: String { return self._s[2043]! } + public var AccessDenied_LocationTracking: String { return self._s[2031]! } + public var Month_GenOctober: String { return self._s[2032]! } + public var GroupInfo_InviteLink_RevokeAlert_Revoke: String { return self._s[2033]! } + public var EnterPasscode_EnterPasscode: String { return self._s[2034]! } + public var MediaPicker_TimerTooltip: String { return self._s[2036]! } + public var SharedMedia_TitleAll: String { return self._s[2037]! } + public var SettingsSearch_Synonyms_Notifications_ChannelNotificationsExceptions: String { return self._s[2040]! } + public var Conversation_RestrictedMedia: String { return self._s[2041]! } + public var AccessDenied_PhotosRestricted: String { return self._s[2042]! } + public var Privacy_Forwards_WhoCanForward: String { return self._s[2044]! } + public var ChangePhoneNumberCode_Called: String { return self._s[2045]! } public func Notification_PinnedDocumentMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2044]!, self._r[2044]!, [_0]) + return formatWithArgumentRanges(self._s[2046]!, self._r[2046]!, [_0]) } - public var Conversation_SavedMessages: String { return self._s[2047]! } - public var Your_cards_expiration_month_is_invalid: String { return self._s[2049]! } - public var FastTwoStepSetup_PasswordPlaceholder: String { return self._s[2050]! } + public var Conversation_SavedMessages: String { return self._s[2049]! } + public var Your_cards_expiration_month_is_invalid: String { return self._s[2051]! } + public var FastTwoStepSetup_PasswordPlaceholder: String { return self._s[2052]! } public func Target_ShareGameConfirmationGroup(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2052]!, self._r[2052]!, [_0]) - } - public var VoiceOver_Chat_YourMessage: String { return self._s[2053]! } - public func VoiceOver_Chat_Title(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[2054]!, self._r[2054]!, [_0]) } - public var ReportPeer_AlertSuccess: String { return self._s[2055]! } - public var PhotoEditor_CropAspectRatioOriginal: String { return self._s[2056]! } + public var VoiceOver_Chat_YourMessage: String { return self._s[2055]! } + public func VoiceOver_Chat_Title(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[2056]!, self._r[2056]!, [_0]) + } + public var ReportPeer_AlertSuccess: String { return self._s[2057]! } + public var PhotoEditor_CropAspectRatioOriginal: String { return self._s[2058]! } public func InstantPage_RelatedArticleAuthorAndDateTitle(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2057]!, self._r[2057]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2059]!, self._r[2059]!, [_1, _2]) } - public var Checkout_PasswordEntry_Title: String { return self._s[2058]! } - public var PhotoEditor_FadeTool: String { return self._s[2059]! } - public var Privacy_ContactsReset: String { return self._s[2060]! } + public var Checkout_PasswordEntry_Title: String { return self._s[2060]! } + public var PhotoEditor_FadeTool: String { return self._s[2061]! } + public var Privacy_ContactsReset: String { return self._s[2062]! } public func Channel_AdminLog_MessageRestrictedUntil(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2062]!, self._r[2062]!, [_0]) + return formatWithArgumentRanges(self._s[2064]!, self._r[2064]!, [_0]) } - public var Message_PinnedVideoMessage: String { return self._s[2063]! } - public var ChatList_Mute: String { return self._s[2064]! } - public var Permissions_CellularDataText_v0: String { return self._s[2065]! } - public var ShareMenu_SelectChats: String { return self._s[2068]! } - public var ChatList_Context_Unarchive: String { return self._s[2069]! } - public var MusicPlayer_VoiceNote: String { return self._s[2070]! } - public var Conversation_RestrictedText: String { return self._s[2071]! } - public var SettingsSearch_Synonyms_Privacy_Data_DeleteDrafts: String { return self._s[2072]! } - public var TwoStepAuth_DisableSuccess: String { return self._s[2073]! } - public var Cache_Videos: String { return self._s[2074]! } - public var PrivacySettings_PhoneNumber: String { return self._s[2075]! } - public var FeatureDisabled_Oops: String { return self._s[2077]! } - public var Passport_Address_PostcodePlaceholder: String { return self._s[2078]! } + public var Message_PinnedVideoMessage: String { return self._s[2065]! } + public var ChatList_Mute: String { return self._s[2066]! } + public var Permissions_CellularDataText_v0: String { return self._s[2067]! } + public var ShareMenu_SelectChats: String { return self._s[2070]! } + public var ChatList_Context_Unarchive: String { return self._s[2071]! } + public var MusicPlayer_VoiceNote: String { return self._s[2072]! } + public var Conversation_RestrictedText: String { return self._s[2073]! } + public var SettingsSearch_Synonyms_Privacy_Data_DeleteDrafts: String { return self._s[2074]! } + public var TwoStepAuth_DisableSuccess: String { return self._s[2075]! } + public var Cache_Videos: String { return self._s[2076]! } + public var PrivacySettings_PhoneNumber: String { return self._s[2077]! } + public var FeatureDisabled_Oops: String { return self._s[2079]! } + public var Passport_Address_PostcodePlaceholder: String { return self._s[2080]! } public func AddContact_StatusSuccess(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2079]!, self._r[2079]!, [_0]) + return formatWithArgumentRanges(self._s[2081]!, self._r[2081]!, [_0]) } - public var Stickers_GroupStickersHelp: String { return self._s[2080]! } - public var GroupPermission_NoSendPolls: String { return self._s[2081]! } - public var Wallet_Qr_ScanCode: String { return self._s[2082]! } - public var Message_VideoExpired: String { return self._s[2084]! } - public var Notifications_Badge: String { return self._s[2085]! } - public var GroupInfo_GroupHistoryVisible: String { return self._s[2086]! } - public var Wallet_Receive_AddressCopied: String { return self._s[2087]! } - public var CreatePoll_OptionPlaceholder: String { return self._s[2088]! } - public var Username_InvalidTooShort: String { return self._s[2089]! } - public var EnterPasscode_EnterNewPasscodeChange: String { return self._s[2090]! } - public var Channel_AdminLog_PinMessages: String { return self._s[2091]! } - public var ArchivedChats_IntroTitle3: String { return self._s[2092]! } + public var Stickers_GroupStickersHelp: String { return self._s[2082]! } + public var GroupPermission_NoSendPolls: String { return self._s[2083]! } + public var Wallet_Qr_ScanCode: String { return self._s[2084]! } + public var Message_VideoExpired: String { return self._s[2086]! } + public var Notifications_Badge: String { return self._s[2087]! } + public var GroupInfo_GroupHistoryVisible: String { return self._s[2088]! } + public var Wallet_Receive_AddressCopied: String { return self._s[2089]! } + public var CreatePoll_OptionPlaceholder: String { return self._s[2090]! } + public var Username_InvalidTooShort: String { return self._s[2091]! } + public var EnterPasscode_EnterNewPasscodeChange: String { return self._s[2092]! } + public var Channel_AdminLog_PinMessages: String { return self._s[2093]! } + public var ArchivedChats_IntroTitle3: String { return self._s[2094]! } public func Notification_MessageLifetimeRemoved(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2093]!, self._r[2093]!, [_1]) + return formatWithArgumentRanges(self._s[2095]!, self._r[2095]!, [_1]) } - public var Permissions_SiriAllowInSettings_v0: String { return self._s[2094]! } - public var Conversation_DefaultRestrictedText: String { return self._s[2095]! } - public var SharedMedia_CategoryDocs: String { return self._s[2098]! } + public var Permissions_SiriAllowInSettings_v0: String { return self._s[2096]! } + public var Conversation_DefaultRestrictedText: String { return self._s[2097]! } + public var SharedMedia_CategoryDocs: String { return self._s[2100]! } public func PUSH_MESSAGE_CONTACT(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2099]!, self._r[2099]!, [_1]) + return formatWithArgumentRanges(self._s[2101]!, self._r[2101]!, [_1]) } - public var Privacy_Forwards_NeverLink: String { return self._s[2101]! } + public var Wallet_Send_UninitializedTitle: String { return self._s[2102]! } + public var Privacy_Forwards_NeverLink: String { return self._s[2104]! } public func Notification_MessageLifetimeChangedOutgoing(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2102]!, self._r[2102]!, [_1]) + return formatWithArgumentRanges(self._s[2105]!, self._r[2105]!, [_1]) } - public var CheckoutInfo_ErrorShippingNotAvailable: String { return self._s[2103]! } + public var CheckoutInfo_ErrorShippingNotAvailable: String { return self._s[2106]! } public func Time_MonthOfYear_m12(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2104]!, self._r[2104]!, [_0]) + return formatWithArgumentRanges(self._s[2107]!, self._r[2107]!, [_0]) } - public var ChatSettings_PrivateChats: String { return self._s[2105]! } - public var SettingsSearch_Synonyms_EditProfile_Logout: String { return self._s[2106]! } - public var Conversation_PrivateMessageLinkCopied: String { return self._s[2107]! } - public var Channel_UpdatePhotoItem: String { return self._s[2108]! } - public var GroupInfo_LeftStatus: String { return self._s[2109]! } - public var Watch_MessageView_Forward: String { return self._s[2111]! } - public var ReportPeer_ReasonChildAbuse: String { return self._s[2112]! } - public var Cache_ClearEmpty: String { return self._s[2114]! } - public var Localization_LanguageName: String { return self._s[2115]! } - public var WebSearch_GIFs: String { return self._s[2116]! } - public var Notifications_DisplayNamesOnLockScreenInfoWithLink: String { return self._s[2117]! } - public var Username_InvalidStartsWithNumber: String { return self._s[2118]! } - public var Common_Back: String { return self._s[2119]! } - public var Passport_Identity_DateOfBirthPlaceholder: String { return self._s[2120]! } - public var Wallet_Send_Send: String { return self._s[2121]! } + public var ChatSettings_PrivateChats: String { return self._s[2108]! } + public var SettingsSearch_Synonyms_EditProfile_Logout: String { return self._s[2109]! } + public var Conversation_PrivateMessageLinkCopied: String { return self._s[2110]! } + public var Channel_UpdatePhotoItem: String { return self._s[2111]! } + public var GroupInfo_LeftStatus: String { return self._s[2112]! } + public var Watch_MessageView_Forward: String { return self._s[2114]! } + public var ReportPeer_ReasonChildAbuse: String { return self._s[2115]! } + public var Cache_ClearEmpty: String { return self._s[2117]! } + public var Localization_LanguageName: String { return self._s[2118]! } + public var WebSearch_GIFs: String { return self._s[2119]! } + public var Notifications_DisplayNamesOnLockScreenInfoWithLink: String { return self._s[2120]! } + public var Username_InvalidStartsWithNumber: String { return self._s[2121]! } + public var Common_Back: String { return self._s[2122]! } + public var Passport_Identity_DateOfBirthPlaceholder: String { return self._s[2123]! } + public var Wallet_Send_Send: String { return self._s[2124]! } public func PUSH_CHANNEL_MESSAGE_STICKER(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2122]!, self._r[2122]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2125]!, self._r[2125]!, [_1, _2]) } - public var Wallet_Info_RefreshErrorTitle: String { return self._s[2123]! } - public var Passport_Email_Help: String { return self._s[2124]! } - public var Watch_Conversation_Reply: String { return self._s[2126]! } - public var Conversation_EditingMessageMediaChange: String { return self._s[2128]! } - public var Passport_Identity_IssueDatePlaceholder: String { return self._s[2129]! } - public var Channel_BanUser_Unban: String { return self._s[2131]! } - public var Channel_EditAdmin_PermissionPostMessages: String { return self._s[2132]! } - public var Group_Username_CreatePublicLinkHelp: String { return self._s[2133]! } - public var TwoStepAuth_ConfirmEmailCodePlaceholder: String { return self._s[2135]! } - public var Wallet_Send_AddressHeader: String { return self._s[2136]! } - public var Passport_Identity_Name: String { return self._s[2137]! } + public var Wallet_Info_RefreshErrorTitle: String { return self._s[2126]! } + public var Passport_Email_Help: String { return self._s[2127]! } + public var Watch_Conversation_Reply: String { return self._s[2129]! } + public var Conversation_EditingMessageMediaChange: String { return self._s[2131]! } + public var Passport_Identity_IssueDatePlaceholder: String { return self._s[2132]! } + public var Channel_BanUser_Unban: String { return self._s[2134]! } + public var Channel_EditAdmin_PermissionPostMessages: String { return self._s[2135]! } + public var Group_Username_CreatePublicLinkHelp: String { return self._s[2136]! } + public var TwoStepAuth_ConfirmEmailCodePlaceholder: String { return self._s[2138]! } + public var Wallet_Send_AddressHeader: String { return self._s[2139]! } + public var Passport_Identity_Name: String { return self._s[2140]! } public func Channel_DiscussionGroup_HeaderGroupSet(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2138]!, self._r[2138]!, [_0]) + return formatWithArgumentRanges(self._s[2141]!, self._r[2141]!, [_0]) } - public var GroupRemoved_ViewUserInfo: String { return self._s[2139]! } - public var Conversation_BlockUser: String { return self._s[2140]! } - public var Month_GenJanuary: String { return self._s[2141]! } - public var ChatSettings_TextSize: String { return self._s[2142]! } - public var Notification_PassportValuePhone: String { return self._s[2143]! } - public var Passport_Language_ne: String { return self._s[2144]! } - public var Notification_CallBack: String { return self._s[2145]! } - public var Wallet_SecureStorageReset_BiometryTouchId: String { return self._s[2146]! } - public var TwoStepAuth_EmailHelp: String { return self._s[2147]! } + public var GroupRemoved_ViewUserInfo: String { return self._s[2142]! } + public var Conversation_BlockUser: String { return self._s[2143]! } + public var Month_GenJanuary: String { return self._s[2144]! } + public var ChatSettings_TextSize: String { return self._s[2145]! } + public var Notification_PassportValuePhone: String { return self._s[2146]! } + public var Passport_Language_ne: String { return self._s[2147]! } + public var Notification_CallBack: String { return self._s[2148]! } + public var Wallet_SecureStorageReset_BiometryTouchId: String { return self._s[2149]! } + public var TwoStepAuth_EmailHelp: String { return self._s[2150]! } public func Time_YesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2148]!, self._r[2148]!, [_0]) + return formatWithArgumentRanges(self._s[2151]!, self._r[2151]!, [_0]) } - public var Channel_Info_Management: String { return self._s[2149]! } - public var Passport_FieldIdentityUploadHelp: String { return self._s[2150]! } - public var Stickers_FrequentlyUsed: String { return self._s[2151]! } - public var Channel_BanUser_PermissionSendMessages: String { return self._s[2152]! } - public var Passport_Address_OneOfTypeUtilityBill: String { return self._s[2154]! } + public var Channel_Info_Management: String { return self._s[2152]! } + public var Passport_FieldIdentityUploadHelp: String { return self._s[2153]! } + public var Stickers_FrequentlyUsed: String { return self._s[2154]! } + public var Channel_BanUser_PermissionSendMessages: String { return self._s[2155]! } + public var Passport_Address_OneOfTypeUtilityBill: String { return self._s[2157]! } public func LOCAL_CHANNEL_MESSAGE_FWDS(_ _1: String, _ _2: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2155]!, self._r[2155]!, [_1, "\(_2)"]) + return formatWithArgumentRanges(self._s[2158]!, self._r[2158]!, [_1, "\(_2)"]) } - public var Passport_Address_EditResidentialAddress: String { return self._s[2156]! } - public var PrivacyPolicy_DeclineTitle: String { return self._s[2157]! } - public var CreatePoll_TextHeader: String { return self._s[2158]! } + public var Passport_Address_EditResidentialAddress: String { return self._s[2159]! } + public var PrivacyPolicy_DeclineTitle: String { return self._s[2160]! } + public var CreatePoll_TextHeader: String { return self._s[2161]! } public func Checkout_SavePasswordTimeoutAndTouchId(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2159]!, self._r[2159]!, [_0]) + return formatWithArgumentRanges(self._s[2162]!, self._r[2162]!, [_0]) } - public var PhotoEditor_QualityMedium: String { return self._s[2160]! } - public var InfoPlist_NSMicrophoneUsageDescription: String { return self._s[2161]! } - public var Conversation_StatusKickedFromChannel: String { return self._s[2163]! } - public var CheckoutInfo_ReceiverInfoName: String { return self._s[2164]! } - public var Group_ErrorSendRestrictedStickers: String { return self._s[2165]! } + public var PhotoEditor_QualityMedium: String { return self._s[2163]! } + public var InfoPlist_NSMicrophoneUsageDescription: String { return self._s[2164]! } + public var Conversation_StatusKickedFromChannel: String { return self._s[2166]! } + public var CheckoutInfo_ReceiverInfoName: String { return self._s[2167]! } + public var Group_ErrorSendRestrictedStickers: String { return self._s[2168]! } public func Conversation_RestrictedInlineTimed(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2166]!, self._r[2166]!, [_0]) + return formatWithArgumentRanges(self._s[2169]!, self._r[2169]!, [_0]) } public func Channel_AdminLog_MessageTransferedName(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2167]!, self._r[2167]!, [_1]) + return formatWithArgumentRanges(self._s[2170]!, self._r[2170]!, [_1]) } - public var Conversation_LinkDialogOpen: String { return self._s[2169]! } - public var VoiceOver_Chat_PollNoVotes: String { return self._s[2170]! } - public var Settings_Username: String { return self._s[2172]! } - public var Conversation_Block: String { return self._s[2174]! } - public var Wallpaper_Wallpaper: String { return self._s[2175]! } - public var SocksProxySetup_UseProxy: String { return self._s[2177]! } - public var Wallet_Send_Confirmation: String { return self._s[2178]! } - public var EditTheme_UploadEditedTheme: String { return self._s[2179]! } - public var UserInfo_ShareMyContactInfo: String { return self._s[2180]! } - public var MessageTimer_Forever: String { return self._s[2181]! } - public var Privacy_Calls_WhoCanCallMe: String { return self._s[2182]! } - public var PhotoEditor_DiscardChanges: String { return self._s[2183]! } - public var AuthSessions_TerminateOtherSessionsHelp: String { return self._s[2184]! } - public var Passport_Language_da: String { return self._s[2185]! } - public var SocksProxySetup_PortPlaceholder: String { return self._s[2186]! } + public var Conversation_LinkDialogOpen: String { return self._s[2172]! } + public var VoiceOver_Chat_PollNoVotes: String { return self._s[2173]! } + public var Settings_Username: String { return self._s[2175]! } + public var Conversation_Block: String { return self._s[2177]! } + public var Wallpaper_Wallpaper: String { return self._s[2178]! } + public var SocksProxySetup_UseProxy: String { return self._s[2180]! } + public var Wallet_Send_Confirmation: String { return self._s[2181]! } + public var EditTheme_UploadEditedTheme: String { return self._s[2182]! } + public var UserInfo_ShareMyContactInfo: String { return self._s[2183]! } + public var MessageTimer_Forever: String { return self._s[2184]! } + public var Privacy_Calls_WhoCanCallMe: String { return self._s[2185]! } + public var PhotoEditor_DiscardChanges: String { return self._s[2186]! } + public var AuthSessions_TerminateOtherSessionsHelp: String { return self._s[2187]! } + public var Passport_Language_da: String { return self._s[2188]! } + public var SocksProxySetup_PortPlaceholder: String { return self._s[2189]! } public func SecretGIF_NotViewedYet(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2187]!, self._r[2187]!, [_0]) - } - public var Passport_Address_EditPassportRegistration: String { return self._s[2188]! } - public func Channel_AdminLog_MessageChangedGroupAbout(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[2190]!, self._r[2190]!, [_0]) } - public var Passport_Identity_ResidenceCountryPlaceholder: String { return self._s[2192]! } - public var Conversation_SearchByName_Prefix: String { return self._s[2193]! } - public var Conversation_PinnedPoll: String { return self._s[2194]! } - public var Conversation_EmptyGifPanelPlaceholder: String { return self._s[2195]! } + public var Passport_Address_EditPassportRegistration: String { return self._s[2191]! } + public func Channel_AdminLog_MessageChangedGroupAbout(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[2193]!, self._r[2193]!, [_0]) + } + public var Passport_Identity_ResidenceCountryPlaceholder: String { return self._s[2195]! } + public var Conversation_SearchByName_Prefix: String { return self._s[2196]! } + public var Conversation_PinnedPoll: String { return self._s[2197]! } + public var Conversation_EmptyGifPanelPlaceholder: String { return self._s[2198]! } public func PUSH_ENCRYPTION_ACCEPT(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2196]!, self._r[2196]!, [_1]) + return formatWithArgumentRanges(self._s[2199]!, self._r[2199]!, [_1]) } - public var WallpaperSearch_ColorPurple: String { return self._s[2197]! } - public var Cache_ByPeerHeader: String { return self._s[2198]! } + public var WallpaperSearch_ColorPurple: String { return self._s[2200]! } + public var Cache_ByPeerHeader: String { return self._s[2201]! } public func Conversation_EncryptedPlaceholderTitleIncoming(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2199]!, self._r[2199]!, [_0]) + return formatWithArgumentRanges(self._s[2202]!, self._r[2202]!, [_0]) } - public var ChatSettings_AutoDownloadDocuments: String { return self._s[2200]! } - public var Appearance_ThemePreview_Chat_3_Text: String { return self._s[2203]! } - public var Wallet_Completed_Title: String { return self._s[2204]! } - public var Notification_PinnedMessage: String { return self._s[2205]! } - public var VoiceOver_Chat_RecordModeVideoMessage: String { return self._s[2207]! } - public var Contacts_SortBy: String { return self._s[2208]! } + public var ChatSettings_AutoDownloadDocuments: String { return self._s[2203]! } + public var Appearance_ThemePreview_Chat_3_Text: String { return self._s[2206]! } + public var Wallet_Completed_Title: String { return self._s[2207]! } + public var Notification_PinnedMessage: String { return self._s[2208]! } + public var VoiceOver_Chat_RecordModeVideoMessage: String { return self._s[2210]! } + public var Contacts_SortBy: String { return self._s[2211]! } public func PUSH_CHANNEL_MESSAGE_NOTEXT(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2209]!, self._r[2209]!, [_1]) + return formatWithArgumentRanges(self._s[2212]!, self._r[2212]!, [_1]) } public func PUSH_MESSAGE_GAME(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2211]!, self._r[2211]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2214]!, self._r[2214]!, [_1, _2]) } - public var Call_EncryptionKey_Title: String { return self._s[2212]! } - public var Watch_UserInfo_Service: String { return self._s[2213]! } - public var SettingsSearch_Synonyms_Data_SaveEditedPhotos: String { return self._s[2215]! } - public var Conversation_Unpin: String { return self._s[2217]! } - public var CancelResetAccount_Title: String { return self._s[2218]! } - public var Map_LiveLocationFor15Minutes: String { return self._s[2219]! } + public var Call_EncryptionKey_Title: String { return self._s[2215]! } + public var Watch_UserInfo_Service: String { return self._s[2216]! } + public var SettingsSearch_Synonyms_Data_SaveEditedPhotos: String { return self._s[2218]! } + public var Conversation_Unpin: String { return self._s[2220]! } + public var CancelResetAccount_Title: String { return self._s[2221]! } + public var Map_LiveLocationFor15Minutes: String { return self._s[2222]! } public func Time_PreciseDate_m8(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2221]!, self._r[2221]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2224]!, self._r[2224]!, [_1, _2, _3]) } - public var Group_Members_AddMemberBotErrorNotAllowed: String { return self._s[2222]! } - public var CallSettings_Title: String { return self._s[2223]! } - public var SettingsSearch_Synonyms_Appearance_ChatBackground: String { return self._s[2224]! } - public var PasscodeSettings_EncryptDataHelp: String { return self._s[2226]! } - public var AutoDownloadSettings_Contacts: String { return self._s[2227]! } + public var Group_Members_AddMemberBotErrorNotAllowed: String { return self._s[2225]! } + public var CallSettings_Title: String { return self._s[2226]! } + public var SettingsSearch_Synonyms_Appearance_ChatBackground: String { return self._s[2227]! } + public var PasscodeSettings_EncryptDataHelp: String { return self._s[2229]! } + public var AutoDownloadSettings_Contacts: String { return self._s[2230]! } public func Channel_AdminLog_MessageRankName(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2228]!, self._r[2228]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2231]!, self._r[2231]!, [_1, _2]) } - public var Passport_Identity_DocumentDetails: String { return self._s[2229]! } - public var LoginPassword_PasswordHelp: String { return self._s[2230]! } - public var SettingsSearch_Synonyms_Data_AutoDownloadUsingWifi: String { return self._s[2231]! } - public var PrivacyLastSeenSettings_CustomShareSettings_Delete: String { return self._s[2232]! } - public var Checkout_TotalPaidAmount: String { return self._s[2233]! } + public var Passport_Identity_DocumentDetails: String { return self._s[2232]! } + public var LoginPassword_PasswordHelp: String { return self._s[2233]! } + public var SettingsSearch_Synonyms_Data_AutoDownloadUsingWifi: String { return self._s[2234]! } + public var PrivacyLastSeenSettings_CustomShareSettings_Delete: String { return self._s[2235]! } + public var Checkout_TotalPaidAmount: String { return self._s[2236]! } public func FileSize_KB(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2234]!, self._r[2234]!, [_0]) + return formatWithArgumentRanges(self._s[2237]!, self._r[2237]!, [_0]) } - public var PasscodeSettings_ChangePasscode: String { return self._s[2235]! } - public var Conversation_SecretLinkPreviewAlert: String { return self._s[2237]! } - public var Privacy_SecretChatsLinkPreviews: String { return self._s[2238]! } + public var PasscodeSettings_ChangePasscode: String { return self._s[2238]! } + public var Conversation_SecretLinkPreviewAlert: String { return self._s[2240]! } + public var Privacy_SecretChatsLinkPreviews: String { return self._s[2241]! } public func PUSH_CHANNEL_MESSAGE_DOC(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2239]!, self._r[2239]!, [_1]) + return formatWithArgumentRanges(self._s[2242]!, self._r[2242]!, [_1]) } - public var VoiceOver_Chat_ReplyToYourMessage: String { return self._s[2240]! } - public var Contacts_InviteFriends: String { return self._s[2242]! } - public var Map_ChooseLocationTitle: String { return self._s[2243]! } - public var Conversation_StopPoll: String { return self._s[2245]! } + public var VoiceOver_Chat_ReplyToYourMessage: String { return self._s[2243]! } + public var Contacts_InviteFriends: String { return self._s[2245]! } + public var Map_ChooseLocationTitle: String { return self._s[2246]! } + public var Conversation_StopPoll: String { return self._s[2248]! } public func WebSearch_SearchNoResultsDescription(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2246]!, self._r[2246]!, [_0]) + return formatWithArgumentRanges(self._s[2249]!, self._r[2249]!, [_0]) } - public var Call_Camera: String { return self._s[2247]! } - public var LogoutOptions_ChangePhoneNumberTitle: String { return self._s[2248]! } - public var Calls_RatingFeedback: String { return self._s[2249]! } - public var GroupInfo_BroadcastListNamePlaceholder: String { return self._s[2250]! } - public var NotificationsSound_Pulse: String { return self._s[2251]! } - public var Watch_LastSeen_Lately: String { return self._s[2252]! } - public var ReportGroupLocation_Report: String { return self._s[2255]! } - public var Widget_NoUsers: String { return self._s[2256]! } - public var Conversation_UnvotePoll: String { return self._s[2257]! } - public var SettingsSearch_Synonyms_Privacy_ProfilePhoto: String { return self._s[2259]! } - public var Privacy_ProfilePhoto_WhoCanSeeMyPhoto: String { return self._s[2260]! } - public var NotificationsSound_Circles: String { return self._s[2261]! } - public var PrivacyLastSeenSettings_AlwaysShareWith_Title: String { return self._s[2264]! } - public var Wallet_Settings_DeleteWallet: String { return self._s[2265]! } - public var TwoStepAuth_RecoveryCodeExpired: String { return self._s[2266]! } - public var Proxy_TooltipUnavailable: String { return self._s[2267]! } - public var Passport_Identity_CountryPlaceholder: String { return self._s[2269]! } - public var GroupInfo_Permissions_SlowmodeInfo: String { return self._s[2271]! } - public var Conversation_FileDropbox: String { return self._s[2272]! } - public var Notifications_ExceptionsUnmuted: String { return self._s[2273]! } - public var Tour_Text3: String { return self._s[2275]! } - public var Login_ResetAccountProtected_Title: String { return self._s[2277]! } - public var GroupPermission_NoSendMessages: String { return self._s[2278]! } - public var WallpaperSearch_ColorTitle: String { return self._s[2279]! } - public var ChatAdmins_AllMembersAreAdminsOnHelp: String { return self._s[2280]! } + public var Call_Camera: String { return self._s[2250]! } + public var LogoutOptions_ChangePhoneNumberTitle: String { return self._s[2251]! } + public var Calls_RatingFeedback: String { return self._s[2252]! } + public var GroupInfo_BroadcastListNamePlaceholder: String { return self._s[2253]! } + public var NotificationsSound_Pulse: String { return self._s[2254]! } + public var Watch_LastSeen_Lately: String { return self._s[2255]! } + public var ReportGroupLocation_Report: String { return self._s[2258]! } + public var Widget_NoUsers: String { return self._s[2259]! } + public var Conversation_UnvotePoll: String { return self._s[2260]! } + public var SettingsSearch_Synonyms_Privacy_ProfilePhoto: String { return self._s[2262]! } + public var Privacy_ProfilePhoto_WhoCanSeeMyPhoto: String { return self._s[2263]! } + public var NotificationsSound_Circles: String { return self._s[2264]! } + public var PrivacyLastSeenSettings_AlwaysShareWith_Title: String { return self._s[2267]! } + public var Wallet_Settings_DeleteWallet: String { return self._s[2268]! } + public var TwoStepAuth_RecoveryCodeExpired: String { return self._s[2269]! } + public var Proxy_TooltipUnavailable: String { return self._s[2270]! } + public var Passport_Identity_CountryPlaceholder: String { return self._s[2272]! } + public var GroupInfo_Permissions_SlowmodeInfo: String { return self._s[2274]! } + public var Conversation_FileDropbox: String { return self._s[2275]! } + public var Notifications_ExceptionsUnmuted: String { return self._s[2276]! } + public var Tour_Text3: String { return self._s[2278]! } + public var Login_ResetAccountProtected_Title: String { return self._s[2280]! } + public var GroupPermission_NoSendMessages: String { return self._s[2281]! } + public var WallpaperSearch_ColorTitle: String { return self._s[2282]! } + public var ChatAdmins_AllMembersAreAdminsOnHelp: String { return self._s[2283]! } public func Conversation_LiveLocationYouAnd(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2282]!, self._r[2282]!, [_0]) + return formatWithArgumentRanges(self._s[2285]!, self._r[2285]!, [_0]) } - public var GroupInfo_AddParticipantTitle: String { return self._s[2283]! } - public var Checkout_ShippingOption_Title: String { return self._s[2284]! } - public var ChatSettings_AutoDownloadTitle: String { return self._s[2285]! } + public var GroupInfo_AddParticipantTitle: String { return self._s[2286]! } + public var Checkout_ShippingOption_Title: String { return self._s[2287]! } + public var ChatSettings_AutoDownloadTitle: String { return self._s[2288]! } public func DialogList_SingleTypingSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2286]!, self._r[2286]!, [_0]) + return formatWithArgumentRanges(self._s[2289]!, self._r[2289]!, [_0]) } public func ChatSettings_AutoDownloadSettings_TypeVideo(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2287]!, self._r[2287]!, [_0]) + return formatWithArgumentRanges(self._s[2290]!, self._r[2290]!, [_0]) } - public var Channel_Management_LabelAdministrator: String { return self._s[2288]! } - public var EditTheme_FileReadError: String { return self._s[2289]! } - public var OwnershipTransfer_ComeBackLater: String { return self._s[2290]! } - public var PrivacyLastSeenSettings_NeverShareWith_Placeholder: String { return self._s[2291]! } - public var AutoDownloadSettings_Photos: String { return self._s[2293]! } - public var Appearance_PreviewIncomingText: String { return self._s[2294]! } - public var ChatList_Context_MarkAllAsRead: String { return self._s[2295]! } - public var ChannelInfo_ConfirmLeave: String { return self._s[2296]! } - public var MediaPicker_MomentsDateRangeSameMonthYearFormat: String { return self._s[2297]! } - public var Passport_Identity_DocumentNumberPlaceholder: String { return self._s[2298]! } - public var Channel_AdminLogFilter_EventsNewMembers: String { return self._s[2299]! } - public var PasscodeSettings_AutoLock_IfAwayFor_5minutes: String { return self._s[2300]! } - public var GroupInfo_SetGroupPhotoStop: String { return self._s[2301]! } - public var Notification_SecretChatScreenshot: String { return self._s[2302]! } - public var AccessDenied_Wallpapers: String { return self._s[2303]! } - public var ChatList_Context_Mute: String { return self._s[2305]! } - public var Passport_Address_City: String { return self._s[2306]! } - public var InfoPlist_NSPhotoLibraryAddUsageDescription: String { return self._s[2307]! } - public var Appearance_ThemeCarouselClassic: String { return self._s[2308]! } - public var SocksProxySetup_SecretPlaceholder: String { return self._s[2309]! } - public var AccessDenied_LocationDisabled: String { return self._s[2310]! } - public var Group_Location_Title: String { return self._s[2311]! } - public var SocksProxySetup_HostnamePlaceholder: String { return self._s[2313]! } - public var GroupInfo_Sound: String { return self._s[2314]! } - public var ChannelInfo_ScamChannelWarning: String { return self._s[2315]! } - public var Stickers_RemoveFromFavorites: String { return self._s[2316]! } - public var Contacts_Title: String { return self._s[2317]! } - public var EditTheme_ThemeTemplateAlertText: String { return self._s[2318]! } - public var Passport_Language_fr: String { return self._s[2319]! } - public var Notifications_ResetAllNotifications: String { return self._s[2320]! } - public var PrivacySettings_SecurityTitle: String { return self._s[2323]! } - public var Checkout_NewCard_Title: String { return self._s[2324]! } - public var Login_HaveNotReceivedCodeInternal: String { return self._s[2325]! } - public var Conversation_ForwardChats: String { return self._s[2326]! } - public var Wallet_SecureStorageReset_PasscodeText: String { return self._s[2328]! } - public var PasscodeSettings_4DigitCode: String { return self._s[2329]! } - public var Settings_FAQ: String { return self._s[2331]! } - public var AutoDownloadSettings_DocumentsTitle: String { return self._s[2332]! } - public var Conversation_ContextMenuForward: String { return self._s[2333]! } - public var VoiceOver_Chat_YourPhoto: String { return self._s[2336]! } - public var PrivacyPolicy_Title: String { return self._s[2339]! } - public var Notifications_TextTone: String { return self._s[2340]! } - public var Profile_CreateNewContact: String { return self._s[2341]! } - public var PrivacyPhoneNumberSettings_WhoCanSeeMyPhoneNumber: String { return self._s[2342]! } - public var Call_Speaker: String { return self._s[2344]! } - public var AutoNightTheme_AutomaticSection: String { return self._s[2345]! } - public var Channel_OwnershipTransfer_EnterPassword: String { return self._s[2347]! } - public var Channel_Username_InvalidCharacters: String { return self._s[2348]! } + public var Channel_Management_LabelAdministrator: String { return self._s[2291]! } + public var EditTheme_FileReadError: String { return self._s[2292]! } + public var OwnershipTransfer_ComeBackLater: String { return self._s[2293]! } + public var PrivacyLastSeenSettings_NeverShareWith_Placeholder: String { return self._s[2294]! } + public var AutoDownloadSettings_Photos: String { return self._s[2296]! } + public var Appearance_PreviewIncomingText: String { return self._s[2297]! } + public var ChatList_Context_MarkAllAsRead: String { return self._s[2298]! } + public var ChannelInfo_ConfirmLeave: String { return self._s[2299]! } + public var MediaPicker_MomentsDateRangeSameMonthYearFormat: String { return self._s[2300]! } + public var Passport_Identity_DocumentNumberPlaceholder: String { return self._s[2301]! } + public var Channel_AdminLogFilter_EventsNewMembers: String { return self._s[2302]! } + public var PasscodeSettings_AutoLock_IfAwayFor_5minutes: String { return self._s[2303]! } + public var GroupInfo_SetGroupPhotoStop: String { return self._s[2304]! } + public var Notification_SecretChatScreenshot: String { return self._s[2305]! } + public var AccessDenied_Wallpapers: String { return self._s[2306]! } + public var ChatList_Context_Mute: String { return self._s[2308]! } + public var Passport_Address_City: String { return self._s[2309]! } + public var InfoPlist_NSPhotoLibraryAddUsageDescription: String { return self._s[2310]! } + public var Appearance_ThemeCarouselClassic: String { return self._s[2311]! } + public var SocksProxySetup_SecretPlaceholder: String { return self._s[2312]! } + public var AccessDenied_LocationDisabled: String { return self._s[2313]! } + public var Group_Location_Title: String { return self._s[2314]! } + public var SocksProxySetup_HostnamePlaceholder: String { return self._s[2316]! } + public var GroupInfo_Sound: String { return self._s[2317]! } + public var ChannelInfo_ScamChannelWarning: String { return self._s[2318]! } + public var Stickers_RemoveFromFavorites: String { return self._s[2319]! } + public var Contacts_Title: String { return self._s[2320]! } + public var EditTheme_ThemeTemplateAlertText: String { return self._s[2321]! } + public var Passport_Language_fr: String { return self._s[2322]! } + public var Notifications_ResetAllNotifications: String { return self._s[2323]! } + public var PrivacySettings_SecurityTitle: String { return self._s[2326]! } + public var Checkout_NewCard_Title: String { return self._s[2327]! } + public var Login_HaveNotReceivedCodeInternal: String { return self._s[2328]! } + public var Conversation_ForwardChats: String { return self._s[2329]! } + public var Wallet_SecureStorageReset_PasscodeText: String { return self._s[2331]! } + public var PasscodeSettings_4DigitCode: String { return self._s[2332]! } + public var Settings_FAQ: String { return self._s[2334]! } + public var AutoDownloadSettings_DocumentsTitle: String { return self._s[2335]! } + public var Conversation_ContextMenuForward: String { return self._s[2336]! } + public var VoiceOver_Chat_YourPhoto: String { return self._s[2339]! } + public var PrivacyPolicy_Title: String { return self._s[2342]! } + public var Notifications_TextTone: String { return self._s[2343]! } + public var Profile_CreateNewContact: String { return self._s[2344]! } + public var PrivacyPhoneNumberSettings_WhoCanSeeMyPhoneNumber: String { return self._s[2345]! } + public var Call_Speaker: String { return self._s[2347]! } + public var AutoNightTheme_AutomaticSection: String { return self._s[2348]! } + public var Channel_OwnershipTransfer_EnterPassword: String { return self._s[2350]! } + public var Channel_Username_InvalidCharacters: String { return self._s[2351]! } public func Channel_AdminLog_MessageChangedChannelUsername(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2349]!, self._r[2349]!, [_0]) + return formatWithArgumentRanges(self._s[2352]!, self._r[2352]!, [_0]) } - public var AutoDownloadSettings_AutodownloadFiles: String { return self._s[2350]! } - public var PrivacySettings_LastSeenTitle: String { return self._s[2351]! } - public var Channel_AdminLog_CanInviteUsers: String { return self._s[2352]! } - public var SettingsSearch_Synonyms_Privacy_Data_ClearPaymentsInfo: String { return self._s[2353]! } - public var OwnershipTransfer_SecurityCheck: String { return self._s[2354]! } - public var Conversation_MessageDeliveryFailed: String { return self._s[2355]! } - public var Watch_ChatList_NoConversationsText: String { return self._s[2356]! } - public var Bot_Unblock: String { return self._s[2357]! } - public var TextFormat_Italic: String { return self._s[2358]! } - public var WallpaperSearch_ColorPink: String { return self._s[2359]! } - public var Settings_About_Help: String { return self._s[2360]! } - public var SearchImages_Title: String { return self._s[2361]! } - public var Weekday_Wednesday: String { return self._s[2362]! } - public var Conversation_ClousStorageInfo_Description1: String { return self._s[2363]! } - public var ExplicitContent_AlertTitle: String { return self._s[2364]! } + public var AutoDownloadSettings_AutodownloadFiles: String { return self._s[2353]! } + public var PrivacySettings_LastSeenTitle: String { return self._s[2354]! } + public var Channel_AdminLog_CanInviteUsers: String { return self._s[2355]! } + public var SettingsSearch_Synonyms_Privacy_Data_ClearPaymentsInfo: String { return self._s[2356]! } + public var OwnershipTransfer_SecurityCheck: String { return self._s[2357]! } + public var Conversation_MessageDeliveryFailed: String { return self._s[2358]! } + public var Watch_ChatList_NoConversationsText: String { return self._s[2359]! } + public var Bot_Unblock: String { return self._s[2360]! } + public var TextFormat_Italic: String { return self._s[2361]! } + public var WallpaperSearch_ColorPink: String { return self._s[2362]! } + public var Settings_About_Help: String { return self._s[2363]! } + public var SearchImages_Title: String { return self._s[2364]! } + public var Weekday_Wednesday: String { return self._s[2365]! } + public var Conversation_ClousStorageInfo_Description1: String { return self._s[2366]! } + public var ExplicitContent_AlertTitle: String { return self._s[2367]! } public func Time_PreciseDate_m5(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2365]!, self._r[2365]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2368]!, self._r[2368]!, [_1, _2, _3]) } - public var Channel_DiscussionGroup_Create: String { return self._s[2366]! } - public var Weekday_Thursday: String { return self._s[2367]! } - public var Channel_BanUser_PermissionChangeGroupInfo: String { return self._s[2368]! } - public var Channel_Members_AddMembersHelp: String { return self._s[2369]! } + public var Channel_DiscussionGroup_Create: String { return self._s[2369]! } + public var Weekday_Thursday: String { return self._s[2370]! } + public var Channel_BanUser_PermissionChangeGroupInfo: String { return self._s[2371]! } + public var Channel_Members_AddMembersHelp: String { return self._s[2372]! } public func Checkout_SavePasswordTimeout(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2370]!, self._r[2370]!, [_0]) + return formatWithArgumentRanges(self._s[2373]!, self._r[2373]!, [_0]) } - public var Channel_DiscussionGroup_LinkGroup: String { return self._s[2371]! } - public var SettingsSearch_Synonyms_Notifications_InAppNotificationsVibrate: String { return self._s[2372]! } - public var Passport_RequestedInformation: String { return self._s[2373]! } - public var Login_PhoneAndCountryHelp: String { return self._s[2374]! } - public var Conversation_EncryptionProcessing: String { return self._s[2376]! } - public var Notifications_PermissionsSuppressWarningTitle: String { return self._s[2377]! } - public var PhotoEditor_EnhanceTool: String { return self._s[2379]! } - public var Channel_Setup_Title: String { return self._s[2380]! } - public var Conversation_SearchPlaceholder: String { return self._s[2381]! } - public var AccessDenied_LocationAlwaysDenied: String { return self._s[2382]! } - public var Checkout_ErrorGeneric: String { return self._s[2383]! } - public var Passport_Language_hu: String { return self._s[2384]! } + public var Channel_DiscussionGroup_LinkGroup: String { return self._s[2374]! } + public var SettingsSearch_Synonyms_Notifications_InAppNotificationsVibrate: String { return self._s[2375]! } + public var Passport_RequestedInformation: String { return self._s[2376]! } + public var Login_PhoneAndCountryHelp: String { return self._s[2377]! } + public var Conversation_EncryptionProcessing: String { return self._s[2379]! } + public var Notifications_PermissionsSuppressWarningTitle: String { return self._s[2380]! } + public var PhotoEditor_EnhanceTool: String { return self._s[2382]! } + public var Channel_Setup_Title: String { return self._s[2383]! } + public var Conversation_SearchPlaceholder: String { return self._s[2384]! } + public var AccessDenied_LocationAlwaysDenied: String { return self._s[2385]! } + public var Checkout_ErrorGeneric: String { return self._s[2386]! } + public var Passport_Language_hu: String { return self._s[2387]! } public func Passport_Identity_UploadOneOfScan(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2386]!, self._r[2386]!, [_0]) + return formatWithArgumentRanges(self._s[2389]!, self._r[2389]!, [_0]) } public func PUSH_MESSAGE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2389]!, self._r[2389]!, [_1]) + return formatWithArgumentRanges(self._s[2392]!, self._r[2392]!, [_1]) } public func UserInfo_BlockConfirmationTitle(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2390]!, self._r[2390]!, [_0]) + return formatWithArgumentRanges(self._s[2393]!, self._r[2393]!, [_0]) } - public var Group_Location_Info: String { return self._s[2391]! } - public var Conversation_CloudStorageInfo_Title: String { return self._s[2392]! } - public var Permissions_PeopleNearbyAllow_v0: String { return self._s[2393]! } - public var PhotoEditor_CropAspectRatioSquare: String { return self._s[2394]! } + public var Group_Location_Info: String { return self._s[2394]! } + public var Conversation_CloudStorageInfo_Title: String { return self._s[2395]! } + public var Permissions_PeopleNearbyAllow_v0: String { return self._s[2396]! } + public var PhotoEditor_CropAspectRatioSquare: String { return self._s[2397]! } public func Notification_Exceptions_MutedUntil(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2395]!, self._r[2395]!, [_0]) + return formatWithArgumentRanges(self._s[2398]!, self._r[2398]!, [_0]) } - public var Conversation_ClearPrivateHistory: String { return self._s[2396]! } - public var ContactInfo_PhoneLabelHome: String { return self._s[2397]! } - public var Appearance_RemoveThemeConfirmation: String { return self._s[2398]! } - public var PrivacySettings_LastSeenContacts: String { return self._s[2399]! } + public var Conversation_ClearPrivateHistory: String { return self._s[2399]! } + public var ContactInfo_PhoneLabelHome: String { return self._s[2400]! } + public var Appearance_RemoveThemeConfirmation: String { return self._s[2401]! } + public var PrivacySettings_LastSeenContacts: String { return self._s[2402]! } public func ChangePhone_ErrorOccupied(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2400]!, self._r[2400]!, [_0]) + return formatWithArgumentRanges(self._s[2403]!, self._r[2403]!, [_0]) } - public var Passport_Language_cs: String { return self._s[2401]! } - public var Message_PinnedAnimationMessage: String { return self._s[2403]! } - public var Passport_Identity_ReverseSideHelp: String { return self._s[2405]! } - public var SettingsSearch_Synonyms_Data_Storage_Title: String { return self._s[2406]! } - public var Wallet_Info_TransactionTo: String { return self._s[2408]! } - public var SettingsSearch_Synonyms_Privacy_PasscodeAndTouchId: String { return self._s[2409]! } - public var Embed_PlayingInPIP: String { return self._s[2410]! } - public var AutoNightTheme_ScheduleSection: String { return self._s[2411]! } + public var Passport_Language_cs: String { return self._s[2404]! } + public var Message_PinnedAnimationMessage: String { return self._s[2406]! } + public var Passport_Identity_ReverseSideHelp: String { return self._s[2408]! } + public var SettingsSearch_Synonyms_Data_Storage_Title: String { return self._s[2409]! } + public var Wallet_Info_TransactionTo: String { return self._s[2411]! } + public var SettingsSearch_Synonyms_Privacy_PasscodeAndTouchId: String { return self._s[2412]! } + public var Embed_PlayingInPIP: String { return self._s[2413]! } + public var AutoNightTheme_ScheduleSection: String { return self._s[2414]! } public func Call_EmojiDescription(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2412]!, self._r[2412]!, [_0]) + return formatWithArgumentRanges(self._s[2415]!, self._r[2415]!, [_0]) } - public var MediaPicker_LivePhotoDescription: String { return self._s[2413]! } + public var MediaPicker_LivePhotoDescription: String { return self._s[2416]! } public func Channel_AdminLog_MessageRestrictedName(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2414]!, self._r[2414]!, [_1]) + return formatWithArgumentRanges(self._s[2417]!, self._r[2417]!, [_1]) } - public var Notification_PaymentSent: String { return self._s[2415]! } - public var PhotoEditor_CurvesGreen: String { return self._s[2416]! } - public var Notification_Exceptions_PreviewAlwaysOff: String { return self._s[2417]! } - public var SaveIncomingPhotosSettings_Title: String { return self._s[2418]! } - public var NotificationSettings_ShowNotificationsAllAccounts: String { return self._s[2419]! } - public var VoiceOver_Chat_PagePreview: String { return self._s[2420]! } + public var Notification_PaymentSent: String { return self._s[2418]! } + public var PhotoEditor_CurvesGreen: String { return self._s[2419]! } + public var Notification_Exceptions_PreviewAlwaysOff: String { return self._s[2420]! } + public var SaveIncomingPhotosSettings_Title: String { return self._s[2421]! } + public var NotificationSettings_ShowNotificationsAllAccounts: String { return self._s[2422]! } + public var VoiceOver_Chat_PagePreview: String { return self._s[2423]! } public func PUSH_MESSAGE_SCREENSHOT(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2423]!, self._r[2423]!, [_1]) + return formatWithArgumentRanges(self._s[2426]!, self._r[2426]!, [_1]) } public func PUSH_MESSAGE_PHOTO_SECRET(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2424]!, self._r[2424]!, [_1]) + return formatWithArgumentRanges(self._s[2427]!, self._r[2427]!, [_1]) } public func ApplyLanguage_UnsufficientDataText(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2425]!, self._r[2425]!, [_1]) + return formatWithArgumentRanges(self._s[2428]!, self._r[2428]!, [_1]) } - public var NetworkUsageSettings_CallDataSection: String { return self._s[2427]! } - public var PasscodeSettings_HelpTop: String { return self._s[2428]! } - public var Group_OwnershipTransfer_ErrorAdminsTooMuch: String { return self._s[2429]! } - public var Passport_Address_TypeRentalAgreement: String { return self._s[2430]! } - public var EditTheme_ShortLink: String { return self._s[2431]! } - public var ProxyServer_VoiceOver_Active: String { return self._s[2432]! } - public var ReportPeer_ReasonOther_Placeholder: String { return self._s[2433]! } - public var CheckoutInfo_ErrorPhoneInvalid: String { return self._s[2434]! } - public var Call_Accept: String { return self._s[2436]! } - public var GroupRemoved_RemoveInfo: String { return self._s[2437]! } - public var Month_GenMarch: String { return self._s[2439]! } - public var PhotoEditor_ShadowsTool: String { return self._s[2440]! } - public var LoginPassword_Title: String { return self._s[2441]! } - public var Call_End: String { return self._s[2442]! } - public var Watch_Conversation_GroupInfo: String { return self._s[2443]! } - public var VoiceOver_Chat_Contact: String { return self._s[2444]! } - public var EditTheme_Create_Preview_IncomingText: String { return self._s[2445]! } - public var CallSettings_Always: String { return self._s[2446]! } - public var CallFeedback_Success: String { return self._s[2447]! } - public var TwoStepAuth_SetupHint: String { return self._s[2448]! } + public var NetworkUsageSettings_CallDataSection: String { return self._s[2430]! } + public var PasscodeSettings_HelpTop: String { return self._s[2431]! } + public var Group_OwnershipTransfer_ErrorAdminsTooMuch: String { return self._s[2432]! } + public var Passport_Address_TypeRentalAgreement: String { return self._s[2433]! } + public var EditTheme_ShortLink: String { return self._s[2434]! } + public var ProxyServer_VoiceOver_Active: String { return self._s[2435]! } + public var ReportPeer_ReasonOther_Placeholder: String { return self._s[2436]! } + public var CheckoutInfo_ErrorPhoneInvalid: String { return self._s[2437]! } + public var Call_Accept: String { return self._s[2439]! } + public var GroupRemoved_RemoveInfo: String { return self._s[2440]! } + public var Month_GenMarch: String { return self._s[2442]! } + public var PhotoEditor_ShadowsTool: String { return self._s[2443]! } + public var LoginPassword_Title: String { return self._s[2444]! } + public var Call_End: String { return self._s[2445]! } + public var Watch_Conversation_GroupInfo: String { return self._s[2446]! } + public var VoiceOver_Chat_Contact: String { return self._s[2447]! } + public var EditTheme_Create_Preview_IncomingText: String { return self._s[2448]! } + public var CallSettings_Always: String { return self._s[2449]! } + public var CallFeedback_Success: String { return self._s[2450]! } + public var TwoStepAuth_SetupHint: String { return self._s[2451]! } public func AddContact_ContactWillBeSharedAfterMutual(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2449]!, self._r[2449]!, [_1]) + return formatWithArgumentRanges(self._s[2452]!, self._r[2452]!, [_1]) } - public var ConversationProfile_UsersTooMuchError: String { return self._s[2450]! } - public var Login_PhoneTitle: String { return self._s[2451]! } - public var Passport_FieldPhoneHelp: String { return self._s[2452]! } - public var Weekday_ShortSunday: String { return self._s[2453]! } - public var Passport_InfoFAQ_URL: String { return self._s[2454]! } - public var ContactInfo_Job: String { return self._s[2456]! } - public var UserInfo_InviteBotToGroup: String { return self._s[2457]! } - public var Appearance_ThemeCarouselNightBlue: String { return self._s[2458]! } - public var TwoStepAuth_PasswordRemovePassportConfirmation: String { return self._s[2459]! } - public var Invite_ChannelsTooMuch: String { return self._s[2460]! } - public var Wallet_Send_ConfirmationConfirm: String { return self._s[2461]! } - public var SettingsSearch_Synonyms_Notifications_InAppNotificationsPreview: String { return self._s[2462]! } - public var Wallet_Receive_AmountText: String { return self._s[2463]! } - public var Passport_DeletePersonalDetailsConfirmation: String { return self._s[2464]! } - public var CallFeedback_ReasonNoise: String { return self._s[2465]! } - public var Appearance_AppIconDefault: String { return self._s[2467]! } - public var Passport_Identity_AddInternalPassport: String { return self._s[2468]! } - public var MediaPicker_AddCaption: String { return self._s[2469]! } - public var CallSettings_TabIconDescription: String { return self._s[2470]! } + public var ConversationProfile_UsersTooMuchError: String { return self._s[2453]! } + public var Login_PhoneTitle: String { return self._s[2454]! } + public var Passport_FieldPhoneHelp: String { return self._s[2455]! } + public var Weekday_ShortSunday: String { return self._s[2456]! } + public var Passport_InfoFAQ_URL: String { return self._s[2457]! } + public var ContactInfo_Job: String { return self._s[2459]! } + public var UserInfo_InviteBotToGroup: String { return self._s[2460]! } + public var Appearance_ThemeCarouselNightBlue: String { return self._s[2461]! } + public var TwoStepAuth_PasswordRemovePassportConfirmation: String { return self._s[2462]! } + public var Invite_ChannelsTooMuch: String { return self._s[2463]! } + public var Wallet_Send_ConfirmationConfirm: String { return self._s[2464]! } + public var SettingsSearch_Synonyms_Notifications_InAppNotificationsPreview: String { return self._s[2465]! } + public var Wallet_Receive_AmountText: String { return self._s[2466]! } + public var Passport_DeletePersonalDetailsConfirmation: String { return self._s[2467]! } + public var CallFeedback_ReasonNoise: String { return self._s[2468]! } + public var Appearance_AppIconDefault: String { return self._s[2470]! } + public var Passport_Identity_AddInternalPassport: String { return self._s[2471]! } + public var MediaPicker_AddCaption: String { return self._s[2472]! } + public var CallSettings_TabIconDescription: String { return self._s[2473]! } public func VoiceOver_Chat_Caption(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2471]!, self._r[2471]!, [_0]) + return formatWithArgumentRanges(self._s[2474]!, self._r[2474]!, [_0]) } - public var ChatList_UndoArchiveHiddenTitle: String { return self._s[2472]! } - public var Privacy_GroupsAndChannels_AlwaysAllow: String { return self._s[2473]! } - public var Passport_Identity_TypePersonalDetails: String { return self._s[2474]! } - public var DialogList_SearchSectionRecent: String { return self._s[2475]! } - public var PrivacyPolicy_DeclineMessage: String { return self._s[2476]! } - public var LogoutOptions_ClearCacheText: String { return self._s[2479]! } - public var LastSeen_WithinAWeek: String { return self._s[2480]! } - public var ChannelMembers_GroupAdminsTitle: String { return self._s[2481]! } - public var Conversation_CloudStorage_ChatStatus: String { return self._s[2483]! } - public var VoiceOver_Media_PlaybackRateNormal: String { return self._s[2484]! } + public var ChatList_UndoArchiveHiddenTitle: String { return self._s[2475]! } + public var Privacy_GroupsAndChannels_AlwaysAllow: String { return self._s[2476]! } + public var Passport_Identity_TypePersonalDetails: String { return self._s[2477]! } + public var DialogList_SearchSectionRecent: String { return self._s[2478]! } + public var PrivacyPolicy_DeclineMessage: String { return self._s[2479]! } + public var LogoutOptions_ClearCacheText: String { return self._s[2482]! } + public var LastSeen_WithinAWeek: String { return self._s[2483]! } + public var ChannelMembers_GroupAdminsTitle: String { return self._s[2484]! } + public var Conversation_CloudStorage_ChatStatus: String { return self._s[2486]! } + public var VoiceOver_Media_PlaybackRateNormal: String { return self._s[2487]! } public func AddContact_SharedContactExceptionInfo(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2485]!, self._r[2485]!, [_0]) + return formatWithArgumentRanges(self._s[2488]!, self._r[2488]!, [_0]) } - public var Passport_Address_TypeResidentialAddress: String { return self._s[2486]! } - public var Conversation_StatusLeftGroup: String { return self._s[2487]! } - public var SocksProxySetup_ProxyDetailsTitle: String { return self._s[2488]! } - public var SettingsSearch_Synonyms_Calls_Title: String { return self._s[2490]! } - public var GroupPermission_AddSuccess: String { return self._s[2491]! } - public var PhotoEditor_BlurToolRadial: String { return self._s[2493]! } - public var Conversation_ContextMenuCopy: String { return self._s[2494]! } - public var AccessDenied_CallMicrophone: String { return self._s[2495]! } + public var Passport_Address_TypeResidentialAddress: String { return self._s[2489]! } + public var Conversation_StatusLeftGroup: String { return self._s[2490]! } + public var SocksProxySetup_ProxyDetailsTitle: String { return self._s[2491]! } + public var SettingsSearch_Synonyms_Calls_Title: String { return self._s[2493]! } + public var GroupPermission_AddSuccess: String { return self._s[2494]! } + public var PhotoEditor_BlurToolRadial: String { return self._s[2496]! } + public var Conversation_ContextMenuCopy: String { return self._s[2497]! } + public var AccessDenied_CallMicrophone: String { return self._s[2498]! } public func Time_PreciseDate_m2(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2496]!, self._r[2496]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2499]!, self._r[2499]!, [_1, _2, _3]) } - public var Login_InvalidFirstNameError: String { return self._s[2497]! } - public var Notifications_Badge_CountUnreadMessages_InfoOn: String { return self._s[2498]! } - public var Checkout_PaymentMethod_New: String { return self._s[2499]! } - public var ShareMenu_CopyShareLinkGame: String { return self._s[2500]! } - public var PhotoEditor_QualityTool: String { return self._s[2501]! } - public var Login_SendCodeViaSms: String { return self._s[2502]! } - public var SettingsSearch_Synonyms_Privacy_DeleteAccountIfAwayFor: String { return self._s[2503]! } - public var Chat_SlowmodeAttachmentLimitReached: String { return self._s[2504]! } - public var Wallet_Receive_CopyAddress: String { return self._s[2505]! } - public var Login_EmailNotConfiguredError: String { return self._s[2506]! } - public var SocksProxySetup_Status: String { return self._s[2507]! } - public var PrivacyPolicy_Accept: String { return self._s[2508]! } - public var Notifications_ExceptionsMessagePlaceholder: String { return self._s[2509]! } - public var Appearance_AppIconClassicX: String { return self._s[2510]! } + public var Login_InvalidFirstNameError: String { return self._s[2500]! } + public var Notifications_Badge_CountUnreadMessages_InfoOn: String { return self._s[2501]! } + public var Checkout_PaymentMethod_New: String { return self._s[2502]! } + public var ShareMenu_CopyShareLinkGame: String { return self._s[2503]! } + public var PhotoEditor_QualityTool: String { return self._s[2504]! } + public var Login_SendCodeViaSms: String { return self._s[2505]! } + public var SettingsSearch_Synonyms_Privacy_DeleteAccountIfAwayFor: String { return self._s[2506]! } + public var Chat_SlowmodeAttachmentLimitReached: String { return self._s[2507]! } + public var Wallet_Receive_CopyAddress: String { return self._s[2508]! } + public var Login_EmailNotConfiguredError: String { return self._s[2509]! } + public var SocksProxySetup_Status: String { return self._s[2510]! } + public var PrivacyPolicy_Accept: String { return self._s[2511]! } + public var Notifications_ExceptionsMessagePlaceholder: String { return self._s[2512]! } + public var Appearance_AppIconClassicX: String { return self._s[2513]! } public func PUSH_CHAT_MESSAGE_TEXT(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2511]!, self._r[2511]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2514]!, self._r[2514]!, [_1, _2, _3]) } - public var OwnershipTransfer_SecurityRequirements: String { return self._s[2512]! } - public var InfoPlist_NSLocationAlwaysUsageDescription: String { return self._s[2513]! } - public var AutoNightTheme_Automatic: String { return self._s[2514]! } - public var Channel_Username_InvalidStartsWithNumber: String { return self._s[2515]! } - public var Privacy_ContactsSyncHelp: String { return self._s[2516]! } - public var Cache_Help: String { return self._s[2517]! } - public var Group_ErrorAccessDenied: String { return self._s[2518]! } - public var Passport_Language_fa: String { return self._s[2519]! } - public var Wallet_Intro_Text: String { return self._s[2520]! } - public var Login_ResetAccountProtected_TimerTitle: String { return self._s[2521]! } - public var VoiceOver_Chat_YourVideoMessage: String { return self._s[2522]! } - public var PrivacySettings_LastSeen: String { return self._s[2523]! } + public var OwnershipTransfer_SecurityRequirements: String { return self._s[2515]! } + public var InfoPlist_NSLocationAlwaysUsageDescription: String { return self._s[2516]! } + public var AutoNightTheme_Automatic: String { return self._s[2517]! } + public var Channel_Username_InvalidStartsWithNumber: String { return self._s[2518]! } + public var Privacy_ContactsSyncHelp: String { return self._s[2519]! } + public var Cache_Help: String { return self._s[2520]! } + public var Group_ErrorAccessDenied: String { return self._s[2521]! } + public var Passport_Language_fa: String { return self._s[2522]! } + public var Wallet_Intro_Text: String { return self._s[2523]! } + public var Login_ResetAccountProtected_TimerTitle: String { return self._s[2524]! } + public var VoiceOver_Chat_YourVideoMessage: String { return self._s[2525]! } + public var PrivacySettings_LastSeen: String { return self._s[2526]! } public func DialogList_MultipleTyping(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2524]!, self._r[2524]!, [_0, _1]) + return formatWithArgumentRanges(self._s[2527]!, self._r[2527]!, [_0, _1]) } - public var Preview_SaveGif: String { return self._s[2528]! } - public var SettingsSearch_Synonyms_Privacy_TwoStepAuth: String { return self._s[2529]! } - public var Profile_About: String { return self._s[2530]! } - public var Channel_About_Placeholder: String { return self._s[2531]! } - public var Login_InfoTitle: String { return self._s[2532]! } + public var Preview_SaveGif: String { return self._s[2531]! } + public var SettingsSearch_Synonyms_Privacy_TwoStepAuth: String { return self._s[2532]! } + public var Profile_About: String { return self._s[2533]! } + public var Channel_About_Placeholder: String { return self._s[2534]! } + public var Login_InfoTitle: String { return self._s[2535]! } public func TwoStepAuth_SetupPendingEmail(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2533]!, self._r[2533]!, [_0]) + return formatWithArgumentRanges(self._s[2536]!, self._r[2536]!, [_0]) } - public var EditTheme_Expand_Preview_IncomingReplyText: String { return self._s[2534]! } - public var Watch_Suggestion_CantTalk: String { return self._s[2536]! } - public var ContactInfo_Title: String { return self._s[2537]! } - public var Media_ShareThisVideo: String { return self._s[2538]! } - public var Weekday_ShortFriday: String { return self._s[2539]! } - public var AccessDenied_Contacts: String { return self._s[2541]! } - public var Notification_CallIncomingShort: String { return self._s[2542]! } - public var Group_Setup_TypePublic: String { return self._s[2543]! } - public var Notifications_MessageNotificationsExceptions: String { return self._s[2544]! } - public var Notifications_Badge_IncludeChannels: String { return self._s[2545]! } - public var Notifications_MessageNotificationsPreview: String { return self._s[2548]! } - public var ConversationProfile_ErrorCreatingConversation: String { return self._s[2549]! } - public var Group_ErrorAddTooMuchBots: String { return self._s[2550]! } - public var Privacy_GroupsAndChannels_CustomShareHelp: String { return self._s[2551]! } - public var Permissions_CellularDataAllowInSettings_v0: String { return self._s[2552]! } + public var EditTheme_Expand_Preview_IncomingReplyText: String { return self._s[2537]! } + public var Watch_Suggestion_CantTalk: String { return self._s[2539]! } + public var ContactInfo_Title: String { return self._s[2540]! } + public var Media_ShareThisVideo: String { return self._s[2541]! } + public var Weekday_ShortFriday: String { return self._s[2542]! } + public var AccessDenied_Contacts: String { return self._s[2544]! } + public var Notification_CallIncomingShort: String { return self._s[2545]! } + public var Group_Setup_TypePublic: String { return self._s[2546]! } + public var Notifications_MessageNotificationsExceptions: String { return self._s[2547]! } + public var Notifications_Badge_IncludeChannels: String { return self._s[2548]! } + public var Notifications_MessageNotificationsPreview: String { return self._s[2551]! } + public var ConversationProfile_ErrorCreatingConversation: String { return self._s[2552]! } + public var Group_ErrorAddTooMuchBots: String { return self._s[2553]! } + public var Privacy_GroupsAndChannels_CustomShareHelp: String { return self._s[2554]! } + public var Permissions_CellularDataAllowInSettings_v0: String { return self._s[2555]! } public func Wallet_SecureStorageChanged_BiometryText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2553]!, self._r[2553]!, [_0]) + return formatWithArgumentRanges(self._s[2556]!, self._r[2556]!, [_0]) } - public var DialogList_Typing: String { return self._s[2554]! } - public var CallFeedback_IncludeLogs: String { return self._s[2556]! } - public var Checkout_Phone: String { return self._s[2558]! } - public var Login_InfoFirstNamePlaceholder: String { return self._s[2561]! } - public var Privacy_Calls_Integration: String { return self._s[2562]! } - public var Notifications_PermissionsAllow: String { return self._s[2563]! } - public var TwoStepAuth_AddHintDescription: String { return self._s[2567]! } - public var Settings_ChatSettings: String { return self._s[2568]! } + public var DialogList_Typing: String { return self._s[2557]! } + public var CallFeedback_IncludeLogs: String { return self._s[2559]! } + public var Checkout_Phone: String { return self._s[2561]! } + public var Login_InfoFirstNamePlaceholder: String { return self._s[2564]! } + public var Privacy_Calls_Integration: String { return self._s[2565]! } + public var Notifications_PermissionsAllow: String { return self._s[2566]! } + public var TwoStepAuth_AddHintDescription: String { return self._s[2570]! } + public var Settings_ChatSettings: String { return self._s[2571]! } public func Channel_AdminLog_MessageInvitedNameUsername(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2569]!, self._r[2569]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2572]!, self._r[2572]!, [_1, _2]) } - public var GroupRemoved_DeleteUser: String { return self._s[2571]! } + public var GroupRemoved_DeleteUser: String { return self._s[2574]! } public func Channel_AdminLog_PollStopped(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2572]!, self._r[2572]!, [_0]) + return formatWithArgumentRanges(self._s[2575]!, self._r[2575]!, [_0]) } public func PUSH_MESSAGE_PHOTO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2573]!, self._r[2573]!, [_1]) + return formatWithArgumentRanges(self._s[2576]!, self._r[2576]!, [_1]) } - public var Login_ContinueWithLocalization: String { return self._s[2574]! } - public var Watch_Message_ForwardedFrom: String { return self._s[2575]! } - public var TwoStepAuth_EnterEmailCode: String { return self._s[2577]! } - public var Conversation_Unblock: String { return self._s[2578]! } - public var PrivacySettings_DataSettings: String { return self._s[2579]! } - public var Group_PublicLink_Info: String { return self._s[2580]! } - public var Notifications_InAppNotificationsVibrate: String { return self._s[2581]! } + public var Login_ContinueWithLocalization: String { return self._s[2577]! } + public var Watch_Message_ForwardedFrom: String { return self._s[2578]! } + public var TwoStepAuth_EnterEmailCode: String { return self._s[2580]! } + public var Conversation_Unblock: String { return self._s[2581]! } + public var PrivacySettings_DataSettings: String { return self._s[2582]! } + public var Group_PublicLink_Info: String { return self._s[2583]! } + public var Notifications_InAppNotificationsVibrate: String { return self._s[2584]! } public func Privacy_GroupsAndChannels_InviteToChannelError(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2582]!, self._r[2582]!, [_0, _1]) + return formatWithArgumentRanges(self._s[2585]!, self._r[2585]!, [_0, _1]) } - public var Wallet_RestoreFailed_CreateWallet: String { return self._s[2584]! } - public var PrivacySettings_Passcode: String { return self._s[2586]! } - public var Call_Mute: String { return self._s[2587]! } - public var Passport_Language_dz: String { return self._s[2588]! } - public var Wallet_Receive_AmountHeader: String { return self._s[2589]! } - public var Passport_Language_tk: String { return self._s[2590]! } + public var Wallet_RestoreFailed_CreateWallet: String { return self._s[2587]! } + public var PrivacySettings_Passcode: String { return self._s[2589]! } + public var Call_Mute: String { return self._s[2590]! } + public var Passport_Language_dz: String { return self._s[2591]! } + public var Wallet_Receive_AmountHeader: String { return self._s[2592]! } + public var Passport_Language_tk: String { return self._s[2593]! } public func Login_EmailCodeSubject(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2591]!, self._r[2591]!, [_0]) + return formatWithArgumentRanges(self._s[2594]!, self._r[2594]!, [_0]) } - public var Settings_Search: String { return self._s[2592]! } - public var InfoPlist_NSPhotoLibraryUsageDescription: String { return self._s[2593]! } - public var Conversation_ContextMenuReply: String { return self._s[2594]! } - public var WallpaperSearch_ColorBrown: String { return self._s[2595]! } - public var Chat_AttachmentMultipleForwardDisabled: String { return self._s[2596]! } - public var Tour_Title1: String { return self._s[2597]! } - public var Conversation_ClearGroupHistory: String { return self._s[2599]! } - public var Wallet_TransactionInfo_RecipientHeader: String { return self._s[2600]! } - public var WallpaperPreview_Motion: String { return self._s[2601]! } + public var Settings_Search: String { return self._s[2595]! } + public var InfoPlist_NSPhotoLibraryUsageDescription: String { return self._s[2596]! } + public var Conversation_ContextMenuReply: String { return self._s[2597]! } + public var WallpaperSearch_ColorBrown: String { return self._s[2598]! } + public var Chat_AttachmentMultipleForwardDisabled: String { return self._s[2599]! } + public var Tour_Title1: String { return self._s[2600]! } + public var Conversation_ClearGroupHistory: String { return self._s[2602]! } + public var Wallet_TransactionInfo_RecipientHeader: String { return self._s[2603]! } + public var WallpaperPreview_Motion: String { return self._s[2604]! } public func Checkout_PasswordEntry_Text(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2602]!, self._r[2602]!, [_0]) + return formatWithArgumentRanges(self._s[2605]!, self._r[2605]!, [_0]) } - public var Call_RateCall: String { return self._s[2603]! } - public var Channel_AdminLog_BanSendStickersAndGifs: String { return self._s[2604]! } - public var Passport_PasswordCompleteSetup: String { return self._s[2605]! } - public var Conversation_InputTextSilentBroadcastPlaceholder: String { return self._s[2606]! } - public var UserInfo_LastNamePlaceholder: String { return self._s[2608]! } + public var Call_RateCall: String { return self._s[2606]! } + public var Channel_AdminLog_BanSendStickersAndGifs: String { return self._s[2607]! } + public var Passport_PasswordCompleteSetup: String { return self._s[2608]! } + public var Conversation_InputTextSilentBroadcastPlaceholder: String { return self._s[2609]! } + public var UserInfo_LastNamePlaceholder: String { return self._s[2611]! } public func Login_WillCallYou(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2610]!, self._r[2610]!, [_0]) + return formatWithArgumentRanges(self._s[2613]!, self._r[2613]!, [_0]) } - public var Compose_Create: String { return self._s[2611]! } - public var Contacts_InviteToTelegram: String { return self._s[2612]! } - public var GroupInfo_Notifications: String { return self._s[2613]! } - public var Message_PinnedLiveLocationMessage: String { return self._s[2615]! } - public var Month_GenApril: String { return self._s[2616]! } - public var Appearance_AutoNightTheme: String { return self._s[2617]! } - public var ChatSettings_AutomaticAudioDownload: String { return self._s[2619]! } - public var Login_CodeSentSms: String { return self._s[2621]! } + public var Compose_Create: String { return self._s[2614]! } + public var Contacts_InviteToTelegram: String { return self._s[2615]! } + public var GroupInfo_Notifications: String { return self._s[2616]! } + public var Message_PinnedLiveLocationMessage: String { return self._s[2618]! } + public var Month_GenApril: String { return self._s[2619]! } + public var Appearance_AutoNightTheme: String { return self._s[2620]! } + public var ChatSettings_AutomaticAudioDownload: String { return self._s[2622]! } + public var Login_CodeSentSms: String { return self._s[2624]! } public func UserInfo_UnblockConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2622]!, self._r[2622]!, [_0]) + return formatWithArgumentRanges(self._s[2625]!, self._r[2625]!, [_0]) } - public var EmptyGroupInfo_Line3: String { return self._s[2623]! } - public var LogoutOptions_ContactSupportText: String { return self._s[2624]! } - public var Passport_Language_hr: String { return self._s[2625]! } - public var Common_ActionNotAllowedError: String { return self._s[2626]! } + public var EmptyGroupInfo_Line3: String { return self._s[2626]! } + public var LogoutOptions_ContactSupportText: String { return self._s[2627]! } + public var Passport_Language_hr: String { return self._s[2628]! } + public var Common_ActionNotAllowedError: String { return self._s[2629]! } public func Channel_AdminLog_MessageRestrictedNewSetting(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2627]!, self._r[2627]!, [_0]) + return formatWithArgumentRanges(self._s[2630]!, self._r[2630]!, [_0]) } - public var GroupInfo_InviteLink_CopyLink: String { return self._s[2628]! } - public var Wallet_Info_TransactionFrom: String { return self._s[2629]! } - public var Wallet_Send_ErrorDecryptionFailed: String { return self._s[2630]! } - public var Conversation_InputTextBroadcastPlaceholder: String { return self._s[2631]! } - public var Privacy_SecretChatsTitle: String { return self._s[2632]! } - public var Notification_SecretChatMessageScreenshotSelf: String { return self._s[2634]! } - public var GroupInfo_AddUserLeftError: String { return self._s[2635]! } - public var AutoDownloadSettings_TypePrivateChats: String { return self._s[2636]! } - public var LogoutOptions_ContactSupportTitle: String { return self._s[2637]! } - public var Channel_AddBotErrorHaveRights: String { return self._s[2638]! } - public var Preview_DeleteGif: String { return self._s[2639]! } - public var GroupInfo_Permissions_Exceptions: String { return self._s[2640]! } - public var Group_ErrorNotMutualContact: String { return self._s[2641]! } - public var Notification_MessageLifetime5s: String { return self._s[2642]! } + public var GroupInfo_InviteLink_CopyLink: String { return self._s[2631]! } + public var Wallet_Info_TransactionFrom: String { return self._s[2632]! } + public var Wallet_Send_ErrorDecryptionFailed: String { return self._s[2633]! } + public var Conversation_InputTextBroadcastPlaceholder: String { return self._s[2634]! } + public var Privacy_SecretChatsTitle: String { return self._s[2635]! } + public var Notification_SecretChatMessageScreenshotSelf: String { return self._s[2637]! } + public var GroupInfo_AddUserLeftError: String { return self._s[2638]! } + public var AutoDownloadSettings_TypePrivateChats: String { return self._s[2639]! } + public var LogoutOptions_ContactSupportTitle: String { return self._s[2640]! } + public var Channel_AddBotErrorHaveRights: String { return self._s[2641]! } + public var Preview_DeleteGif: String { return self._s[2642]! } + public var GroupInfo_Permissions_Exceptions: String { return self._s[2643]! } + public var Group_ErrorNotMutualContact: String { return self._s[2644]! } + public var Notification_MessageLifetime5s: String { return self._s[2645]! } public func Watch_LastSeen_AtDate(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2643]!, self._r[2643]!, [_0]) + return formatWithArgumentRanges(self._s[2646]!, self._r[2646]!, [_0]) } - public var VoiceOver_Chat_Video: String { return self._s[2644]! } - public var Channel_OwnershipTransfer_ErrorPublicChannelsTooMuch: String { return self._s[2646]! } - public var ReportSpam_DeleteThisChat: String { return self._s[2647]! } - public var Passport_Address_AddBankStatement: String { return self._s[2648]! } - public var Notification_CallIncoming: String { return self._s[2649]! } - public var Wallet_Words_NotDoneTitle: String { return self._s[2650]! } - public var Compose_NewGroupTitle: String { return self._s[2651]! } - public var TwoStepAuth_RecoveryCodeHelp: String { return self._s[2653]! } - public var Passport_Address_Postcode: String { return self._s[2655]! } + public var VoiceOver_Chat_Video: String { return self._s[2647]! } + public var Channel_OwnershipTransfer_ErrorPublicChannelsTooMuch: String { return self._s[2649]! } + public var ReportSpam_DeleteThisChat: String { return self._s[2650]! } + public var Passport_Address_AddBankStatement: String { return self._s[2651]! } + public var Notification_CallIncoming: String { return self._s[2652]! } + public var Wallet_Words_NotDoneTitle: String { return self._s[2653]! } + public var Compose_NewGroupTitle: String { return self._s[2654]! } + public var TwoStepAuth_RecoveryCodeHelp: String { return self._s[2656]! } + public var Passport_Address_Postcode: String { return self._s[2658]! } public func LastSeen_YesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2656]!, self._r[2656]!, [_0]) + return formatWithArgumentRanges(self._s[2659]!, self._r[2659]!, [_0]) } - public var Checkout_NewCard_SaveInfoHelp: String { return self._s[2657]! } - public var VoiceOver_Chat_YourMusic: String { return self._s[2658]! } - public var WallpaperColors_Title: String { return self._s[2659]! } - public var SocksProxySetup_ShareQRCodeInfo: String { return self._s[2660]! } - public var VoiceOver_MessageContextForward: String { return self._s[2661]! } - public var GroupPermission_Duration: String { return self._s[2662]! } + public var Checkout_NewCard_SaveInfoHelp: String { return self._s[2660]! } + public var VoiceOver_Chat_YourMusic: String { return self._s[2661]! } + public var WallpaperColors_Title: String { return self._s[2662]! } + public var SocksProxySetup_ShareQRCodeInfo: String { return self._s[2663]! } + public var VoiceOver_MessageContextForward: String { return self._s[2664]! } + public var GroupPermission_Duration: String { return self._s[2665]! } public func Cache_Clear(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2663]!, self._r[2663]!, [_0]) + return formatWithArgumentRanges(self._s[2666]!, self._r[2666]!, [_0]) } - public var Bot_GroupStatusDoesNotReadHistory: String { return self._s[2664]! } - public var Username_Placeholder: String { return self._s[2665]! } - public var CallFeedback_WhatWentWrong: String { return self._s[2666]! } - public var Passport_FieldAddressUploadHelp: String { return self._s[2667]! } - public var Permissions_NotificationsAllowInSettings_v0: String { return self._s[2668]! } + public var Bot_GroupStatusDoesNotReadHistory: String { return self._s[2667]! } + public var Username_Placeholder: String { return self._s[2668]! } + public var CallFeedback_WhatWentWrong: String { return self._s[2669]! } + public var Passport_FieldAddressUploadHelp: String { return self._s[2670]! } + public var Permissions_NotificationsAllowInSettings_v0: String { return self._s[2671]! } public func Channel_AdminLog_MessageChangedUnlinkedChannel(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2670]!, self._r[2670]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2673]!, self._r[2673]!, [_1, _2]) } - public var Passport_PasswordDescription: String { return self._s[2671]! } - public var Channel_MessagePhotoUpdated: String { return self._s[2672]! } - public var MediaPicker_TapToUngroupDescription: String { return self._s[2673]! } - public var SettingsSearch_Synonyms_Notifications_BadgeCountUnreadMessages: String { return self._s[2674]! } - public var AttachmentMenu_PhotoOrVideo: String { return self._s[2675]! } - public var Conversation_ContextMenuMore: String { return self._s[2676]! } - public var Privacy_PaymentsClearInfo: String { return self._s[2677]! } - public var CallSettings_TabIcon: String { return self._s[2678]! } - public var KeyCommand_Find: String { return self._s[2679]! } - public var Appearance_ThemePreview_ChatList_7_Text: String { return self._s[2680]! } - public var EditTheme_Edit_Preview_IncomingText: String { return self._s[2681]! } - public var Message_PinnedGame: String { return self._s[2682]! } - public var VoiceOver_Chat_ForwardedFromYou: String { return self._s[2683]! } - public var Notifications_Badge_CountUnreadMessages_InfoOff: String { return self._s[2685]! } - public var Login_CallRequestState2: String { return self._s[2687]! } - public var CheckoutInfo_ReceiverInfoNamePlaceholder: String { return self._s[2689]! } + public var Passport_PasswordDescription: String { return self._s[2674]! } + public var Channel_MessagePhotoUpdated: String { return self._s[2675]! } + public var MediaPicker_TapToUngroupDescription: String { return self._s[2676]! } + public var SettingsSearch_Synonyms_Notifications_BadgeCountUnreadMessages: String { return self._s[2677]! } + public var AttachmentMenu_PhotoOrVideo: String { return self._s[2678]! } + public var Conversation_ContextMenuMore: String { return self._s[2679]! } + public var Privacy_PaymentsClearInfo: String { return self._s[2680]! } + public var CallSettings_TabIcon: String { return self._s[2681]! } + public var KeyCommand_Find: String { return self._s[2682]! } + public var Appearance_ThemePreview_ChatList_7_Text: String { return self._s[2683]! } + public var EditTheme_Edit_Preview_IncomingText: String { return self._s[2684]! } + public var Message_PinnedGame: String { return self._s[2685]! } + public var VoiceOver_Chat_ForwardedFromYou: String { return self._s[2686]! } + public var Notifications_Badge_CountUnreadMessages_InfoOff: String { return self._s[2688]! } + public var Login_CallRequestState2: String { return self._s[2690]! } + public var CheckoutInfo_ReceiverInfoNamePlaceholder: String { return self._s[2692]! } public func VoiceOver_Chat_PhotoFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2690]!, self._r[2690]!, [_0]) + return formatWithArgumentRanges(self._s[2693]!, self._r[2693]!, [_0]) } public func Checkout_PayPrice(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2692]!, self._r[2692]!, [_0]) - } - public var WallpaperPreview_Blurred: String { return self._s[2693]! } - public var Conversation_InstantPagePreview: String { return self._s[2694]! } - public func DialogList_SingleUploadingVideoSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[2695]!, self._r[2695]!, [_0]) } - public var SecretTimer_VideoDescription: String { return self._s[2698]! } - public var WallpaperSearch_ColorRed: String { return self._s[2699]! } - public var GroupPermission_NoPinMessages: String { return self._s[2700]! } - public var Passport_Language_es: String { return self._s[2701]! } - public var Permissions_ContactsAllow_v0: String { return self._s[2703]! } - public var Conversation_EditingMessageMediaEditCurrentVideo: String { return self._s[2704]! } + public var WallpaperPreview_Blurred: String { return self._s[2696]! } + public var Conversation_InstantPagePreview: String { return self._s[2697]! } + public func DialogList_SingleUploadingVideoSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[2698]!, self._r[2698]!, [_0]) + } + public var SecretTimer_VideoDescription: String { return self._s[2701]! } + public var WallpaperSearch_ColorRed: String { return self._s[2702]! } + public var GroupPermission_NoPinMessages: String { return self._s[2703]! } + public var Passport_Language_es: String { return self._s[2704]! } + public var Permissions_ContactsAllow_v0: String { return self._s[2706]! } + public var Conversation_EditingMessageMediaEditCurrentVideo: String { return self._s[2707]! } public func PUSH_CHAT_MESSAGE_CONTACT(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2705]!, self._r[2705]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2708]!, self._r[2708]!, [_1, _2]) } - public var Privacy_Forwards_CustomHelp: String { return self._s[2706]! } - public var WebPreview_GettingLinkInfo: String { return self._s[2707]! } - public var Watch_UserInfo_Unmute: String { return self._s[2708]! } - public var GroupInfo_ChannelListNamePlaceholder: String { return self._s[2709]! } - public var AccessDenied_CameraRestricted: String { return self._s[2711]! } + public var Privacy_Forwards_CustomHelp: String { return self._s[2709]! } + public var WebPreview_GettingLinkInfo: String { return self._s[2710]! } + public var Watch_UserInfo_Unmute: String { return self._s[2711]! } + public var GroupInfo_ChannelListNamePlaceholder: String { return self._s[2712]! } + public var AccessDenied_CameraRestricted: String { return self._s[2714]! } public func Conversation_Kilobytes(_ _0: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2712]!, self._r[2712]!, ["\(_0)"]) + return formatWithArgumentRanges(self._s[2715]!, self._r[2715]!, ["\(_0)"]) } - public var ChatList_ReadAll: String { return self._s[2714]! } - public var Settings_CopyUsername: String { return self._s[2715]! } - public var Contacts_SearchLabel: String { return self._s[2716]! } - public var Map_OpenInYandexNavigator: String { return self._s[2718]! } - public var PasscodeSettings_EncryptData: String { return self._s[2719]! } - public var WallpaperSearch_ColorPrefix: String { return self._s[2720]! } - public var Notifications_GroupNotificationsPreview: String { return self._s[2721]! } - public var DialogList_AdNoticeAlert: String { return self._s[2722]! } - public var CheckoutInfo_ShippingInfoAddress1: String { return self._s[2724]! } - public var CheckoutInfo_ShippingInfoAddress2: String { return self._s[2725]! } - public var Localization_LanguageCustom: String { return self._s[2726]! } - public var Passport_Identity_TypeDriversLicenseUploadScan: String { return self._s[2727]! } - public var CallFeedback_Title: String { return self._s[2728]! } - public var VoiceOver_Chat_RecordPreviewVoiceMessage: String { return self._s[2731]! } - public var Passport_Address_OneOfTypePassportRegistration: String { return self._s[2732]! } - public var Wallet_Intro_CreateErrorTitle: String { return self._s[2733]! } - public var Conversation_InfoGroup: String { return self._s[2734]! } - public var Compose_NewMessage: String { return self._s[2735]! } - public var FastTwoStepSetup_HintPlaceholder: String { return self._s[2736]! } - public var ChatSettings_AutoDownloadVideoMessages: String { return self._s[2737]! } - public var Wallet_SecureStorageReset_BiometryFaceId: String { return self._s[2738]! } - public var Channel_DiscussionGroup_UnlinkChannel: String { return self._s[2739]! } + public var ChatList_ReadAll: String { return self._s[2717]! } + public var Settings_CopyUsername: String { return self._s[2718]! } + public var Contacts_SearchLabel: String { return self._s[2719]! } + public var Map_OpenInYandexNavigator: String { return self._s[2721]! } + public var PasscodeSettings_EncryptData: String { return self._s[2722]! } + public var WallpaperSearch_ColorPrefix: String { return self._s[2723]! } + public var Notifications_GroupNotificationsPreview: String { return self._s[2724]! } + public var DialogList_AdNoticeAlert: String { return self._s[2725]! } + public var CheckoutInfo_ShippingInfoAddress1: String { return self._s[2727]! } + public var CheckoutInfo_ShippingInfoAddress2: String { return self._s[2728]! } + public var Localization_LanguageCustom: String { return self._s[2729]! } + public var Passport_Identity_TypeDriversLicenseUploadScan: String { return self._s[2730]! } + public var CallFeedback_Title: String { return self._s[2731]! } + public var VoiceOver_Chat_RecordPreviewVoiceMessage: String { return self._s[2734]! } + public var Passport_Address_OneOfTypePassportRegistration: String { return self._s[2735]! } + public var Wallet_Intro_CreateErrorTitle: String { return self._s[2736]! } + public var Conversation_InfoGroup: String { return self._s[2737]! } + public var Compose_NewMessage: String { return self._s[2738]! } + public var FastTwoStepSetup_HintPlaceholder: String { return self._s[2739]! } + public var ChatSettings_AutoDownloadVideoMessages: String { return self._s[2740]! } + public var Wallet_SecureStorageReset_BiometryFaceId: String { return self._s[2741]! } + public var Channel_DiscussionGroup_UnlinkChannel: String { return self._s[2742]! } public func Passport_Scans_ScanIndex(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2740]!, self._r[2740]!, [_0]) + return formatWithArgumentRanges(self._s[2743]!, self._r[2743]!, [_0]) } - public var Channel_AdminLog_CanDeleteMessages: String { return self._s[2741]! } - public var Login_CancelSignUpConfirmation: String { return self._s[2742]! } - public var ChangePhoneNumberCode_Help: String { return self._s[2743]! } - public var PrivacySettings_DeleteAccountHelp: String { return self._s[2744]! } - public var Channel_BlackList_Title: String { return self._s[2745]! } - public var UserInfo_PhoneCall: String { return self._s[2746]! } - public var Passport_Address_OneOfTypeBankStatement: String { return self._s[2748]! } - public var State_connecting: String { return self._s[2749]! } - public var Appearance_ThemePreview_ChatList_6_Text: String { return self._s[2750]! } - public var EditTheme_Expand_BottomInfo: String { return self._s[2751]! } + public var Channel_AdminLog_CanDeleteMessages: String { return self._s[2744]! } + public var Login_CancelSignUpConfirmation: String { return self._s[2745]! } + public var ChangePhoneNumberCode_Help: String { return self._s[2746]! } + public var PrivacySettings_DeleteAccountHelp: String { return self._s[2747]! } + public var Channel_BlackList_Title: String { return self._s[2748]! } + public var UserInfo_PhoneCall: String { return self._s[2749]! } + public var Passport_Address_OneOfTypeBankStatement: String { return self._s[2751]! } + public var State_connecting: String { return self._s[2752]! } + public var Appearance_ThemePreview_ChatList_6_Text: String { return self._s[2753]! } + public var EditTheme_Expand_BottomInfo: String { return self._s[2754]! } public func LastSeen_TodayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2752]!, self._r[2752]!, [_0]) + return formatWithArgumentRanges(self._s[2755]!, self._r[2755]!, [_0]) } public func DialogList_SingleRecordingAudioSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2753]!, self._r[2753]!, [_0]) + return formatWithArgumentRanges(self._s[2756]!, self._r[2756]!, [_0]) } - public var Notifications_GroupNotifications: String { return self._s[2754]! } - public var Conversation_SendMessageErrorTooMuchScheduled: String { return self._s[2755]! } - public var Passport_Identity_EditPassport: String { return self._s[2756]! } - public var EnterPasscode_RepeatNewPasscode: String { return self._s[2758]! } - public var Localization_EnglishLanguageName: String { return self._s[2759]! } - public var Share_AuthDescription: String { return self._s[2760]! } - public var SettingsSearch_Synonyms_Notifications_ChannelNotificationsAlert: String { return self._s[2761]! } - public var Passport_Identity_Surname: String { return self._s[2762]! } - public var Compose_TokenListPlaceholder: String { return self._s[2763]! } - public var Passport_Identity_OneOfTypePassport: String { return self._s[2764]! } - public var Settings_AboutEmpty: String { return self._s[2765]! } - public var Conversation_Unmute: String { return self._s[2766]! } - public var CreateGroup_ChannelsTooMuch: String { return self._s[2768]! } - public var Wallet_Sending_Text: String { return self._s[2769]! } + public var Notifications_GroupNotifications: String { return self._s[2757]! } + public var Conversation_SendMessageErrorTooMuchScheduled: String { return self._s[2758]! } + public var Passport_Identity_EditPassport: String { return self._s[2759]! } + public var EnterPasscode_RepeatNewPasscode: String { return self._s[2761]! } + public var Localization_EnglishLanguageName: String { return self._s[2762]! } + public var Share_AuthDescription: String { return self._s[2763]! } + public var SettingsSearch_Synonyms_Notifications_ChannelNotificationsAlert: String { return self._s[2764]! } + public var Passport_Identity_Surname: String { return self._s[2765]! } + public var Compose_TokenListPlaceholder: String { return self._s[2766]! } + public var Passport_Identity_OneOfTypePassport: String { return self._s[2767]! } + public var Settings_AboutEmpty: String { return self._s[2768]! } + public var Conversation_Unmute: String { return self._s[2769]! } + public var CreateGroup_ChannelsTooMuch: String { return self._s[2771]! } + public var Wallet_Sending_Text: String { return self._s[2772]! } public func PUSH_CONTACT_JOINED(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2770]!, self._r[2770]!, [_1]) + return formatWithArgumentRanges(self._s[2773]!, self._r[2773]!, [_1]) } - public var Login_CodeSentCall: String { return self._s[2771]! } - public var ContactInfo_PhoneLabelHomeFax: String { return self._s[2773]! } - public var ChatSettings_Appearance: String { return self._s[2774]! } - public var Appearance_PickAccentColor: String { return self._s[2775]! } + public var Login_CodeSentCall: String { return self._s[2774]! } + public var ContactInfo_PhoneLabelHomeFax: String { return self._s[2776]! } + public var ChatSettings_Appearance: String { return self._s[2777]! } + public var Appearance_PickAccentColor: String { return self._s[2778]! } public func PUSH_CHAT_MESSAGE_NOTEXT(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2776]!, self._r[2776]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2779]!, self._r[2779]!, [_1, _2]) } public func PUSH_MESSAGE_GEO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2777]!, self._r[2777]!, [_1]) + return formatWithArgumentRanges(self._s[2780]!, self._r[2780]!, [_1]) } - public var Notification_CallMissed: String { return self._s[2778]! } - public var SettingsSearch_Synonyms_Appearance_ChatBackground_Custom: String { return self._s[2779]! } - public var Channel_AdminLogFilter_EventsInfo: String { return self._s[2780]! } - public var ChatAdmins_AdminLabel: String { return self._s[2782]! } - public var KeyCommand_JumpToNextChat: String { return self._s[2783]! } - public var Conversation_StopPollConfirmationTitle: String { return self._s[2785]! } - public var ChangePhoneNumberCode_CodePlaceholder: String { return self._s[2786]! } - public var Month_GenJune: String { return self._s[2787]! } - public var Watch_Location_Current: String { return self._s[2788]! } - public var Wallet_Receive_CopyInvoiceUrl: String { return self._s[2789]! } - public var Conversation_TitleMute: String { return self._s[2790]! } + public var Notification_CallMissed: String { return self._s[2781]! } + public var SettingsSearch_Synonyms_Appearance_ChatBackground_Custom: String { return self._s[2782]! } + public var Channel_AdminLogFilter_EventsInfo: String { return self._s[2783]! } + public var ChatAdmins_AdminLabel: String { return self._s[2785]! } + public var KeyCommand_JumpToNextChat: String { return self._s[2786]! } + public var Conversation_StopPollConfirmationTitle: String { return self._s[2788]! } + public var ChangePhoneNumberCode_CodePlaceholder: String { return self._s[2789]! } + public var Month_GenJune: String { return self._s[2790]! } + public var Watch_Location_Current: String { return self._s[2791]! } + public var Wallet_Receive_CopyInvoiceUrl: String { return self._s[2792]! } + public var Conversation_TitleMute: String { return self._s[2793]! } public func PUSH_CHANNEL_MESSAGE_ROUND(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2791]!, self._r[2791]!, [_1]) + return formatWithArgumentRanges(self._s[2794]!, self._r[2794]!, [_1]) } - public var GroupInfo_DeleteAndExit: String { return self._s[2792]! } + public var GroupInfo_DeleteAndExit: String { return self._s[2795]! } public func Conversation_Moderate_DeleteAllMessages(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2793]!, self._r[2793]!, [_0]) + return formatWithArgumentRanges(self._s[2796]!, self._r[2796]!, [_0]) } - public var Call_ReportPlaceholder: String { return self._s[2794]! } - public var Chat_SlowmodeSendError: String { return self._s[2795]! } - public var MaskStickerSettings_Info: String { return self._s[2796]! } - public var EditTheme_Expand_TopInfo: String { return self._s[2797]! } + public var Call_ReportPlaceholder: String { return self._s[2797]! } + public var Chat_SlowmodeSendError: String { return self._s[2798]! } + public var MaskStickerSettings_Info: String { return self._s[2799]! } + public var EditTheme_Expand_TopInfo: String { return self._s[2800]! } public func GroupInfo_AddParticipantConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2798]!, self._r[2798]!, [_0]) + return formatWithArgumentRanges(self._s[2801]!, self._r[2801]!, [_0]) } - public var Checkout_NewCard_PostcodeTitle: String { return self._s[2799]! } - public var Passport_Address_RegionPlaceholder: String { return self._s[2801]! } - public var Contacts_ShareTelegram: String { return self._s[2802]! } - public var EnterPasscode_EnterNewPasscodeNew: String { return self._s[2803]! } - public var Channel_ErrorAccessDenied: String { return self._s[2804]! } - public var UserInfo_ScamBotWarning: String { return self._s[2806]! } - public var Stickers_GroupChooseStickerPack: String { return self._s[2807]! } - public var Call_ConnectionErrorTitle: String { return self._s[2808]! } - public var UserInfo_NotificationsEnable: String { return self._s[2809]! } - public var ArchivedChats_IntroText1: String { return self._s[2810]! } - public var Tour_Text4: String { return self._s[2813]! } - public var WallpaperSearch_Recent: String { return self._s[2814]! } - public var GroupInfo_ScamGroupWarning: String { return self._s[2815]! } - public var Profile_MessageLifetime2s: String { return self._s[2817]! } - public var Appearance_ThemePreview_ChatList_5_Text: String { return self._s[2818]! } - public var Notification_MessageLifetime2s: String { return self._s[2819]! } + public var Checkout_NewCard_PostcodeTitle: String { return self._s[2802]! } + public var Passport_Address_RegionPlaceholder: String { return self._s[2804]! } + public var Contacts_ShareTelegram: String { return self._s[2805]! } + public var EnterPasscode_EnterNewPasscodeNew: String { return self._s[2806]! } + public var Channel_ErrorAccessDenied: String { return self._s[2807]! } + public var UserInfo_ScamBotWarning: String { return self._s[2809]! } + public var Stickers_GroupChooseStickerPack: String { return self._s[2810]! } + public var Call_ConnectionErrorTitle: String { return self._s[2811]! } + public var UserInfo_NotificationsEnable: String { return self._s[2812]! } + public var ArchivedChats_IntroText1: String { return self._s[2813]! } + public var Tour_Text4: String { return self._s[2816]! } + public var WallpaperSearch_Recent: String { return self._s[2817]! } + public var GroupInfo_ScamGroupWarning: String { return self._s[2818]! } + public var Profile_MessageLifetime2s: String { return self._s[2820]! } + public var Appearance_ThemePreview_ChatList_5_Text: String { return self._s[2821]! } + public var Notification_MessageLifetime2s: String { return self._s[2822]! } public func Time_PreciseDate_m10(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2820]!, self._r[2820]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2823]!, self._r[2823]!, [_1, _2, _3]) } - public var Cache_ClearCache: String { return self._s[2821]! } - public var AutoNightTheme_UpdateLocation: String { return self._s[2822]! } - public var Permissions_NotificationsUnreachableText_v0: String { return self._s[2823]! } + public var Cache_ClearCache: String { return self._s[2824]! } + public var AutoNightTheme_UpdateLocation: String { return self._s[2825]! } + public var Permissions_NotificationsUnreachableText_v0: String { return self._s[2826]! } public func Channel_AdminLog_MessageChangedGroupUsername(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2828]!, self._r[2828]!, [_0]) + return formatWithArgumentRanges(self._s[2831]!, self._r[2831]!, [_0]) } public func Conversation_ShareMyPhoneNumber_StatusSuccess(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2830]!, self._r[2830]!, [_0]) + return formatWithArgumentRanges(self._s[2833]!, self._r[2833]!, [_0]) } - public var LocalGroup_Text: String { return self._s[2831]! } - public var Channel_AdminLog_EmptyFilterTitle: String { return self._s[2832]! } - public var SocksProxySetup_TypeSocks: String { return self._s[2833]! } - public var ChatList_UnarchiveAction: String { return self._s[2834]! } - public var AutoNightTheme_Title: String { return self._s[2835]! } - public var InstantPage_FeedbackButton: String { return self._s[2836]! } - public var Passport_FieldAddress: String { return self._s[2837]! } + public var LocalGroup_Text: String { return self._s[2834]! } + public var Channel_AdminLog_EmptyFilterTitle: String { return self._s[2835]! } + public var SocksProxySetup_TypeSocks: String { return self._s[2836]! } + public var ChatList_UnarchiveAction: String { return self._s[2837]! } + public var AutoNightTheme_Title: String { return self._s[2838]! } + public var InstantPage_FeedbackButton: String { return self._s[2839]! } + public var Passport_FieldAddress: String { return self._s[2840]! } public func Channel_AdminLog_SetSlowmode(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2838]!, self._r[2838]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2841]!, self._r[2841]!, [_1, _2]) } - public var Month_ShortMarch: String { return self._s[2839]! } + public var Month_ShortMarch: String { return self._s[2842]! } public func PUSH_MESSAGE_INVOICE(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2840]!, self._r[2840]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2843]!, self._r[2843]!, [_1, _2]) } - public var SocksProxySetup_UsernamePlaceholder: String { return self._s[2841]! } - public var Conversation_ShareInlineBotLocationConfirmation: String { return self._s[2842]! } - public var Passport_FloodError: String { return self._s[2843]! } - public var SecretGif_Title: String { return self._s[2844]! } - public var NotificationSettings_ShowNotificationsAllAccountsInfoOn: String { return self._s[2845]! } - public var ChatList_Context_UnhideArchive: String { return self._s[2846]! } - public var Passport_Language_th: String { return self._s[2848]! } - public var Passport_Address_Address: String { return self._s[2849]! } - public var Login_InvalidLastNameError: String { return self._s[2850]! } - public var Notifications_InAppNotificationsPreview: String { return self._s[2851]! } - public var Notifications_PermissionsUnreachableTitle: String { return self._s[2852]! } - public var ChatList_Context_Archive: String { return self._s[2853]! } - public var SettingsSearch_FAQ: String { return self._s[2854]! } - public var ShareMenu_Send: String { return self._s[2855]! } - public var WallpaperSearch_ColorYellow: String { return self._s[2857]! } - public var Month_GenNovember: String { return self._s[2859]! } - public var SettingsSearch_Synonyms_Appearance_LargeEmoji: String { return self._s[2861]! } + public var SocksProxySetup_UsernamePlaceholder: String { return self._s[2844]! } + public var Conversation_ShareInlineBotLocationConfirmation: String { return self._s[2845]! } + public var Passport_FloodError: String { return self._s[2846]! } + public var SecretGif_Title: String { return self._s[2847]! } + public var NotificationSettings_ShowNotificationsAllAccountsInfoOn: String { return self._s[2848]! } + public var ChatList_Context_UnhideArchive: String { return self._s[2849]! } + public var Passport_Language_th: String { return self._s[2851]! } + public var Passport_Address_Address: String { return self._s[2852]! } + public var Login_InvalidLastNameError: String { return self._s[2853]! } + public var Notifications_InAppNotificationsPreview: String { return self._s[2854]! } + public var Notifications_PermissionsUnreachableTitle: String { return self._s[2855]! } + public var ChatList_Context_Archive: String { return self._s[2856]! } + public var SettingsSearch_FAQ: String { return self._s[2857]! } + public var ShareMenu_Send: String { return self._s[2858]! } + public var WallpaperSearch_ColorYellow: String { return self._s[2860]! } + public var Month_GenNovember: String { return self._s[2862]! } + public var SettingsSearch_Synonyms_Appearance_LargeEmoji: String { return self._s[2864]! } public func Conversation_ShareMyPhoneNumberConfirmation(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2862]!, self._r[2862]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2865]!, self._r[2865]!, [_1, _2]) } - public var Checkout_Email: String { return self._s[2864]! } - public var NotificationsSound_Tritone: String { return self._s[2865]! } - public var StickerPacksSettings_ManagingHelp: String { return self._s[2867]! } + public var Checkout_Email: String { return self._s[2867]! } + public var NotificationsSound_Tritone: String { return self._s[2868]! } + public var StickerPacksSettings_ManagingHelp: String { return self._s[2870]! } public func PUSH_PINNED_ROUND(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2870]!, self._r[2870]!, [_1]) + return formatWithArgumentRanges(self._s[2873]!, self._r[2873]!, [_1]) } - public var ChangePhoneNumberNumber_Help: String { return self._s[2871]! } + public var ChangePhoneNumberNumber_Help: String { return self._s[2874]! } public func Checkout_LiabilityAlert(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2872]!, self._r[2872]!, [_1, _1, _1, _2]) + return formatWithArgumentRanges(self._s[2875]!, self._r[2875]!, [_1, _1, _1, _2]) } - public var ChatList_UndoArchiveTitle: String { return self._s[2873]! } - public var Notification_Exceptions_Add: String { return self._s[2874]! } - public var DialogList_You: String { return self._s[2875]! } - public var MediaPicker_Send: String { return self._s[2878]! } - public var SettingsSearch_Synonyms_Stickers_Title: String { return self._s[2879]! } - public var Appearance_ThemePreview_ChatList_4_Text: String { return self._s[2880]! } - public var Call_AudioRouteSpeaker: String { return self._s[2881]! } - public var Watch_UserInfo_Title: String { return self._s[2882]! } - public var VoiceOver_Chat_PollFinalResults: String { return self._s[2883]! } - public var Appearance_AccentColor: String { return self._s[2884]! } + public var ChatList_UndoArchiveTitle: String { return self._s[2876]! } + public var Notification_Exceptions_Add: String { return self._s[2877]! } + public var DialogList_You: String { return self._s[2878]! } + public var MediaPicker_Send: String { return self._s[2881]! } + public var SettingsSearch_Synonyms_Stickers_Title: String { return self._s[2882]! } + public var Appearance_ThemePreview_ChatList_4_Text: String { return self._s[2883]! } + public var Call_AudioRouteSpeaker: String { return self._s[2884]! } + public var Watch_UserInfo_Title: String { return self._s[2885]! } + public var VoiceOver_Chat_PollFinalResults: String { return self._s[2886]! } + public var Appearance_AccentColor: String { return self._s[2887]! } public func Login_EmailPhoneSubject(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2885]!, self._r[2885]!, [_0]) + return formatWithArgumentRanges(self._s[2888]!, self._r[2888]!, [_0]) } - public var Permissions_ContactsAllowInSettings_v0: String { return self._s[2886]! } + public var Permissions_ContactsAllowInSettings_v0: String { return self._s[2889]! } public func PUSH_CHANNEL_MESSAGE_GAME(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2887]!, self._r[2887]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2890]!, self._r[2890]!, [_1, _2]) } - public var Conversation_ClousStorageInfo_Description2: String { return self._s[2888]! } - public var WebSearch_RecentClearConfirmation: String { return self._s[2889]! } - public var Notification_CallOutgoing: String { return self._s[2890]! } - public var PrivacySettings_PasscodeAndFaceId: String { return self._s[2891]! } - public var Channel_DiscussionGroup_MakeHistoryPublic: String { return self._s[2892]! } - public var Call_RecordingDisabledMessage: String { return self._s[2893]! } - public var Message_Game: String { return self._s[2894]! } - public var Conversation_PressVolumeButtonForSound: String { return self._s[2895]! } - public var PrivacyLastSeenSettings_CustomHelp: String { return self._s[2896]! } - public var Channel_DiscussionGroup_PrivateGroup: String { return self._s[2897]! } - public var Channel_EditAdmin_PermissionAddAdmins: String { return self._s[2898]! } - public var Date_DialogDateFormat: String { return self._s[2899]! } - public var WallpaperColors_SetCustomColor: String { return self._s[2900]! } - public var Notifications_InAppNotifications: String { return self._s[2901]! } + public var Conversation_ClousStorageInfo_Description2: String { return self._s[2891]! } + public var WebSearch_RecentClearConfirmation: String { return self._s[2892]! } + public var Notification_CallOutgoing: String { return self._s[2893]! } + public var PrivacySettings_PasscodeAndFaceId: String { return self._s[2894]! } + public var Channel_DiscussionGroup_MakeHistoryPublic: String { return self._s[2895]! } + public var Call_RecordingDisabledMessage: String { return self._s[2896]! } + public var Message_Game: String { return self._s[2897]! } + public var Conversation_PressVolumeButtonForSound: String { return self._s[2898]! } + public var PrivacyLastSeenSettings_CustomHelp: String { return self._s[2899]! } + public var Channel_DiscussionGroup_PrivateGroup: String { return self._s[2900]! } + public var Channel_EditAdmin_PermissionAddAdmins: String { return self._s[2901]! } + public var Date_DialogDateFormat: String { return self._s[2902]! } + public var WallpaperColors_SetCustomColor: String { return self._s[2903]! } + public var Notifications_InAppNotifications: String { return self._s[2904]! } public func Channel_Management_RemovedBy(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2902]!, self._r[2902]!, [_0]) - } - public func Settings_ApplyProxyAlert(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2903]!, self._r[2903]!, [_1, _2]) - } - public var NewContact_Title: String { return self._s[2904]! } - public func AutoDownloadSettings_UpToForAll(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[2905]!, self._r[2905]!, [_0]) } - public var Conversation_ViewContactDetails: String { return self._s[2906]! } + public func Settings_ApplyProxyAlert(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[2906]!, self._r[2906]!, [_1, _2]) + } + public var NewContact_Title: String { return self._s[2907]! } + public func AutoDownloadSettings_UpToForAll(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[2908]!, self._r[2908]!, [_0]) + } + public var Conversation_ViewContactDetails: String { return self._s[2909]! } public func PUSH_CHANNEL_MESSAGE_CONTACT(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2908]!, self._r[2908]!, [_1]) + return formatWithArgumentRanges(self._s[2911]!, self._r[2911]!, [_1]) } - public var Checkout_NewCard_CardholderNameTitle: String { return self._s[2909]! } - public var Passport_Identity_ExpiryDateNone: String { return self._s[2910]! } - public var PrivacySettings_Title: String { return self._s[2911]! } - public var Conversation_SilentBroadcastTooltipOff: String { return self._s[2914]! } - public var GroupRemoved_UsersSectionTitle: String { return self._s[2915]! } - public var VoiceOver_Chat_ContactEmail: String { return self._s[2916]! } - public var Contacts_PhoneNumber: String { return self._s[2917]! } - public var Map_ShowPlaces: String { return self._s[2919]! } - public var ChatAdmins_Title: String { return self._s[2920]! } - public var InstantPage_Reference: String { return self._s[2922]! } - public var Wallet_Info_Updating: String { return self._s[2923]! } - public var ReportGroupLocation_Text: String { return self._s[2924]! } + public var Checkout_NewCard_CardholderNameTitle: String { return self._s[2912]! } + public var Passport_Identity_ExpiryDateNone: String { return self._s[2913]! } + public var PrivacySettings_Title: String { return self._s[2914]! } + public var Conversation_SilentBroadcastTooltipOff: String { return self._s[2917]! } + public var GroupRemoved_UsersSectionTitle: String { return self._s[2918]! } + public var VoiceOver_Chat_ContactEmail: String { return self._s[2919]! } + public var Contacts_PhoneNumber: String { return self._s[2920]! } + public var Map_ShowPlaces: String { return self._s[2922]! } + public var ChatAdmins_Title: String { return self._s[2923]! } + public var InstantPage_Reference: String { return self._s[2925]! } + public var Wallet_Info_Updating: String { return self._s[2926]! } + public var ReportGroupLocation_Text: String { return self._s[2927]! } public func PUSH_CHAT_MESSAGE_FWD(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2925]!, self._r[2925]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2928]!, self._r[2928]!, [_1, _2]) } - public var Camera_FlashOff: String { return self._s[2926]! } - public var Wallet_Intro_TermsUrl: String { return self._s[2927]! } - public var Watch_UserInfo_Block: String { return self._s[2928]! } - public var ChatSettings_Stickers: String { return self._s[2929]! } - public var ChatSettings_DownloadInBackground: String { return self._s[2930]! } - public var Appearance_ThemeCarouselTintedNight: String { return self._s[2931]! } + public var Camera_FlashOff: String { return self._s[2929]! } + public var Wallet_Intro_TermsUrl: String { return self._s[2930]! } + public var Watch_UserInfo_Block: String { return self._s[2931]! } + public var ChatSettings_Stickers: String { return self._s[2932]! } + public var ChatSettings_DownloadInBackground: String { return self._s[2933]! } + public var Appearance_ThemeCarouselTintedNight: String { return self._s[2934]! } public func UserInfo_BlockConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2932]!, self._r[2932]!, [_0]) + return formatWithArgumentRanges(self._s[2935]!, self._r[2935]!, [_0]) } - public var Settings_ViewPhoto: String { return self._s[2933]! } - public var Login_CheckOtherSessionMessages: String { return self._s[2934]! } - public var AutoDownloadSettings_Cellular: String { return self._s[2935]! } - public var Wallet_Created_ExportErrorTitle: String { return self._s[2936]! } - public var SettingsSearch_Synonyms_Notifications_GroupNotificationsExceptions: String { return self._s[2937]! } - public var VoiceOver_MessageContextShare: String { return self._s[2938]! } + public var Settings_ViewPhoto: String { return self._s[2936]! } + public var Login_CheckOtherSessionMessages: String { return self._s[2937]! } + public var AutoDownloadSettings_Cellular: String { return self._s[2938]! } + public var Wallet_Created_ExportErrorTitle: String { return self._s[2939]! } + public var SettingsSearch_Synonyms_Notifications_GroupNotificationsExceptions: String { return self._s[2940]! } + public var VoiceOver_MessageContextShare: String { return self._s[2941]! } public func Target_InviteToGroupConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2940]!, self._r[2940]!, [_0]) - } - public var Privacy_DeleteDrafts: String { return self._s[2941]! } - public var Wallpaper_SetCustomBackgroundInfo: String { return self._s[2942]! } - public func LastSeen_AtDate(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[2943]!, self._r[2943]!, [_0]) } - public var DialogList_SavedMessagesHelp: String { return self._s[2944]! } - public var Wallet_SecureStorageNotAvailable_Title: String { return self._s[2945]! } - public var DialogList_SavedMessages: String { return self._s[2946]! } - public var GroupInfo_UpgradeButton: String { return self._s[2947]! } - public var Appearance_ThemePreview_ChatList_3_Text: String { return self._s[2949]! } - public var DialogList_Pin: String { return self._s[2950]! } + public var Privacy_DeleteDrafts: String { return self._s[2944]! } + public var Wallpaper_SetCustomBackgroundInfo: String { return self._s[2945]! } + public func LastSeen_AtDate(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[2946]!, self._r[2946]!, [_0]) + } + public var DialogList_SavedMessagesHelp: String { return self._s[2947]! } + public var Wallet_SecureStorageNotAvailable_Title: String { return self._s[2948]! } + public var DialogList_SavedMessages: String { return self._s[2949]! } + public var GroupInfo_UpgradeButton: String { return self._s[2950]! } + public var Appearance_ThemePreview_ChatList_3_Text: String { return self._s[2952]! } + public var DialogList_Pin: String { return self._s[2953]! } public func ForwardedAuthors2(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2951]!, self._r[2951]!, [_0, _1]) + return formatWithArgumentRanges(self._s[2954]!, self._r[2954]!, [_0, _1]) } public func Login_PhoneGenericEmailSubject(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2952]!, self._r[2952]!, [_0]) + return formatWithArgumentRanges(self._s[2955]!, self._r[2955]!, [_0]) } - public var Notification_Exceptions_AlwaysOn: String { return self._s[2953]! } - public var UserInfo_NotificationsDisable: String { return self._s[2954]! } - public var Paint_Outlined: String { return self._s[2955]! } - public var Activity_PlayingGame: String { return self._s[2956]! } - public var SearchImages_NoImagesFound: String { return self._s[2957]! } - public var SocksProxySetup_ProxyType: String { return self._s[2958]! } - public var AppleWatch_ReplyPresetsHelp: String { return self._s[2960]! } - public var Conversation_ContextMenuCancelSending: String { return self._s[2961]! } - public var Settings_AppLanguage: String { return self._s[2962]! } - public var TwoStepAuth_ResetAccountHelp: String { return self._s[2963]! } - public var Common_ChoosePhoto: String { return self._s[2964]! } - public var CallFeedback_ReasonEcho: String { return self._s[2965]! } + public var Notification_Exceptions_AlwaysOn: String { return self._s[2956]! } + public var UserInfo_NotificationsDisable: String { return self._s[2957]! } + public var Paint_Outlined: String { return self._s[2958]! } + public var Activity_PlayingGame: String { return self._s[2959]! } + public var SearchImages_NoImagesFound: String { return self._s[2960]! } + public var SocksProxySetup_ProxyType: String { return self._s[2961]! } + public var AppleWatch_ReplyPresetsHelp: String { return self._s[2963]! } + public var Conversation_ContextMenuCancelSending: String { return self._s[2964]! } + public var Settings_AppLanguage: String { return self._s[2965]! } + public var TwoStepAuth_ResetAccountHelp: String { return self._s[2966]! } + public var Common_ChoosePhoto: String { return self._s[2967]! } + public var CallFeedback_ReasonEcho: String { return self._s[2968]! } public func PUSH_PINNED_AUDIO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2966]!, self._r[2966]!, [_1]) + return formatWithArgumentRanges(self._s[2969]!, self._r[2969]!, [_1]) } - public var Privacy_Calls_AlwaysAllow: String { return self._s[2967]! } - public var Activity_UploadingVideo: String { return self._s[2968]! } - public var ChannelInfo_DeleteChannelConfirmation: String { return self._s[2969]! } - public var NetworkUsageSettings_Wifi: String { return self._s[2970]! } - public var VoiceOver_Editing_ClearText: String { return self._s[2971]! } - public var PUSH_SENDER_YOU: String { return self._s[2972]! } - public var Channel_BanUser_PermissionReadMessages: String { return self._s[2973]! } - public var Checkout_PayWithTouchId: String { return self._s[2974]! } - public var Wallpaper_ResetWallpapersConfirmation: String { return self._s[2975]! } + public var Privacy_Calls_AlwaysAllow: String { return self._s[2970]! } + public var Activity_UploadingVideo: String { return self._s[2971]! } + public var ChannelInfo_DeleteChannelConfirmation: String { return self._s[2972]! } + public var NetworkUsageSettings_Wifi: String { return self._s[2973]! } + public var VoiceOver_Editing_ClearText: String { return self._s[2974]! } + public var PUSH_SENDER_YOU: String { return self._s[2975]! } + public var Channel_BanUser_PermissionReadMessages: String { return self._s[2976]! } + public var Checkout_PayWithTouchId: String { return self._s[2977]! } + public var Wallpaper_ResetWallpapersConfirmation: String { return self._s[2978]! } public func PUSH_LOCKED_MESSAGE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2977]!, self._r[2977]!, [_1]) - } - public var Notifications_ExceptionsNone: String { return self._s[2978]! } - public func Message_ForwardedMessageShort(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2979]!, self._r[2979]!, [_0]) - } - public func PUSH_PINNED_GEO(_ _1: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[2980]!, self._r[2980]!, [_1]) } - public var AuthSessions_IncompleteAttempts: String { return self._s[2982]! } - public var Passport_Address_Region: String { return self._s[2985]! } - public var ChatList_DeleteChat: String { return self._s[2986]! } - public var LogoutOptions_ClearCacheTitle: String { return self._s[2987]! } - public var PhotoEditor_TiltShift: String { return self._s[2988]! } - public var Settings_FAQ_URL: String { return self._s[2989]! } - public var Passport_Language_sl: String { return self._s[2990]! } - public var Settings_PrivacySettings: String { return self._s[2992]! } - public var SharedMedia_TitleLink: String { return self._s[2993]! } - public var Passport_Identity_TypePassportUploadScan: String { return self._s[2994]! } - public var Settings_SetProfilePhoto: String { return self._s[2995]! } - public var Channel_About_Help: String { return self._s[2996]! } - public var Contacts_PermissionsEnable: String { return self._s[2997]! } - public var Wallet_Sending_Title: String { return self._s[2998]! } - public var SettingsSearch_Synonyms_Notifications_GroupNotificationsAlert: String { return self._s[2999]! } - public var AttachmentMenu_SendAsFiles: String { return self._s[3000]! } - public var CallFeedback_ReasonInterruption: String { return self._s[3002]! } - public var Passport_Address_AddTemporaryRegistration: String { return self._s[3003]! } - public var AutoDownloadSettings_AutodownloadVideos: String { return self._s[3004]! } - public var ChatSettings_AutoDownloadSettings_Delimeter: String { return self._s[3005]! } - public var PrivacySettings_DeleteAccountTitle: String { return self._s[3006]! } - public var AccessDenied_VideoMessageCamera: String { return self._s[3008]! } - public var Map_OpenInYandexMaps: String { return self._s[3010]! } - public var CreateGroup_ErrorLocatedGroupsTooMuch: String { return self._s[3011]! } - public var VoiceOver_MessageContextReply: String { return self._s[3012]! } - public var PhotoEditor_SaturationTool: String { return self._s[3013]! } + public var Notifications_ExceptionsNone: String { return self._s[2981]! } + public func Message_ForwardedMessageShort(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[2982]!, self._r[2982]!, [_0]) + } + public func PUSH_PINNED_GEO(_ _1: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[2983]!, self._r[2983]!, [_1]) + } + public var AuthSessions_IncompleteAttempts: String { return self._s[2985]! } + public var Passport_Address_Region: String { return self._s[2988]! } + public var ChatList_DeleteChat: String { return self._s[2989]! } + public var LogoutOptions_ClearCacheTitle: String { return self._s[2990]! } + public var PhotoEditor_TiltShift: String { return self._s[2991]! } + public var Settings_FAQ_URL: String { return self._s[2992]! } + public var Passport_Language_sl: String { return self._s[2993]! } + public var Settings_PrivacySettings: String { return self._s[2995]! } + public var SharedMedia_TitleLink: String { return self._s[2996]! } + public var Passport_Identity_TypePassportUploadScan: String { return self._s[2997]! } + public var Settings_SetProfilePhoto: String { return self._s[2998]! } + public var Channel_About_Help: String { return self._s[2999]! } + public var Contacts_PermissionsEnable: String { return self._s[3000]! } + public var Wallet_Sending_Title: String { return self._s[3001]! } + public var SettingsSearch_Synonyms_Notifications_GroupNotificationsAlert: String { return self._s[3002]! } + public var AttachmentMenu_SendAsFiles: String { return self._s[3003]! } + public var CallFeedback_ReasonInterruption: String { return self._s[3005]! } + public var Passport_Address_AddTemporaryRegistration: String { return self._s[3006]! } + public var AutoDownloadSettings_AutodownloadVideos: String { return self._s[3007]! } + public var ChatSettings_AutoDownloadSettings_Delimeter: String { return self._s[3008]! } + public var PrivacySettings_DeleteAccountTitle: String { return self._s[3009]! } + public var AccessDenied_VideoMessageCamera: String { return self._s[3011]! } + public var Map_OpenInYandexMaps: String { return self._s[3013]! } + public var CreateGroup_ErrorLocatedGroupsTooMuch: String { return self._s[3014]! } + public var VoiceOver_MessageContextReply: String { return self._s[3015]! } + public var PhotoEditor_SaturationTool: String { return self._s[3016]! } public func PUSH_MESSAGE_STICKER(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3014]!, self._r[3014]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3017]!, self._r[3017]!, [_1, _2]) } - public var PrivacyPhoneNumberSettings_CustomHelp: String { return self._s[3015]! } - public var Notification_Exceptions_NewException_NotificationHeader: String { return self._s[3016]! } - public var Group_OwnershipTransfer_ErrorLocatedGroupsTooMuch: String { return self._s[3017]! } - public var Appearance_TextSize: String { return self._s[3018]! } + public var PrivacyPhoneNumberSettings_CustomHelp: String { return self._s[3018]! } + public var Notification_Exceptions_NewException_NotificationHeader: String { return self._s[3019]! } + public var Wallet_Send_NetworkError: String { return self._s[3020]! } + public var Group_OwnershipTransfer_ErrorLocatedGroupsTooMuch: String { return self._s[3021]! } + public var Appearance_TextSize: String { return self._s[3022]! } public func LOCAL_MESSAGE_FWDS(_ _1: String, _ _2: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3019]!, self._r[3019]!, [_1, "\(_2)"]) + return formatWithArgumentRanges(self._s[3023]!, self._r[3023]!, [_1, "\(_2)"]) } - public var Appearance_ThemePreview_ChatList_2_Text: String { return self._s[3020]! } - public var Channel_Username_InvalidTooShort: String { return self._s[3022]! } + public var Appearance_ThemePreview_ChatList_2_Text: String { return self._s[3024]! } + public var Channel_Username_InvalidTooShort: String { return self._s[3026]! } public func Group_OwnershipTransfer_DescriptionInfo(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3023]!, self._r[3023]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3027]!, self._r[3027]!, [_1, _2]) } public func PUSH_CHAT_MESSAGE_GAME(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3024]!, self._r[3024]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3028]!, self._r[3028]!, [_1, _2, _3]) } - public var GroupInfo_PublicLinkAdd: String { return self._s[3025]! } - public var Passport_PassportInformation: String { return self._s[3028]! } - public var Theme_Unsupported: String { return self._s[3029]! } - public var WatchRemote_AlertTitle: String { return self._s[3030]! } - public var Privacy_GroupsAndChannels_NeverAllow: String { return self._s[3031]! } - public var ConvertToSupergroup_HelpText: String { return self._s[3033]! } + public var GroupInfo_PublicLinkAdd: String { return self._s[3029]! } + public var Passport_PassportInformation: String { return self._s[3032]! } + public var Theme_Unsupported: String { return self._s[3033]! } + public var WatchRemote_AlertTitle: String { return self._s[3034]! } + public var Privacy_GroupsAndChannels_NeverAllow: String { return self._s[3035]! } + public var ConvertToSupergroup_HelpText: String { return self._s[3037]! } public func Time_MonthOfYear_m7(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3034]!, self._r[3034]!, [_0]) + return formatWithArgumentRanges(self._s[3038]!, self._r[3038]!, [_0]) } public func PUSH_PHONE_CALL_REQUEST(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3035]!, self._r[3035]!, [_1]) + return formatWithArgumentRanges(self._s[3039]!, self._r[3039]!, [_1]) } - public var Privacy_GroupsAndChannels_CustomHelp: String { return self._s[3036]! } - public var TwoStepAuth_RecoveryCodeInvalid: String { return self._s[3038]! } - public var AccessDenied_CameraDisabled: String { return self._s[3039]! } + public var Privacy_GroupsAndChannels_CustomHelp: String { return self._s[3040]! } + public var TwoStepAuth_RecoveryCodeInvalid: String { return self._s[3042]! } + public var AccessDenied_CameraDisabled: String { return self._s[3043]! } public func Channel_Username_UsernameIsAvailable(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3040]!, self._r[3040]!, [_0]) + return formatWithArgumentRanges(self._s[3044]!, self._r[3044]!, [_0]) } - public var PhotoEditor_ContrastTool: String { return self._s[3043]! } + public var PhotoEditor_ContrastTool: String { return self._s[3047]! } public func PUSH_PINNED_DOC(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3044]!, self._r[3044]!, [_1]) + return formatWithArgumentRanges(self._s[3048]!, self._r[3048]!, [_1]) } - public var DialogList_Draft: String { return self._s[3045]! } - public var Privacy_TopPeersDelete: String { return self._s[3047]! } - public var LoginPassword_PasswordPlaceholder: String { return self._s[3048]! } - public var Passport_Identity_TypeIdentityCardUploadScan: String { return self._s[3049]! } - public var WebSearch_RecentSectionClear: String { return self._s[3050]! } - public var EditTheme_ErrorInvalidCharacters: String { return self._s[3051]! } - public var Watch_ChatList_NoConversationsTitle: String { return self._s[3053]! } - public var Common_Done: String { return self._s[3055]! } - public var AuthSessions_EmptyText: String { return self._s[3056]! } - public var Conversation_ShareBotContactConfirmation: String { return self._s[3057]! } - public var Tour_Title5: String { return self._s[3058]! } - public var Wallet_Settings_Title: String { return self._s[3059]! } + public var DialogList_Draft: String { return self._s[3049]! } + public var Privacy_TopPeersDelete: String { return self._s[3051]! } + public var LoginPassword_PasswordPlaceholder: String { return self._s[3052]! } + public var Passport_Identity_TypeIdentityCardUploadScan: String { return self._s[3053]! } + public var WebSearch_RecentSectionClear: String { return self._s[3054]! } + public var EditTheme_ErrorInvalidCharacters: String { return self._s[3055]! } + public var Watch_ChatList_NoConversationsTitle: String { return self._s[3057]! } + public var Common_Done: String { return self._s[3059]! } + public var AuthSessions_EmptyText: String { return self._s[3060]! } + public var Conversation_ShareBotContactConfirmation: String { return self._s[3061]! } + public var Tour_Title5: String { return self._s[3062]! } + public var Wallet_Settings_Title: String { return self._s[3063]! } public func Map_DirectionsDriveEta(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3060]!, self._r[3060]!, [_0]) + return formatWithArgumentRanges(self._s[3064]!, self._r[3064]!, [_0]) } - public var ApplyLanguage_UnsufficientDataTitle: String { return self._s[3061]! } - public var Conversation_LinkDialogSave: String { return self._s[3062]! } - public var GroupInfo_ActionRestrict: String { return self._s[3063]! } - public var Checkout_Title: String { return self._s[3064]! } - public var Channel_DiscussionGroup_HeaderLabel: String { return self._s[3066]! } - public var Channel_AdminLog_CanChangeInfo: String { return self._s[3068]! } - public var Notification_RenamedGroup: String { return self._s[3069]! } - public var PeopleNearby_Groups: String { return self._s[3070]! } - public var Checkout_PayWithFaceId: String { return self._s[3071]! } - public var Channel_BanList_BlockedTitle: String { return self._s[3072]! } - public var SettingsSearch_Synonyms_Notifications_InAppNotificationsSound: String { return self._s[3074]! } - public var Checkout_WebConfirmation_Title: String { return self._s[3075]! } - public var Notifications_MessageNotificationsAlert: String { return self._s[3076]! } + public var ApplyLanguage_UnsufficientDataTitle: String { return self._s[3065]! } + public var Conversation_LinkDialogSave: String { return self._s[3066]! } + public var GroupInfo_ActionRestrict: String { return self._s[3067]! } + public var Checkout_Title: String { return self._s[3068]! } + public var Channel_DiscussionGroup_HeaderLabel: String { return self._s[3070]! } + public var Channel_AdminLog_CanChangeInfo: String { return self._s[3072]! } + public var Notification_RenamedGroup: String { return self._s[3073]! } + public var PeopleNearby_Groups: String { return self._s[3074]! } + public var Checkout_PayWithFaceId: String { return self._s[3075]! } + public var Channel_BanList_BlockedTitle: String { return self._s[3076]! } + public var SettingsSearch_Synonyms_Notifications_InAppNotificationsSound: String { return self._s[3078]! } + public var Checkout_WebConfirmation_Title: String { return self._s[3079]! } + public var Notifications_MessageNotificationsAlert: String { return self._s[3080]! } public func Activity_RemindAboutGroup(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3077]!, self._r[3077]!, [_0]) + return formatWithArgumentRanges(self._s[3081]!, self._r[3081]!, [_0]) } - public var Profile_AddToExisting: String { return self._s[3079]! } + public var Profile_AddToExisting: String { return self._s[3083]! } public func Profile_CreateEncryptedChatOutdatedError(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3080]!, self._r[3080]!, [_0, _1]) + return formatWithArgumentRanges(self._s[3084]!, self._r[3084]!, [_0, _1]) } - public var Cache_Files: String { return self._s[3082]! } - public var Permissions_PrivacyPolicy: String { return self._s[3083]! } - public var SocksProxySetup_ConnectAndSave: String { return self._s[3084]! } - public var UserInfo_NotificationsDefaultDisabled: String { return self._s[3085]! } - public var AutoDownloadSettings_TypeContacts: String { return self._s[3087]! } - public var Appearance_ThemePreview_ChatList_1_Text: String { return self._s[3089]! } - public var Calls_NoCallsPlaceholder: String { return self._s[3090]! } - public var Channel_Username_RevokeExistingUsernamesInfo: String { return self._s[3091]! } - public var VoiceOver_AttachMedia: String { return self._s[3093]! } - public var Notifications_ExceptionsGroupPlaceholder: String { return self._s[3094]! } + public var Cache_Files: String { return self._s[3086]! } + public var Permissions_PrivacyPolicy: String { return self._s[3087]! } + public var SocksProxySetup_ConnectAndSave: String { return self._s[3088]! } + public var UserInfo_NotificationsDefaultDisabled: String { return self._s[3089]! } + public var AutoDownloadSettings_TypeContacts: String { return self._s[3091]! } + public var Appearance_ThemePreview_ChatList_1_Text: String { return self._s[3093]! } + public var Calls_NoCallsPlaceholder: String { return self._s[3094]! } + public var Channel_Username_RevokeExistingUsernamesInfo: String { return self._s[3095]! } + public var VoiceOver_AttachMedia: String { return self._s[3097]! } + public var Notifications_ExceptionsGroupPlaceholder: String { return self._s[3098]! } public func PUSH_CHAT_MESSAGE_INVOICE(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3095]!, self._r[3095]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3099]!, self._r[3099]!, [_1, _2, _3]) } - public var SettingsSearch_Synonyms_Notifications_GroupNotificationsSound: String { return self._s[3096]! } - public var Conversation_SetReminder_Title: String { return self._s[3097]! } - public var Passport_FieldAddressHelp: String { return self._s[3098]! } - public var Privacy_GroupsAndChannels_InviteToChannelMultipleError: String { return self._s[3099]! } - public var PUSH_REMINDER_TITLE: String { return self._s[3100]! } + public var SettingsSearch_Synonyms_Notifications_GroupNotificationsSound: String { return self._s[3100]! } + public var Conversation_SetReminder_Title: String { return self._s[3101]! } + public var Passport_FieldAddressHelp: String { return self._s[3102]! } + public var Privacy_GroupsAndChannels_InviteToChannelMultipleError: String { return self._s[3103]! } + public var PUSH_REMINDER_TITLE: String { return self._s[3104]! } public func Login_TermsOfService_ProceedBot(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3101]!, self._r[3101]!, [_0]) + return formatWithArgumentRanges(self._s[3105]!, self._r[3105]!, [_0]) } - public var Channel_AdminLog_EmptyTitle: String { return self._s[3102]! } - public var Privacy_Calls_NeverAllow_Title: String { return self._s[3103]! } - public var Login_UnknownError: String { return self._s[3104]! } - public var Group_UpgradeNoticeText2: String { return self._s[3107]! } - public var Watch_Compose_AddContact: String { return self._s[3108]! } - public var Web_Error: String { return self._s[3109]! } - public var Gif_Search: String { return self._s[3110]! } - public var Profile_MessageLifetime1h: String { return self._s[3111]! } - public var CheckoutInfo_ReceiverInfoEmailPlaceholder: String { return self._s[3112]! } - public var Channel_Username_CheckingUsername: String { return self._s[3113]! } - public var CallFeedback_ReasonSilentRemote: String { return self._s[3114]! } - public var AutoDownloadSettings_TypeChannels: String { return self._s[3115]! } - public var Channel_AboutItem: String { return self._s[3116]! } - public var Privacy_GroupsAndChannels_AlwaysAllow_Placeholder: String { return self._s[3118]! } - public var VoiceOver_Chat_VoiceMessage: String { return self._s[3119]! } - public var GroupInfo_SharedMedia: String { return self._s[3120]! } + public var Channel_AdminLog_EmptyTitle: String { return self._s[3106]! } + public var Privacy_Calls_NeverAllow_Title: String { return self._s[3107]! } + public var Login_UnknownError: String { return self._s[3108]! } + public var Group_UpgradeNoticeText2: String { return self._s[3111]! } + public var Watch_Compose_AddContact: String { return self._s[3112]! } + public var Web_Error: String { return self._s[3113]! } + public var Gif_Search: String { return self._s[3114]! } + public var Profile_MessageLifetime1h: String { return self._s[3115]! } + public var CheckoutInfo_ReceiverInfoEmailPlaceholder: String { return self._s[3116]! } + public var Channel_Username_CheckingUsername: String { return self._s[3117]! } + public var CallFeedback_ReasonSilentRemote: String { return self._s[3118]! } + public var AutoDownloadSettings_TypeChannels: String { return self._s[3119]! } + public var Channel_AboutItem: String { return self._s[3120]! } + public var Privacy_GroupsAndChannels_AlwaysAllow_Placeholder: String { return self._s[3122]! } + public var VoiceOver_Chat_VoiceMessage: String { return self._s[3123]! } + public var GroupInfo_SharedMedia: String { return self._s[3124]! } public func Channel_AdminLog_MessagePromotedName(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3121]!, self._r[3121]!, [_1]) + return formatWithArgumentRanges(self._s[3125]!, self._r[3125]!, [_1]) } - public var Call_PhoneCallInProgressMessage: String { return self._s[3122]! } + public var Call_PhoneCallInProgressMessage: String { return self._s[3126]! } public func PUSH_CHANNEL_ALBUM(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3123]!, self._r[3123]!, [_1]) + return formatWithArgumentRanges(self._s[3127]!, self._r[3127]!, [_1]) } - public var ChatList_UndoArchiveRevealedText: String { return self._s[3124]! } - public var GroupInfo_InviteLink_RevokeAlert_Text: String { return self._s[3125]! } - public var Conversation_SearchByName_Placeholder: String { return self._s[3126]! } - public var CreatePoll_AddOption: String { return self._s[3127]! } - public var GroupInfo_Permissions_SearchPlaceholder: String { return self._s[3128]! } - public var Group_UpgradeNoticeHeader: String { return self._s[3129]! } - public var Channel_Management_AddModerator: String { return self._s[3130]! } - public var AutoDownloadSettings_MaxFileSize: String { return self._s[3131]! } - public var StickerPacksSettings_ShowStickersButton: String { return self._s[3132]! } - public var NotificationsSound_Hello: String { return self._s[3133]! } - public var SocksProxySetup_SavedProxies: String { return self._s[3134]! } - public var Channel_Stickers_Placeholder: String { return self._s[3136]! } + public var ChatList_UndoArchiveRevealedText: String { return self._s[3128]! } + public var GroupInfo_InviteLink_RevokeAlert_Text: String { return self._s[3129]! } + public var Conversation_SearchByName_Placeholder: String { return self._s[3130]! } + public var CreatePoll_AddOption: String { return self._s[3131]! } + public var GroupInfo_Permissions_SearchPlaceholder: String { return self._s[3132]! } + public var Group_UpgradeNoticeHeader: String { return self._s[3133]! } + public var Channel_Management_AddModerator: String { return self._s[3134]! } + public var AutoDownloadSettings_MaxFileSize: String { return self._s[3135]! } + public var StickerPacksSettings_ShowStickersButton: String { return self._s[3136]! } + public var Wallet_Info_RefreshErrorNetworkText: String { return self._s[3137]! } + public var NotificationsSound_Hello: String { return self._s[3138]! } + public var SocksProxySetup_SavedProxies: String { return self._s[3139]! } + public var Channel_Stickers_Placeholder: String { return self._s[3141]! } public func Login_EmailCodeBody(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3137]!, self._r[3137]!, [_0]) + return formatWithArgumentRanges(self._s[3142]!, self._r[3142]!, [_0]) } - public var PrivacyPolicy_DeclineDeclineAndDelete: String { return self._s[3138]! } - public var Channel_Management_AddModeratorHelp: String { return self._s[3139]! } - public var ContactInfo_BirthdayLabel: String { return self._s[3140]! } - public var ChangePhoneNumberCode_RequestingACall: String { return self._s[3141]! } - public var AutoDownloadSettings_Channels: String { return self._s[3142]! } - public var Passport_Language_mn: String { return self._s[3143]! } - public var Notifications_ResetAllNotificationsHelp: String { return self._s[3146]! } - public var GroupInfo_Permissions_SlowmodeValue_Off: String { return self._s[3147]! } - public var Passport_Language_ja: String { return self._s[3149]! } - public var Settings_About_Title: String { return self._s[3150]! } - public var Settings_NotificationsAndSounds: String { return self._s[3151]! } - public var ChannelInfo_DeleteGroup: String { return self._s[3152]! } - public var Settings_BlockedUsers: String { return self._s[3153]! } + public var PrivacyPolicy_DeclineDeclineAndDelete: String { return self._s[3143]! } + public var Channel_Management_AddModeratorHelp: String { return self._s[3144]! } + public var ContactInfo_BirthdayLabel: String { return self._s[3145]! } + public var ChangePhoneNumberCode_RequestingACall: String { return self._s[3146]! } + public var AutoDownloadSettings_Channels: String { return self._s[3147]! } + public var Passport_Language_mn: String { return self._s[3148]! } + public var Notifications_ResetAllNotificationsHelp: String { return self._s[3151]! } + public var GroupInfo_Permissions_SlowmodeValue_Off: String { return self._s[3152]! } + public var Passport_Language_ja: String { return self._s[3154]! } + public var Settings_About_Title: String { return self._s[3155]! } + public var Settings_NotificationsAndSounds: String { return self._s[3156]! } + public var ChannelInfo_DeleteGroup: String { return self._s[3157]! } + public var Settings_BlockedUsers: String { return self._s[3158]! } public func Time_MonthOfYear_m4(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3154]!, self._r[3154]!, [_0]) - } - public var EditTheme_Create_Preview_OutgoingText: String { return self._s[3155]! } - public var AutoDownloadSettings_PreloadVideo: String { return self._s[3156]! } - public var Passport_Address_AddResidentialAddress: String { return self._s[3157]! } - public var Channel_Username_Title: String { return self._s[3158]! } - public func Notification_RemovedGroupPhoto(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[3159]!, self._r[3159]!, [_0]) } - public var AttachmentMenu_File: String { return self._s[3161]! } - public var AppleWatch_Title: String { return self._s[3162]! } - public var Activity_RecordingVideoMessage: String { return self._s[3163]! } + public var EditTheme_Create_Preview_OutgoingText: String { return self._s[3160]! } + public var AutoDownloadSettings_PreloadVideo: String { return self._s[3161]! } + public var Passport_Address_AddResidentialAddress: String { return self._s[3162]! } + public var Channel_Username_Title: String { return self._s[3163]! } + public func Notification_RemovedGroupPhoto(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3164]!, self._r[3164]!, [_0]) + } + public var AttachmentMenu_File: String { return self._s[3166]! } + public var AppleWatch_Title: String { return self._s[3167]! } + public var Activity_RecordingVideoMessage: String { return self._s[3168]! } public func Channel_DiscussionGroup_PublicChannelLink(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3164]!, self._r[3164]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3169]!, self._r[3169]!, [_1, _2]) } - public var Weekday_Saturday: String { return self._s[3165]! } - public var WallpaperPreview_SwipeColorsTopText: String { return self._s[3166]! } - public var Profile_CreateEncryptedChatError: String { return self._s[3167]! } - public var Common_Next: String { return self._s[3169]! } - public var Channel_Stickers_YourStickers: String { return self._s[3171]! } - public var Message_Theme: String { return self._s[3172]! } - public var Call_AudioRouteHeadphones: String { return self._s[3173]! } - public var TwoStepAuth_EnterPasswordForgot: String { return self._s[3175]! } - public var Watch_Contacts_NoResults: String { return self._s[3177]! } - public var PhotoEditor_TintTool: String { return self._s[3180]! } - public var LoginPassword_ResetAccount: String { return self._s[3182]! } - public var Settings_SavedMessages: String { return self._s[3183]! } - public var SettingsSearch_Synonyms_Appearance_Animations: String { return self._s[3184]! } - public var Bot_GenericSupportStatus: String { return self._s[3185]! } - public var StickerPack_Add: String { return self._s[3186]! } - public var Checkout_TotalAmount: String { return self._s[3187]! } - public var Your_cards_number_is_invalid: String { return self._s[3188]! } - public var SettingsSearch_Synonyms_Appearance_AutoNightTheme: String { return self._s[3189]! } - public var VoiceOver_Chat_VideoMessage: String { return self._s[3190]! } + public var Weekday_Saturday: String { return self._s[3170]! } + public var WallpaperPreview_SwipeColorsTopText: String { return self._s[3171]! } + public var Profile_CreateEncryptedChatError: String { return self._s[3172]! } + public var Common_Next: String { return self._s[3174]! } + public var Channel_Stickers_YourStickers: String { return self._s[3176]! } + public var Message_Theme: String { return self._s[3177]! } + public var Call_AudioRouteHeadphones: String { return self._s[3178]! } + public var TwoStepAuth_EnterPasswordForgot: String { return self._s[3180]! } + public var Watch_Contacts_NoResults: String { return self._s[3182]! } + public var PhotoEditor_TintTool: String { return self._s[3185]! } + public var LoginPassword_ResetAccount: String { return self._s[3187]! } + public var Settings_SavedMessages: String { return self._s[3188]! } + public var SettingsSearch_Synonyms_Appearance_Animations: String { return self._s[3189]! } + public var Bot_GenericSupportStatus: String { return self._s[3190]! } + public var StickerPack_Add: String { return self._s[3191]! } + public var Checkout_TotalAmount: String { return self._s[3192]! } + public var Your_cards_number_is_invalid: String { return self._s[3193]! } + public var SettingsSearch_Synonyms_Appearance_AutoNightTheme: String { return self._s[3194]! } + public var VoiceOver_Chat_VideoMessage: String { return self._s[3195]! } public func ChangePhoneNumberCode_CallTimer(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3191]!, self._r[3191]!, [_0]) - } - public func GroupPermission_AddedInfo(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3192]!, self._r[3192]!, [_1, _2]) - } - public var ChatSettings_ConnectionType_UseSocks5: String { return self._s[3193]! } - public func PUSH_CHAT_PHOTO_EDITED(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3195]!, self._r[3195]!, [_1, _2]) - } - public func Conversation_RestrictedTextTimed(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[3196]!, self._r[3196]!, [_0]) } - public var GroupInfo_InviteLink_ShareLink: String { return self._s[3197]! } - public var StickerPack_Share: String { return self._s[3198]! } - public var Passport_DeleteAddress: String { return self._s[3199]! } - public var Settings_Passport: String { return self._s[3200]! } - public var SharedMedia_EmptyFilesText: String { return self._s[3201]! } - public var Conversation_DeleteMessagesForMe: String { return self._s[3202]! } - public var PasscodeSettings_AutoLock_IfAwayFor_1hour: String { return self._s[3203]! } - public var Contacts_PermissionsText: String { return self._s[3204]! } - public var Group_Setup_HistoryVisible: String { return self._s[3205]! } - public var Passport_Address_AddRentalAgreement: String { return self._s[3207]! } - public var SocksProxySetup_Title: String { return self._s[3208]! } - public var Notification_Mute1h: String { return self._s[3209]! } + public func GroupPermission_AddedInfo(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3197]!, self._r[3197]!, [_1, _2]) + } + public var ChatSettings_ConnectionType_UseSocks5: String { return self._s[3198]! } + public func PUSH_CHAT_PHOTO_EDITED(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3200]!, self._r[3200]!, [_1, _2]) + } + public func Conversation_RestrictedTextTimed(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3201]!, self._r[3201]!, [_0]) + } + public var GroupInfo_InviteLink_ShareLink: String { return self._s[3202]! } + public var StickerPack_Share: String { return self._s[3203]! } + public var Passport_DeleteAddress: String { return self._s[3204]! } + public var Settings_Passport: String { return self._s[3205]! } + public var SharedMedia_EmptyFilesText: String { return self._s[3206]! } + public var Conversation_DeleteMessagesForMe: String { return self._s[3207]! } + public var PasscodeSettings_AutoLock_IfAwayFor_1hour: String { return self._s[3208]! } + public var Contacts_PermissionsText: String { return self._s[3209]! } + public var Group_Setup_HistoryVisible: String { return self._s[3210]! } + public var Passport_Address_AddRentalAgreement: String { return self._s[3212]! } + public var SocksProxySetup_Title: String { return self._s[3213]! } + public var Notification_Mute1h: String { return self._s[3214]! } public func Passport_Email_CodeHelp(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3210]!, self._r[3210]!, [_0]) + return formatWithArgumentRanges(self._s[3215]!, self._r[3215]!, [_0]) } - public var NotificationSettings_ShowNotificationsAllAccountsInfoOff: String { return self._s[3212]! } + public var NotificationSettings_ShowNotificationsAllAccountsInfoOff: String { return self._s[3217]! } public func PUSH_PINNED_GEOLIVE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3213]!, self._r[3213]!, [_1]) + return formatWithArgumentRanges(self._s[3218]!, self._r[3218]!, [_1]) } - public var FastTwoStepSetup_PasswordSection: String { return self._s[3214]! } - public var NetworkUsageSettings_ResetStatsConfirmation: String { return self._s[3217]! } - public var InfoPlist_NSFaceIDUsageDescription: String { return self._s[3219]! } - public var DialogList_NoMessagesText: String { return self._s[3220]! } - public var Privacy_ContactsResetConfirmation: String { return self._s[3221]! } - public var Privacy_Calls_P2PHelp: String { return self._s[3222]! } - public var Channel_DiscussionGroup_SearchPlaceholder: String { return self._s[3224]! } - public var Your_cards_expiration_year_is_invalid: String { return self._s[3225]! } - public var Common_TakePhotoOrVideo: String { return self._s[3226]! } - public var Wallet_Words_Text: String { return self._s[3227]! } - public var Call_StatusBusy: String { return self._s[3228]! } - public var Conversation_PinnedMessage: String { return self._s[3229]! } - public var AutoDownloadSettings_VoiceMessagesTitle: String { return self._s[3230]! } - public var TwoStepAuth_SetupPasswordConfirmFailed: String { return self._s[3231]! } - public var Undo_ChatCleared: String { return self._s[3232]! } - public var AppleWatch_ReplyPresets: String { return self._s[3233]! } - public var Passport_DiscardMessageDescription: String { return self._s[3235]! } - public var Login_NetworkError: String { return self._s[3236]! } + public var FastTwoStepSetup_PasswordSection: String { return self._s[3219]! } + public var NetworkUsageSettings_ResetStatsConfirmation: String { return self._s[3222]! } + public var InfoPlist_NSFaceIDUsageDescription: String { return self._s[3224]! } + public var DialogList_NoMessagesText: String { return self._s[3225]! } + public var Privacy_ContactsResetConfirmation: String { return self._s[3226]! } + public var Privacy_Calls_P2PHelp: String { return self._s[3227]! } + public var Channel_DiscussionGroup_SearchPlaceholder: String { return self._s[3229]! } + public var Your_cards_expiration_year_is_invalid: String { return self._s[3230]! } + public var Common_TakePhotoOrVideo: String { return self._s[3231]! } + public var Wallet_Words_Text: String { return self._s[3232]! } + public var Call_StatusBusy: String { return self._s[3233]! } + public var Conversation_PinnedMessage: String { return self._s[3234]! } + public var AutoDownloadSettings_VoiceMessagesTitle: String { return self._s[3235]! } + public var TwoStepAuth_SetupPasswordConfirmFailed: String { return self._s[3236]! } + public var Undo_ChatCleared: String { return self._s[3237]! } + public var AppleWatch_ReplyPresets: String { return self._s[3238]! } + public var Passport_DiscardMessageDescription: String { return self._s[3240]! } + public var Login_NetworkError: String { return self._s[3241]! } public func Notification_PinnedRoundMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3237]!, self._r[3237]!, [_0]) + return formatWithArgumentRanges(self._s[3242]!, self._r[3242]!, [_0]) } public func Channel_AdminLog_MessageRemovedChannelUsername(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3238]!, self._r[3238]!, [_0]) + return formatWithArgumentRanges(self._s[3243]!, self._r[3243]!, [_0]) } - public var SocksProxySetup_PasswordPlaceholder: String { return self._s[3239]! } - public var Wallet_WordCheck_ViewWords: String { return self._s[3241]! } - public var Login_ResetAccountProtected_LimitExceeded: String { return self._s[3242]! } + public var SocksProxySetup_PasswordPlaceholder: String { return self._s[3244]! } + public var Wallet_WordCheck_ViewWords: String { return self._s[3246]! } + public var Login_ResetAccountProtected_LimitExceeded: String { return self._s[3247]! } public func Watch_LastSeen_YesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3244]!, self._r[3244]!, [_0]) + return formatWithArgumentRanges(self._s[3249]!, self._r[3249]!, [_0]) } - public var Call_ConnectionErrorMessage: String { return self._s[3245]! } - public var VoiceOver_Chat_Music: String { return self._s[3246]! } - public var SettingsSearch_Synonyms_Notifications_MessageNotificationsSound: String { return self._s[3247]! } - public var Compose_GroupTokenListPlaceholder: String { return self._s[3249]! } - public var ConversationMedia_Title: String { return self._s[3250]! } - public var EncryptionKey_Title: String { return self._s[3252]! } - public var TwoStepAuth_EnterPasswordTitle: String { return self._s[3253]! } - public var Notification_Exceptions_AddException: String { return self._s[3254]! } - public var PrivacySettings_BlockedPeersEmpty: String { return self._s[3255]! } - public var Profile_MessageLifetime1m: String { return self._s[3256]! } + public var Call_ConnectionErrorMessage: String { return self._s[3250]! } + public var VoiceOver_Chat_Music: String { return self._s[3251]! } + public var SettingsSearch_Synonyms_Notifications_MessageNotificationsSound: String { return self._s[3252]! } + public var Compose_GroupTokenListPlaceholder: String { return self._s[3254]! } + public var ConversationMedia_Title: String { return self._s[3255]! } + public var EncryptionKey_Title: String { return self._s[3257]! } + public var TwoStepAuth_EnterPasswordTitle: String { return self._s[3258]! } + public var Notification_Exceptions_AddException: String { return self._s[3259]! } + public var PrivacySettings_BlockedPeersEmpty: String { return self._s[3260]! } + public var Profile_MessageLifetime1m: String { return self._s[3261]! } public func Channel_AdminLog_MessageUnkickedName(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3257]!, self._r[3257]!, [_1]) + return formatWithArgumentRanges(self._s[3262]!, self._r[3262]!, [_1]) } - public var Month_GenMay: String { return self._s[3258]! } + public var Month_GenMay: String { return self._s[3263]! } public func LiveLocationUpdated_TodayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3259]!, self._r[3259]!, [_0]) + return formatWithArgumentRanges(self._s[3264]!, self._r[3264]!, [_0]) } - public var PeopleNearby_Users: String { return self._s[3260]! } - public var Wallet_Send_AddressInfo: String { return self._s[3261]! } - public var ChannelMembers_WhoCanAddMembersAllHelp: String { return self._s[3262]! } - public var AutoDownloadSettings_ResetSettings: String { return self._s[3263]! } - public var Conversation_EmptyPlaceholder: String { return self._s[3265]! } - public var Passport_Address_AddPassportRegistration: String { return self._s[3266]! } - public var Notifications_ChannelNotificationsAlert: String { return self._s[3267]! } - public var ChatSettings_AutoDownloadUsingCellular: String { return self._s[3268]! } - public var Camera_TapAndHoldForVideo: String { return self._s[3269]! } - public var Channel_JoinChannel: String { return self._s[3271]! } - public var Appearance_Animations: String { return self._s[3274]! } + public var PeopleNearby_Users: String { return self._s[3265]! } + public var Wallet_Send_AddressInfo: String { return self._s[3266]! } + public var ChannelMembers_WhoCanAddMembersAllHelp: String { return self._s[3267]! } + public var AutoDownloadSettings_ResetSettings: String { return self._s[3268]! } + public var Conversation_EmptyPlaceholder: String { return self._s[3270]! } + public var Passport_Address_AddPassportRegistration: String { return self._s[3271]! } + public var Notifications_ChannelNotificationsAlert: String { return self._s[3272]! } + public var ChatSettings_AutoDownloadUsingCellular: String { return self._s[3273]! } + public var Camera_TapAndHoldForVideo: String { return self._s[3274]! } + public var Channel_JoinChannel: String { return self._s[3276]! } + public var Appearance_Animations: String { return self._s[3279]! } public func Notification_MessageLifetimeChanged(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3275]!, self._r[3275]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3280]!, self._r[3280]!, [_1, _2]) } - public var Stickers_GroupStickers: String { return self._s[3277]! } - public var Appearance_ShareTheme: String { return self._s[3278]! } - public var ConvertToSupergroup_HelpTitle: String { return self._s[3280]! } - public var Passport_Address_Street: String { return self._s[3281]! } - public var Conversation_AddContact: String { return self._s[3282]! } - public var Login_PhonePlaceholder: String { return self._s[3283]! } - public var Channel_Members_InviteLink: String { return self._s[3285]! } - public var Bot_Stop: String { return self._s[3286]! } - public var SettingsSearch_Synonyms_Proxy_UseForCalls: String { return self._s[3288]! } - public var Notification_PassportValueAddress: String { return self._s[3289]! } - public var Month_ShortJuly: String { return self._s[3290]! } - public var Passport_Address_TypeTemporaryRegistrationUploadScan: String { return self._s[3291]! } - public var Channel_AdminLog_BanSendMedia: String { return self._s[3292]! } - public var Passport_Identity_ReverseSide: String { return self._s[3293]! } - public var Watch_Stickers_Recents: String { return self._s[3296]! } - public var PrivacyLastSeenSettings_EmpryUsersPlaceholder: String { return self._s[3298]! } - public var Map_SendThisLocation: String { return self._s[3299]! } + public var Stickers_GroupStickers: String { return self._s[3282]! } + public var Appearance_ShareTheme: String { return self._s[3283]! } + public var ConvertToSupergroup_HelpTitle: String { return self._s[3285]! } + public var Passport_Address_Street: String { return self._s[3286]! } + public var Conversation_AddContact: String { return self._s[3287]! } + public var Login_PhonePlaceholder: String { return self._s[3288]! } + public var Channel_Members_InviteLink: String { return self._s[3290]! } + public var Bot_Stop: String { return self._s[3291]! } + public var SettingsSearch_Synonyms_Proxy_UseForCalls: String { return self._s[3293]! } + public var Notification_PassportValueAddress: String { return self._s[3294]! } + public var Month_ShortJuly: String { return self._s[3295]! } + public var Passport_Address_TypeTemporaryRegistrationUploadScan: String { return self._s[3296]! } + public var Channel_AdminLog_BanSendMedia: String { return self._s[3297]! } + public var Passport_Identity_ReverseSide: String { return self._s[3298]! } + public var Watch_Stickers_Recents: String { return self._s[3301]! } + public var PrivacyLastSeenSettings_EmpryUsersPlaceholder: String { return self._s[3303]! } + public var Map_SendThisLocation: String { return self._s[3304]! } public func Time_MonthOfYear_m1(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3300]!, self._r[3300]!, [_0]) + return formatWithArgumentRanges(self._s[3305]!, self._r[3305]!, [_0]) } public func InviteText_SingleContact(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3301]!, self._r[3301]!, [_0]) + return formatWithArgumentRanges(self._s[3306]!, self._r[3306]!, [_0]) } - public var ConvertToSupergroup_Note: String { return self._s[3302]! } - public var Wallet_Intro_NotNow: String { return self._s[3303]! } + public var ConvertToSupergroup_Note: String { return self._s[3307]! } + public var Wallet_Intro_NotNow: String { return self._s[3308]! } public func FileSize_MB(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3304]!, self._r[3304]!, [_0]) + return formatWithArgumentRanges(self._s[3309]!, self._r[3309]!, [_0]) } - public var NetworkUsageSettings_GeneralDataSection: String { return self._s[3305]! } + public var NetworkUsageSettings_GeneralDataSection: String { return self._s[3310]! } public func Compatibility_SecretMediaVersionTooLow(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3306]!, self._r[3306]!, [_0, _1]) + return formatWithArgumentRanges(self._s[3311]!, self._r[3311]!, [_0, _1]) } - public var Login_CallRequestState3: String { return self._s[3308]! } - public var Wallpaper_SearchShort: String { return self._s[3309]! } - public var SettingsSearch_Synonyms_Appearance_ColorTheme: String { return self._s[3311]! } - public var PasscodeSettings_UnlockWithFaceId: String { return self._s[3312]! } - public var Channel_BotDoesntSupportGroups: String { return self._s[3313]! } + public var Login_CallRequestState3: String { return self._s[3313]! } + public var Wallpaper_SearchShort: String { return self._s[3314]! } + public var SettingsSearch_Synonyms_Appearance_ColorTheme: String { return self._s[3316]! } + public var PasscodeSettings_UnlockWithFaceId: String { return self._s[3317]! } + public var Channel_BotDoesntSupportGroups: String { return self._s[3318]! } public func PUSH_CHAT_MESSAGE_GEOLIVE(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3314]!, self._r[3314]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3319]!, self._r[3319]!, [_1, _2]) } - public var Channel_AdminLogFilter_Title: String { return self._s[3315]! } - public var Notifications_GroupNotificationsExceptions: String { return self._s[3320]! } + public var Channel_AdminLogFilter_Title: String { return self._s[3320]! } + public var Notifications_GroupNotificationsExceptions: String { return self._s[3325]! } public func FileSize_B(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3321]!, self._r[3321]!, [_0]) + return formatWithArgumentRanges(self._s[3326]!, self._r[3326]!, [_0]) } - public var Passport_CorrectErrors: String { return self._s[3322]! } - public var VoiceOver_Chat_YourAnonymousPoll: String { return self._s[3323]! } + public var Passport_CorrectErrors: String { return self._s[3327]! } + public var VoiceOver_Chat_YourAnonymousPoll: String { return self._s[3328]! } public func Channel_MessageTitleUpdated(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3324]!, self._r[3324]!, [_0]) + return formatWithArgumentRanges(self._s[3329]!, self._r[3329]!, [_0]) } - public var Map_SendMyCurrentLocation: String { return self._s[3325]! } - public var Channel_DiscussionGroup: String { return self._s[3326]! } + public var Map_SendMyCurrentLocation: String { return self._s[3330]! } + public var Channel_DiscussionGroup: String { return self._s[3331]! } public func PUSH_PINNED_CONTACT(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3327]!, self._r[3327]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3332]!, self._r[3332]!, [_1, _2]) } - public var SharedMedia_SearchNoResults: String { return self._s[3328]! } - public var Permissions_NotificationsText_v0: String { return self._s[3329]! } - public var Channel_EditAdmin_PermissionDeleteMessagesOfOthers: String { return self._s[3330]! } - public var Appearance_AppIcon: String { return self._s[3331]! } - public var Appearance_ThemePreview_ChatList_3_AuthorName: String { return self._s[3332]! } - public var LoginPassword_FloodError: String { return self._s[3333]! } - public var Group_Setup_HistoryHiddenHelp: String { return self._s[3335]! } + public var SharedMedia_SearchNoResults: String { return self._s[3333]! } + public var Permissions_NotificationsText_v0: String { return self._s[3334]! } + public var Channel_EditAdmin_PermissionDeleteMessagesOfOthers: String { return self._s[3335]! } + public var Appearance_AppIcon: String { return self._s[3336]! } + public var Appearance_ThemePreview_ChatList_3_AuthorName: String { return self._s[3337]! } + public var LoginPassword_FloodError: String { return self._s[3338]! } + public var Group_Setup_HistoryHiddenHelp: String { return self._s[3340]! } public func TwoStepAuth_PendingEmailHelp(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3336]!, self._r[3336]!, [_0]) - } - public var Passport_Language_bn: String { return self._s[3337]! } - public func DialogList_SingleUploadingPhotoSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3338]!, self._r[3338]!, [_0]) - } - public var ChatList_Context_Pin: String { return self._s[3339]! } - public func Notification_PinnedAudioMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3340]!, self._r[3340]!, [_0]) - } - public func Channel_AdminLog_MessageChangedGroupStickerPack(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[3341]!, self._r[3341]!, [_0]) } - public var GroupInfo_InvitationLinkGroupFull: String { return self._s[3344]! } - public var Group_EditAdmin_PermissionChangeInfo: String { return self._s[3346]! } - public var Contacts_PermissionsAllow: String { return self._s[3347]! } - public var ReportPeer_ReasonCopyright: String { return self._s[3348]! } - public var Channel_EditAdmin_PermissinAddAdminOn: String { return self._s[3349]! } - public var WallpaperPreview_Pattern: String { return self._s[3350]! } - public var Paint_Duplicate: String { return self._s[3351]! } - public var Passport_Address_Country: String { return self._s[3352]! } - public var Notification_RenamedChannel: String { return self._s[3354]! } - public var ChatList_Context_Unmute: String { return self._s[3355]! } - public var CheckoutInfo_ErrorPostcodeInvalid: String { return self._s[3356]! } - public var Group_MessagePhotoUpdated: String { return self._s[3357]! } - public var Channel_BanUser_PermissionSendMedia: String { return self._s[3358]! } - public var Conversation_ContextMenuBan: String { return self._s[3359]! } - public var TwoStepAuth_EmailSent: String { return self._s[3360]! } - public var MessagePoll_NoVotes: String { return self._s[3361]! } - public var Passport_Language_is: String { return self._s[3362]! } - public var PeopleNearby_UsersEmpty: String { return self._s[3364]! } - public var Tour_Text5: String { return self._s[3365]! } + public var Passport_Language_bn: String { return self._s[3342]! } + public func DialogList_SingleUploadingPhotoSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3343]!, self._r[3343]!, [_0]) + } + public var ChatList_Context_Pin: String { return self._s[3344]! } + public func Notification_PinnedAudioMessage(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3345]!, self._r[3345]!, [_0]) + } + public func Channel_AdminLog_MessageChangedGroupStickerPack(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3346]!, self._r[3346]!, [_0]) + } + public var GroupInfo_InvitationLinkGroupFull: String { return self._s[3349]! } + public var Group_EditAdmin_PermissionChangeInfo: String { return self._s[3351]! } + public var Contacts_PermissionsAllow: String { return self._s[3352]! } + public var ReportPeer_ReasonCopyright: String { return self._s[3353]! } + public var Channel_EditAdmin_PermissinAddAdminOn: String { return self._s[3354]! } + public var WallpaperPreview_Pattern: String { return self._s[3355]! } + public var Paint_Duplicate: String { return self._s[3356]! } + public var Passport_Address_Country: String { return self._s[3357]! } + public var Notification_RenamedChannel: String { return self._s[3359]! } + public var ChatList_Context_Unmute: String { return self._s[3360]! } + public var CheckoutInfo_ErrorPostcodeInvalid: String { return self._s[3361]! } + public var Group_MessagePhotoUpdated: String { return self._s[3362]! } + public var Channel_BanUser_PermissionSendMedia: String { return self._s[3363]! } + public var Conversation_ContextMenuBan: String { return self._s[3364]! } + public var TwoStepAuth_EmailSent: String { return self._s[3365]! } + public var MessagePoll_NoVotes: String { return self._s[3366]! } + public var Passport_Language_is: String { return self._s[3367]! } + public var PeopleNearby_UsersEmpty: String { return self._s[3369]! } + public var Tour_Text5: String { return self._s[3370]! } public func Call_GroupFormat(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3367]!, self._r[3367]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3372]!, self._r[3372]!, [_1, _2]) } - public var Undo_SecretChatDeleted: String { return self._s[3368]! } - public var SocksProxySetup_ShareQRCode: String { return self._s[3369]! } + public var Undo_SecretChatDeleted: String { return self._s[3373]! } + public var SocksProxySetup_ShareQRCode: String { return self._s[3374]! } public func VoiceOver_Chat_Size(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3370]!, self._r[3370]!, [_0]) + return formatWithArgumentRanges(self._s[3375]!, self._r[3375]!, [_0]) } - public var LogoutOptions_ChangePhoneNumberText: String { return self._s[3371]! } - public var Paint_Edit: String { return self._s[3373]! } - public var ScheduledMessages_ReminderNotification: String { return self._s[3375]! } - public var Undo_DeletedGroup: String { return self._s[3377]! } - public var LoginPassword_ForgotPassword: String { return self._s[3378]! } - public var Wallet_WordImport_IncorrectTitle: String { return self._s[3379]! } - public var GroupInfo_GroupNamePlaceholder: String { return self._s[3380]! } + public var LogoutOptions_ChangePhoneNumberText: String { return self._s[3376]! } + public var Paint_Edit: String { return self._s[3378]! } + public var ScheduledMessages_ReminderNotification: String { return self._s[3380]! } + public var Undo_DeletedGroup: String { return self._s[3382]! } + public var LoginPassword_ForgotPassword: String { return self._s[3383]! } + public var Wallet_WordImport_IncorrectTitle: String { return self._s[3384]! } + public var GroupInfo_GroupNamePlaceholder: String { return self._s[3385]! } public func Notification_Kicked(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3381]!, self._r[3381]!, [_0, _1]) + return formatWithArgumentRanges(self._s[3386]!, self._r[3386]!, [_0, _1]) } - public var Conversation_InputTextCaptionPlaceholder: String { return self._s[3382]! } - public var AutoDownloadSettings_VideoMessagesTitle: String { return self._s[3383]! } - public var Passport_Language_uz: String { return self._s[3384]! } - public var Conversation_PinMessageAlertGroup: String { return self._s[3385]! } - public var SettingsSearch_Synonyms_Privacy_GroupsAndChannels: String { return self._s[3386]! } - public var Map_StopLiveLocation: String { return self._s[3388]! } - public var VoiceOver_MessageContextSend: String { return self._s[3390]! } - public var PasscodeSettings_Help: String { return self._s[3391]! } - public var NotificationsSound_Input: String { return self._s[3392]! } - public var Share_Title: String { return self._s[3395]! } - public var LogoutOptions_Title: String { return self._s[3396]! } - public var Wallet_Send_AddressText: String { return self._s[3397]! } - public var Login_TermsOfServiceAgree: String { return self._s[3398]! } - public var Compose_NewEncryptedChatTitle: String { return self._s[3399]! } - public var Channel_AdminLog_TitleSelectedEvents: String { return self._s[3400]! } - public var Channel_EditAdmin_PermissionEditMessages: String { return self._s[3401]! } - public var EnterPasscode_EnterTitle: String { return self._s[3402]! } + public var Conversation_InputTextCaptionPlaceholder: String { return self._s[3387]! } + public var AutoDownloadSettings_VideoMessagesTitle: String { return self._s[3388]! } + public var Passport_Language_uz: String { return self._s[3389]! } + public var Conversation_PinMessageAlertGroup: String { return self._s[3390]! } + public var SettingsSearch_Synonyms_Privacy_GroupsAndChannels: String { return self._s[3391]! } + public var Map_StopLiveLocation: String { return self._s[3393]! } + public var VoiceOver_MessageContextSend: String { return self._s[3395]! } + public var PasscodeSettings_Help: String { return self._s[3396]! } + public var NotificationsSound_Input: String { return self._s[3397]! } + public var Share_Title: String { return self._s[3400]! } + public var LogoutOptions_Title: String { return self._s[3401]! } + public var Wallet_Send_AddressText: String { return self._s[3402]! } + public var Login_TermsOfServiceAgree: String { return self._s[3403]! } + public var Compose_NewEncryptedChatTitle: String { return self._s[3404]! } + public var Channel_AdminLog_TitleSelectedEvents: String { return self._s[3405]! } + public var Channel_EditAdmin_PermissionEditMessages: String { return self._s[3406]! } + public var EnterPasscode_EnterTitle: String { return self._s[3407]! } public func Call_PrivacyErrorMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3403]!, self._r[3403]!, [_0]) - } - public var Settings_CopyPhoneNumber: String { return self._s[3404]! } - public var Conversation_AddToContacts: String { return self._s[3405]! } - public func VoiceOver_Chat_ReplyFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3406]!, self._r[3406]!, [_0]) - } - public var NotificationsSound_Keys: String { return self._s[3407]! } - public func Call_ParticipantVersionOutdatedError(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[3408]!, self._r[3408]!, [_0]) } - public var Notification_MessageLifetime1w: String { return self._s[3409]! } - public var Message_Video: String { return self._s[3410]! } - public var AutoDownloadSettings_CellularTitle: String { return self._s[3411]! } - public func PUSH_CHANNEL_MESSAGE_PHOTO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3412]!, self._r[3412]!, [_1]) + public var Settings_CopyPhoneNumber: String { return self._s[3409]! } + public var Conversation_AddToContacts: String { return self._s[3410]! } + public func VoiceOver_Chat_ReplyFrom(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3411]!, self._r[3411]!, [_0]) } - public var Wallet_Receive_AmountInfo: String { return self._s[3415]! } + public var NotificationsSound_Keys: String { return self._s[3412]! } + public func Call_ParticipantVersionOutdatedError(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3413]!, self._r[3413]!, [_0]) + } + public var Notification_MessageLifetime1w: String { return self._s[3414]! } + public var Message_Video: String { return self._s[3415]! } + public var AutoDownloadSettings_CellularTitle: String { return self._s[3416]! } + public func PUSH_CHANNEL_MESSAGE_PHOTO(_ _1: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3417]!, self._r[3417]!, [_1]) + } + public var Wallet_Receive_AmountInfo: String { return self._s[3420]! } public func Notification_JoinedChat(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3416]!, self._r[3416]!, [_0]) + return formatWithArgumentRanges(self._s[3421]!, self._r[3421]!, [_0]) } public func PrivacySettings_LastSeenContactsPlus(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3417]!, self._r[3417]!, [_0]) + return formatWithArgumentRanges(self._s[3422]!, self._r[3422]!, [_0]) } - public var Passport_Language_mk: String { return self._s[3418]! } - public var CreatePoll_CancelConfirmation: String { return self._s[3419]! } - public var Conversation_SilentBroadcastTooltipOn: String { return self._s[3421]! } - public var PrivacyPolicy_Decline: String { return self._s[3422]! } - public var Passport_Identity_DoesNotExpire: String { return self._s[3423]! } - public var Channel_AdminLogFilter_EventsRestrictions: String { return self._s[3424]! } - public var Permissions_SiriAllow_v0: String { return self._s[3426]! } - public var Appearance_ThemeCarouselNight: String { return self._s[3427]! } + public var Passport_Language_mk: String { return self._s[3423]! } + public var CreatePoll_CancelConfirmation: String { return self._s[3424]! } + public var Conversation_SilentBroadcastTooltipOn: String { return self._s[3426]! } + public var PrivacyPolicy_Decline: String { return self._s[3427]! } + public var Passport_Identity_DoesNotExpire: String { return self._s[3428]! } + public var Channel_AdminLogFilter_EventsRestrictions: String { return self._s[3429]! } + public var Permissions_SiriAllow_v0: String { return self._s[3431]! } + public var Appearance_ThemeCarouselNight: String { return self._s[3432]! } public func LOCAL_CHAT_MESSAGE_FWDS(_ _1: String, _ _2: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3428]!, self._r[3428]!, [_1, "\(_2)"]) + return formatWithArgumentRanges(self._s[3433]!, self._r[3433]!, [_1, "\(_2)"]) } public func Notification_RenamedChat(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3429]!, self._r[3429]!, [_0]) + return formatWithArgumentRanges(self._s[3434]!, self._r[3434]!, [_0]) } - public var Paint_Regular: String { return self._s[3430]! } - public var ChatSettings_AutoDownloadReset: String { return self._s[3431]! } - public var SocksProxySetup_ShareLink: String { return self._s[3432]! } - public var Wallet_Qr_Title: String { return self._s[3433]! } - public var BlockedUsers_SelectUserTitle: String { return self._s[3434]! } - public var VoiceOver_Chat_RecordModeVoiceMessage: String { return self._s[3436]! } - public var GroupInfo_InviteByLink: String { return self._s[3437]! } - public var MessageTimer_Custom: String { return self._s[3438]! } - public var UserInfo_NotificationsDefaultEnabled: String { return self._s[3439]! } - public var Passport_Address_TypeTemporaryRegistration: String { return self._s[3441]! } - public var Conversation_SendMessage_SetReminder: String { return self._s[3442]! } - public var VoiceOver_Chat_Selected: String { return self._s[3443]! } - public var ChatSettings_AutoDownloadUsingWiFi: String { return self._s[3444]! } - public var Channel_Username_InvalidTaken: String { return self._s[3445]! } - public var Conversation_ClousStorageInfo_Description3: String { return self._s[3446]! } - public var Wallet_WordCheck_TryAgain: String { return self._s[3447]! } - public var Settings_ChatBackground: String { return self._s[3448]! } - public var Channel_Subscribers_Title: String { return self._s[3449]! } - public var Wallet_Receive_InvoiceUrlHeader: String { return self._s[3450]! } - public var ApplyLanguage_ChangeLanguageTitle: String { return self._s[3451]! } - public var Watch_ConnectionDescription: String { return self._s[3452]! } - public var ChatList_ArchivedChatsTitle: String { return self._s[3456]! } - public var Wallpaper_ResetWallpapers: String { return self._s[3457]! } - public var EditProfile_Title: String { return self._s[3458]! } - public var NotificationsSound_Bamboo: String { return self._s[3460]! } - public var Channel_AdminLog_MessagePreviousMessage: String { return self._s[3462]! } - public var Login_SmsRequestState2: String { return self._s[3463]! } - public var Passport_Language_ar: String { return self._s[3464]! } + public var Paint_Regular: String { return self._s[3435]! } + public var ChatSettings_AutoDownloadReset: String { return self._s[3436]! } + public var SocksProxySetup_ShareLink: String { return self._s[3437]! } + public var Wallet_Qr_Title: String { return self._s[3438]! } + public var BlockedUsers_SelectUserTitle: String { return self._s[3439]! } + public var VoiceOver_Chat_RecordModeVoiceMessage: String { return self._s[3441]! } + public var GroupInfo_InviteByLink: String { return self._s[3442]! } + public var MessageTimer_Custom: String { return self._s[3443]! } + public var UserInfo_NotificationsDefaultEnabled: String { return self._s[3444]! } + public var Passport_Address_TypeTemporaryRegistration: String { return self._s[3446]! } + public var Conversation_SendMessage_SetReminder: String { return self._s[3447]! } + public var VoiceOver_Chat_Selected: String { return self._s[3448]! } + public var ChatSettings_AutoDownloadUsingWiFi: String { return self._s[3449]! } + public var Channel_Username_InvalidTaken: String { return self._s[3450]! } + public var Conversation_ClousStorageInfo_Description3: String { return self._s[3451]! } + public var Wallet_WordCheck_TryAgain: String { return self._s[3452]! } + public var Settings_ChatBackground: String { return self._s[3453]! } + public var Channel_Subscribers_Title: String { return self._s[3454]! } + public var Wallet_Receive_InvoiceUrlHeader: String { return self._s[3455]! } + public var ApplyLanguage_ChangeLanguageTitle: String { return self._s[3456]! } + public var Watch_ConnectionDescription: String { return self._s[3457]! } + public var ChatList_ArchivedChatsTitle: String { return self._s[3461]! } + public var Wallpaper_ResetWallpapers: String { return self._s[3462]! } + public var EditProfile_Title: String { return self._s[3463]! } + public var NotificationsSound_Bamboo: String { return self._s[3465]! } + public var Channel_AdminLog_MessagePreviousMessage: String { return self._s[3467]! } + public var Login_SmsRequestState2: String { return self._s[3468]! } + public var Passport_Language_ar: String { return self._s[3469]! } public func Message_AuthorPinnedGame(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3465]!, self._r[3465]!, [_0]) + return formatWithArgumentRanges(self._s[3470]!, self._r[3470]!, [_0]) } - public var SettingsSearch_Synonyms_EditProfile_Title: String { return self._s[3466]! } - public var Wallet_Created_Text: String { return self._s[3467]! } - public var Conversation_MessageDialogEdit: String { return self._s[3468]! } - public var Wallet_Created_Proceed: String { return self._s[3469]! } - public var Wallet_Words_Done: String { return self._s[3470]! } - public var VoiceOver_Media_PlaybackPause: String { return self._s[3471]! } + public var SettingsSearch_Synonyms_EditProfile_Title: String { return self._s[3471]! } + public var Wallet_Created_Text: String { return self._s[3472]! } + public var Conversation_MessageDialogEdit: String { return self._s[3473]! } + public var Wallet_Created_Proceed: String { return self._s[3474]! } + public var Wallet_Words_Done: String { return self._s[3475]! } + public var VoiceOver_Media_PlaybackPause: String { return self._s[3476]! } public func PUSH_AUTH_UNKNOWN(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3472]!, self._r[3472]!, [_1]) + return formatWithArgumentRanges(self._s[3477]!, self._r[3477]!, [_1]) } - public var Common_Close: String { return self._s[3473]! } - public var GroupInfo_PublicLink: String { return self._s[3474]! } - public var Channel_OwnershipTransfer_ErrorPrivacyRestricted: String { return self._s[3475]! } - public var SettingsSearch_Synonyms_Notifications_GroupNotificationsPreview: String { return self._s[3476]! } + public var Common_Close: String { return self._s[3478]! } + public var GroupInfo_PublicLink: String { return self._s[3479]! } + public var Channel_OwnershipTransfer_ErrorPrivacyRestricted: String { return self._s[3480]! } + public var SettingsSearch_Synonyms_Notifications_GroupNotificationsPreview: String { return self._s[3481]! } public func Channel_AdminLog_MessageToggleInvitesOff(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3480]!, self._r[3480]!, [_0]) + return formatWithArgumentRanges(self._s[3485]!, self._r[3485]!, [_0]) } - public var UserInfo_About_Placeholder: String { return self._s[3481]! } + public var UserInfo_About_Placeholder: String { return self._s[3486]! } public func Conversation_FileHowToText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3482]!, self._r[3482]!, [_0]) + return formatWithArgumentRanges(self._s[3487]!, self._r[3487]!, [_0]) } - public var GroupInfo_Permissions_SectionTitle: String { return self._s[3483]! } - public var Channel_Info_Banned: String { return self._s[3485]! } + public var GroupInfo_Permissions_SectionTitle: String { return self._s[3488]! } + public var Channel_Info_Banned: String { return self._s[3490]! } public func Time_MonthOfYear_m11(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3486]!, self._r[3486]!, [_0]) + return formatWithArgumentRanges(self._s[3491]!, self._r[3491]!, [_0]) } - public var Appearance_Other: String { return self._s[3487]! } - public var Passport_Language_my: String { return self._s[3488]! } - public var Group_Setup_BasicHistoryHiddenHelp: String { return self._s[3489]! } + public var Appearance_Other: String { return self._s[3492]! } + public var Passport_Language_my: String { return self._s[3493]! } + public var Group_Setup_BasicHistoryHiddenHelp: String { return self._s[3494]! } public func Time_PreciseDate_m9(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3490]!, self._r[3490]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3495]!, self._r[3495]!, [_1, _2, _3]) } - public var SettingsSearch_Synonyms_Privacy_PasscodeAndFaceId: String { return self._s[3491]! } - public var Preview_CopyAddress: String { return self._s[3492]! } + public var SettingsSearch_Synonyms_Privacy_PasscodeAndFaceId: String { return self._s[3496]! } + public var Preview_CopyAddress: String { return self._s[3497]! } public func DialogList_SinglePlayingGameSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3493]!, self._r[3493]!, [_0]) + return formatWithArgumentRanges(self._s[3498]!, self._r[3498]!, [_0]) } - public var KeyCommand_JumpToPreviousChat: String { return self._s[3494]! } - public var UserInfo_BotSettings: String { return self._s[3495]! } - public var LiveLocation_MenuStopAll: String { return self._s[3497]! } - public var Passport_PasswordCreate: String { return self._s[3498]! } - public var StickerSettings_MaskContextInfo: String { return self._s[3499]! } - public var Message_PinnedLocationMessage: String { return self._s[3500]! } - public var Map_Satellite: String { return self._s[3501]! } - public var Watch_Message_Unsupported: String { return self._s[3502]! } - public var Username_TooManyPublicUsernamesError: String { return self._s[3503]! } - public var TwoStepAuth_EnterPasswordInvalid: String { return self._s[3504]! } + public var KeyCommand_JumpToPreviousChat: String { return self._s[3499]! } + public var UserInfo_BotSettings: String { return self._s[3500]! } + public var LiveLocation_MenuStopAll: String { return self._s[3502]! } + public var Passport_PasswordCreate: String { return self._s[3503]! } + public var StickerSettings_MaskContextInfo: String { return self._s[3504]! } + public var Message_PinnedLocationMessage: String { return self._s[3505]! } + public var Map_Satellite: String { return self._s[3506]! } + public var Watch_Message_Unsupported: String { return self._s[3507]! } + public var Username_TooManyPublicUsernamesError: String { return self._s[3508]! } + public var TwoStepAuth_EnterPasswordInvalid: String { return self._s[3509]! } public func Notification_PinnedTextMessage(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3505]!, self._r[3505]!, [_0, _1]) + return formatWithArgumentRanges(self._s[3510]!, self._r[3510]!, [_0, _1]) } public func Conversation_OpenBotLinkText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3506]!, self._r[3506]!, [_0]) + return formatWithArgumentRanges(self._s[3511]!, self._r[3511]!, [_0]) } - public var Wallet_WordImport_Continue: String { return self._s[3507]! } - public var Notifications_ChannelNotificationsHelp: String { return self._s[3508]! } - public var Privacy_Calls_P2PContacts: String { return self._s[3509]! } - public var NotificationsSound_None: String { return self._s[3510]! } - public var Channel_DiscussionGroup_UnlinkGroup: String { return self._s[3512]! } - public var AccessDenied_VoiceMicrophone: String { return self._s[3513]! } + public var Wallet_WordImport_Continue: String { return self._s[3512]! } + public var Notifications_ChannelNotificationsHelp: String { return self._s[3513]! } + public var Privacy_Calls_P2PContacts: String { return self._s[3514]! } + public var NotificationsSound_None: String { return self._s[3515]! } + public var Channel_DiscussionGroup_UnlinkGroup: String { return self._s[3517]! } + public var AccessDenied_VoiceMicrophone: String { return self._s[3518]! } public func ApplyLanguage_ChangeLanguageAlreadyActive(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3514]!, self._r[3514]!, [_1]) + return formatWithArgumentRanges(self._s[3519]!, self._r[3519]!, [_1]) } - public var Cache_Indexing: String { return self._s[3515]! } - public var DialogList_RecentTitlePeople: String { return self._s[3517]! } - public var DialogList_EncryptionRejected: String { return self._s[3518]! } - public var GroupInfo_Administrators: String { return self._s[3519]! } - public var Passport_ScanPassportHelp: String { return self._s[3520]! } - public var Application_Name: String { return self._s[3521]! } - public var Channel_AdminLogFilter_ChannelEventsInfo: String { return self._s[3522]! } - public var Appearance_ThemeCarouselDay: String { return self._s[3524]! } - public var Passport_Identity_TranslationHelp: String { return self._s[3525]! } + public var Cache_Indexing: String { return self._s[3520]! } + public var DialogList_RecentTitlePeople: String { return self._s[3522]! } + public var DialogList_EncryptionRejected: String { return self._s[3523]! } + public var GroupInfo_Administrators: String { return self._s[3524]! } + public var Passport_ScanPassportHelp: String { return self._s[3525]! } + public var Application_Name: String { return self._s[3526]! } + public var Channel_AdminLogFilter_ChannelEventsInfo: String { return self._s[3527]! } + public var Appearance_ThemeCarouselDay: String { return self._s[3529]! } + public var Passport_Identity_TranslationHelp: String { return self._s[3530]! } public func VoiceOver_Chat_VideoMessageFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3526]!, self._r[3526]!, [_0]) + return formatWithArgumentRanges(self._s[3531]!, self._r[3531]!, [_0]) } public func Notification_JoinedGroupByLink(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3527]!, self._r[3527]!, [_0]) + return formatWithArgumentRanges(self._s[3532]!, self._r[3532]!, [_0]) } public func DialogList_EncryptedChatStartedOutgoing(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3528]!, self._r[3528]!, [_0]) + return formatWithArgumentRanges(self._s[3533]!, self._r[3533]!, [_0]) } - public var Channel_EditAdmin_PermissionDeleteMessages: String { return self._s[3529]! } - public var Privacy_ChatsTitle: String { return self._s[3530]! } - public var DialogList_ClearHistoryConfirmation: String { return self._s[3531]! } - public var SettingsSearch_Synonyms_Data_Storage_ClearCache: String { return self._s[3532]! } - public var Watch_Suggestion_HoldOn: String { return self._s[3533]! } - public var Group_EditAdmin_TransferOwnership: String { return self._s[3534]! } - public var Group_LinkedChannel: String { return self._s[3535]! } - public var VoiceOver_Chat_SeenByRecipient: String { return self._s[3536]! } - public var SocksProxySetup_RequiredCredentials: String { return self._s[3537]! } - public var Passport_Address_TypeRentalAgreementUploadScan: String { return self._s[3538]! } - public var TwoStepAuth_EmailSkipAlert: String { return self._s[3539]! } - public var ScheduledMessages_RemindersTitle: String { return self._s[3541]! } - public var Channel_Setup_TypePublic: String { return self._s[3543]! } + public var Channel_EditAdmin_PermissionDeleteMessages: String { return self._s[3534]! } + public var Privacy_ChatsTitle: String { return self._s[3535]! } + public var DialogList_ClearHistoryConfirmation: String { return self._s[3536]! } + public var SettingsSearch_Synonyms_Data_Storage_ClearCache: String { return self._s[3537]! } + public var Watch_Suggestion_HoldOn: String { return self._s[3538]! } + public var Group_EditAdmin_TransferOwnership: String { return self._s[3539]! } + public var Group_LinkedChannel: String { return self._s[3540]! } + public var VoiceOver_Chat_SeenByRecipient: String { return self._s[3541]! } + public var SocksProxySetup_RequiredCredentials: String { return self._s[3542]! } + public var Passport_Address_TypeRentalAgreementUploadScan: String { return self._s[3543]! } + public var TwoStepAuth_EmailSkipAlert: String { return self._s[3544]! } + public var ScheduledMessages_RemindersTitle: String { return self._s[3546]! } + public var Channel_Setup_TypePublic: String { return self._s[3548]! } public func Channel_AdminLog_MessageToggleInvitesOn(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3544]!, self._r[3544]!, [_0]) + return formatWithArgumentRanges(self._s[3549]!, self._r[3549]!, [_0]) } - public var Channel_TypeSetup_Title: String { return self._s[3546]! } - public var Map_OpenInMaps: String { return self._s[3548]! } + public var Channel_TypeSetup_Title: String { return self._s[3551]! } + public var Map_OpenInMaps: String { return self._s[3553]! } public func PUSH_PINNED_NOTEXT(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3549]!, self._r[3549]!, [_1]) + return formatWithArgumentRanges(self._s[3554]!, self._r[3554]!, [_1]) } - public var NotificationsSound_Tremolo: String { return self._s[3551]! } + public var NotificationsSound_Tremolo: String { return self._s[3556]! } public func Date_ChatDateHeaderYear(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3552]!, self._r[3552]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3557]!, self._r[3557]!, [_1, _2, _3]) } - public var ConversationProfile_UnknownAddMemberError: String { return self._s[3553]! } - public var Channel_OwnershipTransfer_PasswordPlaceholder: String { return self._s[3554]! } - public var Passport_PasswordHelp: String { return self._s[3555]! } - public var Login_CodeExpiredError: String { return self._s[3556]! } - public var Channel_EditAdmin_PermissionChangeInfo: String { return self._s[3557]! } - public var Conversation_TitleUnmute: String { return self._s[3558]! } - public var Passport_Identity_ScansHelp: String { return self._s[3559]! } - public var Passport_Language_lo: String { return self._s[3560]! } - public var Camera_FlashAuto: String { return self._s[3561]! } - public var Conversation_OpenBotLinkOpen: String { return self._s[3562]! } - public var Common_Cancel: String { return self._s[3563]! } - public var DialogList_SavedMessagesTooltip: String { return self._s[3564]! } - public var TwoStepAuth_SetupPasswordTitle: String { return self._s[3565]! } - public var Appearance_TintAllColors: String { return self._s[3566]! } + public var ConversationProfile_UnknownAddMemberError: String { return self._s[3558]! } + public var Channel_OwnershipTransfer_PasswordPlaceholder: String { return self._s[3559]! } + public var Passport_PasswordHelp: String { return self._s[3560]! } + public var Login_CodeExpiredError: String { return self._s[3561]! } + public var Channel_EditAdmin_PermissionChangeInfo: String { return self._s[3562]! } + public var Conversation_TitleUnmute: String { return self._s[3563]! } + public var Passport_Identity_ScansHelp: String { return self._s[3564]! } + public var Passport_Language_lo: String { return self._s[3565]! } + public var Camera_FlashAuto: String { return self._s[3566]! } + public var Conversation_OpenBotLinkOpen: String { return self._s[3567]! } + public var Common_Cancel: String { return self._s[3568]! } + public var DialogList_SavedMessagesTooltip: String { return self._s[3569]! } + public var TwoStepAuth_SetupPasswordTitle: String { return self._s[3570]! } + public var Appearance_TintAllColors: String { return self._s[3571]! } public func PUSH_MESSAGE_FWD(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3567]!, self._r[3567]!, [_1]) + return formatWithArgumentRanges(self._s[3572]!, self._r[3572]!, [_1]) } - public var Conversation_ReportSpamConfirmation: String { return self._s[3568]! } - public var ChatSettings_Title: String { return self._s[3570]! } - public var Passport_PasswordReset: String { return self._s[3571]! } - public var SocksProxySetup_TypeNone: String { return self._s[3572]! } - public var EditTheme_Title: String { return self._s[3574]! } - public var PhoneNumberHelp_Help: String { return self._s[3575]! } - public var Checkout_EnterPassword: String { return self._s[3576]! } - public var Share_AuthTitle: String { return self._s[3578]! } - public var Activity_UploadingDocument: String { return self._s[3579]! } - public var State_Connecting: String { return self._s[3580]! } - public var Profile_MessageLifetime1w: String { return self._s[3581]! } - public var Conversation_ContextMenuReport: String { return self._s[3582]! } - public var CheckoutInfo_ReceiverInfoPhone: String { return self._s[3583]! } - public var AutoNightTheme_ScheduledTo: String { return self._s[3584]! } + public var Conversation_ReportSpamConfirmation: String { return self._s[3573]! } + public var ChatSettings_Title: String { return self._s[3575]! } + public var Passport_PasswordReset: String { return self._s[3576]! } + public var SocksProxySetup_TypeNone: String { return self._s[3577]! } + public var EditTheme_Title: String { return self._s[3579]! } + public var PhoneNumberHelp_Help: String { return self._s[3580]! } + public var Checkout_EnterPassword: String { return self._s[3581]! } + public var Share_AuthTitle: String { return self._s[3583]! } + public var Activity_UploadingDocument: String { return self._s[3584]! } + public var State_Connecting: String { return self._s[3585]! } + public var Profile_MessageLifetime1w: String { return self._s[3586]! } + public var Conversation_ContextMenuReport: String { return self._s[3587]! } + public var CheckoutInfo_ReceiverInfoPhone: String { return self._s[3588]! } + public var AutoNightTheme_ScheduledTo: String { return self._s[3589]! } public func VoiceOver_Chat_AnonymousPollFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3585]!, self._r[3585]!, [_0]) + return formatWithArgumentRanges(self._s[3590]!, self._r[3590]!, [_0]) } - public var AuthSessions_Terminate: String { return self._s[3586]! } - public var Wallet_WordImport_CanNotRemember: String { return self._s[3587]! } - public var Checkout_NewCard_CardholderNamePlaceholder: String { return self._s[3588]! } - public var KeyCommand_JumpToPreviousUnreadChat: String { return self._s[3589]! } - public var PhotoEditor_Set: String { return self._s[3590]! } - public var EmptyGroupInfo_Title: String { return self._s[3591]! } - public var Login_PadPhoneHelp: String { return self._s[3592]! } - public var AutoDownloadSettings_TypeGroupChats: String { return self._s[3595]! } - public var PrivacyPolicy_DeclineLastWarning: String { return self._s[3597]! } - public var NotificationsSound_Complete: String { return self._s[3598]! } - public var SettingsSearch_Synonyms_Privacy_Data_Title: String { return self._s[3599]! } - public var Group_Info_AdminLog: String { return self._s[3600]! } - public var GroupPermission_NotAvailableInPublicGroups: String { return self._s[3601]! } - public var Channel_AdminLog_InfoPanelAlertText: String { return self._s[3602]! } - public var Conversation_Admin: String { return self._s[3604]! } - public var Conversation_GifTooltip: String { return self._s[3605]! } - public var Passport_NotLoggedInMessage: String { return self._s[3606]! } + public var AuthSessions_Terminate: String { return self._s[3591]! } + public var Wallet_WordImport_CanNotRemember: String { return self._s[3592]! } + public var Checkout_NewCard_CardholderNamePlaceholder: String { return self._s[3593]! } + public var KeyCommand_JumpToPreviousUnreadChat: String { return self._s[3594]! } + public var PhotoEditor_Set: String { return self._s[3595]! } + public var EmptyGroupInfo_Title: String { return self._s[3596]! } + public var Login_PadPhoneHelp: String { return self._s[3597]! } + public var AutoDownloadSettings_TypeGroupChats: String { return self._s[3600]! } + public var PrivacyPolicy_DeclineLastWarning: String { return self._s[3602]! } + public var NotificationsSound_Complete: String { return self._s[3603]! } + public var SettingsSearch_Synonyms_Privacy_Data_Title: String { return self._s[3604]! } + public var Group_Info_AdminLog: String { return self._s[3605]! } + public var GroupPermission_NotAvailableInPublicGroups: String { return self._s[3606]! } + public var Channel_AdminLog_InfoPanelAlertText: String { return self._s[3607]! } + public var Conversation_Admin: String { return self._s[3609]! } + public var Conversation_GifTooltip: String { return self._s[3610]! } + public var Passport_NotLoggedInMessage: String { return self._s[3611]! } public func AutoDownloadSettings_OnFor(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3608]!, self._r[3608]!, [_0]) + return formatWithArgumentRanges(self._s[3613]!, self._r[3613]!, [_0]) } - public var Profile_MessageLifetimeForever: String { return self._s[3609]! } - public var SharedMedia_EmptyTitle: String { return self._s[3611]! } - public var Channel_Edit_PrivatePublicLinkAlert: String { return self._s[3613]! } - public var Username_Help: String { return self._s[3614]! } - public var DialogList_LanguageTooltip: String { return self._s[3616]! } - public var Map_LoadError: String { return self._s[3617]! } - public var Login_PhoneNumberAlreadyAuthorized: String { return self._s[3618]! } - public var Channel_AdminLog_AddMembers: String { return self._s[3619]! } - public var ArchivedChats_IntroTitle2: String { return self._s[3620]! } - public var Notification_Exceptions_NewException: String { return self._s[3621]! } - public var TwoStepAuth_EmailTitle: String { return self._s[3622]! } - public var WatchRemote_AlertText: String { return self._s[3623]! } + public var Profile_MessageLifetimeForever: String { return self._s[3614]! } + public var SharedMedia_EmptyTitle: String { return self._s[3616]! } + public var Channel_Edit_PrivatePublicLinkAlert: String { return self._s[3618]! } + public var Username_Help: String { return self._s[3619]! } + public var DialogList_LanguageTooltip: String { return self._s[3621]! } + public var Map_LoadError: String { return self._s[3622]! } + public var Login_PhoneNumberAlreadyAuthorized: String { return self._s[3623]! } + public var Channel_AdminLog_AddMembers: String { return self._s[3624]! } + public var ArchivedChats_IntroTitle2: String { return self._s[3625]! } + public var Notification_Exceptions_NewException: String { return self._s[3626]! } + public var TwoStepAuth_EmailTitle: String { return self._s[3627]! } + public var WatchRemote_AlertText: String { return self._s[3628]! } public func Wallet_Send_ConfirmationText(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3624]!, self._r[3624]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3629]!, self._r[3629]!, [_1, _2]) } - public var ChatSettings_ConnectionType_Title: String { return self._s[3627]! } + public var ChatSettings_ConnectionType_Title: String { return self._s[3632]! } public func Settings_CheckPhoneNumberTitle(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3628]!, self._r[3628]!, [_0]) + return formatWithArgumentRanges(self._s[3633]!, self._r[3633]!, [_0]) } - public var SettingsSearch_Synonyms_Calls_CallTab: String { return self._s[3629]! } - public var Passport_Address_CountryPlaceholder: String { return self._s[3630]! } + public var SettingsSearch_Synonyms_Calls_CallTab: String { return self._s[3634]! } + public var Passport_Address_CountryPlaceholder: String { return self._s[3635]! } public func DialogList_AwaitingEncryption(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3631]!, self._r[3631]!, [_0]) + return formatWithArgumentRanges(self._s[3636]!, self._r[3636]!, [_0]) } public func Time_PreciseDate_m6(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3632]!, self._r[3632]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3637]!, self._r[3637]!, [_1, _2, _3]) } - public var Group_AdminLog_EmptyText: String { return self._s[3633]! } - public var SettingsSearch_Synonyms_Appearance_Title: String { return self._s[3634]! } - public var Conversation_PrivateChannelTooltip: String { return self._s[3636]! } - public var Wallet_Created_ExportErrorText: String { return self._s[3637]! } - public var ChatList_UndoArchiveText1: String { return self._s[3638]! } - public var AccessDenied_VideoMicrophone: String { return self._s[3639]! } - public var Conversation_ContextMenuStickerPackAdd: String { return self._s[3640]! } - public var Cache_ClearNone: String { return self._s[3641]! } - public var SocksProxySetup_FailedToConnect: String { return self._s[3642]! } - public var Permissions_NotificationsTitle_v0: String { return self._s[3643]! } + public var Group_AdminLog_EmptyText: String { return self._s[3638]! } + public var SettingsSearch_Synonyms_Appearance_Title: String { return self._s[3639]! } + public var Conversation_PrivateChannelTooltip: String { return self._s[3641]! } + public var Wallet_Created_ExportErrorText: String { return self._s[3642]! } + public var ChatList_UndoArchiveText1: String { return self._s[3643]! } + public var AccessDenied_VideoMicrophone: String { return self._s[3644]! } + public var Conversation_ContextMenuStickerPackAdd: String { return self._s[3645]! } + public var Cache_ClearNone: String { return self._s[3646]! } + public var SocksProxySetup_FailedToConnect: String { return self._s[3647]! } + public var Permissions_NotificationsTitle_v0: String { return self._s[3648]! } public func Channel_AdminLog_MessageEdited(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3644]!, self._r[3644]!, [_0]) + return formatWithArgumentRanges(self._s[3649]!, self._r[3649]!, [_0]) } - public var Passport_Identity_Country: String { return self._s[3645]! } + public var Passport_Identity_Country: String { return self._s[3650]! } public func ChatSettings_AutoDownloadSettings_TypeFile(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3646]!, self._r[3646]!, [_0]) + return formatWithArgumentRanges(self._s[3651]!, self._r[3651]!, [_0]) } public func Notification_CreatedChat(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3647]!, self._r[3647]!, [_0]) + return formatWithArgumentRanges(self._s[3652]!, self._r[3652]!, [_0]) } - public var Exceptions_AddToExceptions: String { return self._s[3648]! } - public var AccessDenied_Settings: String { return self._s[3649]! } - public var Passport_Address_TypeUtilityBillUploadScan: String { return self._s[3650]! } - public var Month_ShortMay: String { return self._s[3651]! } - public var Compose_NewGroup: String { return self._s[3653]! } - public var Group_Setup_TypePrivate: String { return self._s[3655]! } - public var Login_PadPhoneHelpTitle: String { return self._s[3657]! } - public var Appearance_ThemeDayClassic: String { return self._s[3658]! } - public var Channel_AdminLog_MessagePreviousCaption: String { return self._s[3659]! } - public var AutoDownloadSettings_OffForAll: String { return self._s[3660]! } - public var Privacy_GroupsAndChannels_WhoCanAddMe: String { return self._s[3661]! } - public var Conversation_typing: String { return self._s[3663]! } - public var Undo_ScheduledMessagesCleared: String { return self._s[3664]! } - public var Paint_Masks: String { return self._s[3665]! } - public var Contacts_DeselectAll: String { return self._s[3666]! } - public var Username_InvalidTaken: String { return self._s[3667]! } - public var Call_StatusNoAnswer: String { return self._s[3668]! } - public var TwoStepAuth_EmailAddSuccess: String { return self._s[3669]! } - public var SettingsSearch_Synonyms_Privacy_BlockedUsers: String { return self._s[3670]! } - public var Passport_Identity_Selfie: String { return self._s[3671]! } - public var Login_InfoLastNamePlaceholder: String { return self._s[3672]! } - public var Privacy_SecretChatsLinkPreviewsHelp: String { return self._s[3673]! } - public var Conversation_ClearSecretHistory: String { return self._s[3674]! } - public var PeopleNearby_Description: String { return self._s[3676]! } - public var NetworkUsageSettings_Title: String { return self._s[3677]! } - public var Your_cards_security_code_is_invalid: String { return self._s[3679]! } + public var Exceptions_AddToExceptions: String { return self._s[3653]! } + public var AccessDenied_Settings: String { return self._s[3654]! } + public var Passport_Address_TypeUtilityBillUploadScan: String { return self._s[3655]! } + public var Month_ShortMay: String { return self._s[3656]! } + public var Compose_NewGroup: String { return self._s[3658]! } + public var Group_Setup_TypePrivate: String { return self._s[3660]! } + public var Login_PadPhoneHelpTitle: String { return self._s[3662]! } + public var Appearance_ThemeDayClassic: String { return self._s[3663]! } + public var Channel_AdminLog_MessagePreviousCaption: String { return self._s[3664]! } + public var AutoDownloadSettings_OffForAll: String { return self._s[3665]! } + public var Privacy_GroupsAndChannels_WhoCanAddMe: String { return self._s[3666]! } + public var Conversation_typing: String { return self._s[3668]! } + public var Undo_ScheduledMessagesCleared: String { return self._s[3669]! } + public var Paint_Masks: String { return self._s[3670]! } + public var Contacts_DeselectAll: String { return self._s[3671]! } + public var Username_InvalidTaken: String { return self._s[3672]! } + public var Call_StatusNoAnswer: String { return self._s[3673]! } + public var TwoStepAuth_EmailAddSuccess: String { return self._s[3674]! } + public var SettingsSearch_Synonyms_Privacy_BlockedUsers: String { return self._s[3675]! } + public var Passport_Identity_Selfie: String { return self._s[3676]! } + public var Login_InfoLastNamePlaceholder: String { return self._s[3677]! } + public var Privacy_SecretChatsLinkPreviewsHelp: String { return self._s[3678]! } + public var Conversation_ClearSecretHistory: String { return self._s[3679]! } + public var PeopleNearby_Description: String { return self._s[3681]! } + public var NetworkUsageSettings_Title: String { return self._s[3682]! } + public var Your_cards_security_code_is_invalid: String { return self._s[3684]! } public func Notification_LeftChannel(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3681]!, self._r[3681]!, [_0]) + return formatWithArgumentRanges(self._s[3686]!, self._r[3686]!, [_0]) } public func Call_CallInProgressMessage(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3682]!, self._r[3682]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3687]!, self._r[3687]!, [_1, _2]) } - public var SaveIncomingPhotosSettings_From: String { return self._s[3684]! } - public var VoiceOver_Navigation_Search: String { return self._s[3685]! } - public var Map_LiveLocationTitle: String { return self._s[3686]! } - public var Login_InfoAvatarAdd: String { return self._s[3687]! } - public var Passport_Identity_FilesView: String { return self._s[3688]! } - public var UserInfo_GenericPhoneLabel: String { return self._s[3689]! } - public var Privacy_Calls_NeverAllow: String { return self._s[3690]! } - public var VoiceOver_Chat_File: String { return self._s[3691]! } - public var Wallet_Settings_DeleteWalletInfo: String { return self._s[3692]! } + public var SaveIncomingPhotosSettings_From: String { return self._s[3689]! } + public var VoiceOver_Navigation_Search: String { return self._s[3690]! } + public var Map_LiveLocationTitle: String { return self._s[3691]! } + public var Login_InfoAvatarAdd: String { return self._s[3692]! } + public var Passport_Identity_FilesView: String { return self._s[3693]! } + public var UserInfo_GenericPhoneLabel: String { return self._s[3694]! } + public var Privacy_Calls_NeverAllow: String { return self._s[3695]! } + public var VoiceOver_Chat_File: String { return self._s[3696]! } + public var Wallet_Settings_DeleteWalletInfo: String { return self._s[3697]! } public func Contacts_AddPhoneNumber(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3693]!, self._r[3693]!, [_0]) + return formatWithArgumentRanges(self._s[3698]!, self._r[3698]!, [_0]) } - public var ContactInfo_PhoneNumberHidden: String { return self._s[3694]! } - public var TwoStepAuth_ConfirmationText: String { return self._s[3695]! } - public var ChatSettings_AutomaticVideoMessageDownload: String { return self._s[3696]! } + public var ContactInfo_PhoneNumberHidden: String { return self._s[3699]! } + public var TwoStepAuth_ConfirmationText: String { return self._s[3700]! } + public var ChatSettings_AutomaticVideoMessageDownload: String { return self._s[3701]! } public func PUSH_CHAT_MESSAGE_VIDEOS(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3697]!, self._r[3697]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3702]!, self._r[3702]!, [_1, _2, _3]) } - public var Channel_AdminLogFilter_AdminsAll: String { return self._s[3698]! } - public var Wallet_Intro_CreateErrorText: String { return self._s[3699]! } - public var Tour_Title2: String { return self._s[3700]! } - public var Wallet_Sent_ViewWallet: String { return self._s[3701]! } - public var Conversation_FileOpenIn: String { return self._s[3702]! } - public var Checkout_ErrorPrecheckoutFailed: String { return self._s[3703]! } - public var Wallet_Send_ErrorInvalidAddress: String { return self._s[3704]! } - public var Wallpaper_Set: String { return self._s[3705]! } - public var Passport_Identity_Translations: String { return self._s[3707]! } + public var Channel_AdminLogFilter_AdminsAll: String { return self._s[3703]! } + public var Wallet_Intro_CreateErrorText: String { return self._s[3704]! } + public var Tour_Title2: String { return self._s[3705]! } + public var Wallet_Sent_ViewWallet: String { return self._s[3706]! } + public var Conversation_FileOpenIn: String { return self._s[3707]! } + public var Checkout_ErrorPrecheckoutFailed: String { return self._s[3708]! } + public var Wallet_Send_ErrorInvalidAddress: String { return self._s[3709]! } + public var Wallpaper_Set: String { return self._s[3710]! } + public var Passport_Identity_Translations: String { return self._s[3712]! } public func Channel_AdminLog_MessageChangedChannelAbout(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3708]!, self._r[3708]!, [_0]) + return formatWithArgumentRanges(self._s[3713]!, self._r[3713]!, [_0]) } - public var Channel_LeaveChannel: String { return self._s[3709]! } + public var Channel_LeaveChannel: String { return self._s[3714]! } public func PINNED_INVOICE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3710]!, self._r[3710]!, [_1]) + return formatWithArgumentRanges(self._s[3715]!, self._r[3715]!, [_1]) } - public var SettingsSearch_Synonyms_Proxy_AddProxy: String { return self._s[3712]! } - public var PhotoEditor_HighlightsTint: String { return self._s[3713]! } - public var Passport_Email_Delete: String { return self._s[3714]! } - public var Conversation_Mute: String { return self._s[3716]! } - public var Channel_AddBotAsAdmin: String { return self._s[3717]! } - public var Channel_AdminLog_CanSendMessages: String { return self._s[3719]! } - public var Channel_Management_LabelOwner: String { return self._s[3721]! } + public var SettingsSearch_Synonyms_Proxy_AddProxy: String { return self._s[3717]! } + public var PhotoEditor_HighlightsTint: String { return self._s[3718]! } + public var Passport_Email_Delete: String { return self._s[3719]! } + public var Conversation_Mute: String { return self._s[3721]! } + public var Channel_AddBotAsAdmin: String { return self._s[3722]! } + public var Channel_AdminLog_CanSendMessages: String { return self._s[3724]! } + public var Channel_Management_LabelOwner: String { return self._s[3726]! } public func Notification_PassportValuesSentMessage(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3722]!, self._r[3722]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3727]!, self._r[3727]!, [_1, _2]) } - public var Calls_CallTabDescription: String { return self._s[3723]! } - public var Passport_Identity_NativeNameHelp: String { return self._s[3724]! } - public var Common_No: String { return self._s[3725]! } - public var Weekday_Sunday: String { return self._s[3726]! } - public var Notification_Reply: String { return self._s[3727]! } - public var Conversation_ViewMessage: String { return self._s[3728]! } + public var Calls_CallTabDescription: String { return self._s[3728]! } + public var Passport_Identity_NativeNameHelp: String { return self._s[3729]! } + public var Common_No: String { return self._s[3730]! } + public var Weekday_Sunday: String { return self._s[3731]! } + public var Notification_Reply: String { return self._s[3732]! } + public var Conversation_ViewMessage: String { return self._s[3733]! } public func Checkout_SavePasswordTimeoutAndFaceId(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3729]!, self._r[3729]!, [_0]) + return formatWithArgumentRanges(self._s[3734]!, self._r[3734]!, [_0]) } public func Map_LiveLocationPrivateDescription(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3730]!, self._r[3730]!, [_0]) + return formatWithArgumentRanges(self._s[3735]!, self._r[3735]!, [_0]) } - public var SettingsSearch_Synonyms_EditProfile_AddAccount: String { return self._s[3731]! } - public var Wallet_Send_Title: String { return self._s[3732]! } - public var Message_PinnedDocumentMessage: String { return self._s[3733]! } - public var Wallet_Info_RefreshErrorText: String { return self._s[3734]! } - public var DialogList_TabTitle: String { return self._s[3736]! } - public var ChatSettings_AutoPlayTitle: String { return self._s[3737]! } - public var Passport_FieldEmail: String { return self._s[3738]! } - public var Conversation_UnpinMessageAlert: String { return self._s[3739]! } - public var Passport_Address_TypeBankStatement: String { return self._s[3740]! } - public var Wallet_SecureStorageReset_Title: String { return self._s[3741]! } - public var Passport_Identity_ExpiryDate: String { return self._s[3742]! } - public var Privacy_Calls_P2P: String { return self._s[3743]! } + public var SettingsSearch_Synonyms_EditProfile_AddAccount: String { return self._s[3736]! } + public var Wallet_Send_Title: String { return self._s[3737]! } + public var Message_PinnedDocumentMessage: String { return self._s[3738]! } + public var Wallet_Info_RefreshErrorText: String { return self._s[3739]! } + public var DialogList_TabTitle: String { return self._s[3741]! } + public var ChatSettings_AutoPlayTitle: String { return self._s[3742]! } + public var Passport_FieldEmail: String { return self._s[3743]! } + public var Conversation_UnpinMessageAlert: String { return self._s[3744]! } + public var Passport_Address_TypeBankStatement: String { return self._s[3745]! } + public var Wallet_SecureStorageReset_Title: String { return self._s[3746]! } + public var Passport_Identity_ExpiryDate: String { return self._s[3747]! } + public var Privacy_Calls_P2P: String { return self._s[3748]! } public func CancelResetAccount_Success(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3745]!, self._r[3745]!, [_0]) + return formatWithArgumentRanges(self._s[3750]!, self._r[3750]!, [_0]) } - public var SocksProxySetup_UseForCallsHelp: String { return self._s[3746]! } + public var SocksProxySetup_UseForCallsHelp: String { return self._s[3751]! } public func PUSH_CHAT_ALBUM(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3747]!, self._r[3747]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3752]!, self._r[3752]!, [_1, _2]) } - public var Stickers_ClearRecent: String { return self._s[3748]! } - public var EnterPasscode_ChangeTitle: String { return self._s[3749]! } - public var Passport_InfoText: String { return self._s[3750]! } - public var Checkout_NewCard_SaveInfoEnableHelp: String { return self._s[3751]! } + public var Stickers_ClearRecent: String { return self._s[3753]! } + public var EnterPasscode_ChangeTitle: String { return self._s[3754]! } + public var Passport_InfoText: String { return self._s[3755]! } + public var Checkout_NewCard_SaveInfoEnableHelp: String { return self._s[3756]! } public func Login_InvalidPhoneEmailSubject(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3752]!, self._r[3752]!, [_0]) + return formatWithArgumentRanges(self._s[3757]!, self._r[3757]!, [_0]) } public func Time_PreciseDate_m3(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3753]!, self._r[3753]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3758]!, self._r[3758]!, [_1, _2, _3]) } - public var SettingsSearch_Synonyms_Notifications_BadgeIncludeMutedChannels: String { return self._s[3754]! } - public var ScheduledMessages_PollUnavailable: String { return self._s[3755]! } - public var VoiceOver_Navigation_Compose: String { return self._s[3756]! } - public var Passport_Identity_EditDriversLicense: String { return self._s[3757]! } - public var Conversation_TapAndHoldToRecord: String { return self._s[3759]! } - public var SettingsSearch_Synonyms_Notifications_BadgeIncludeMutedChats: String { return self._s[3760]! } + public var SettingsSearch_Synonyms_Notifications_BadgeIncludeMutedChannels: String { return self._s[3759]! } + public var ScheduledMessages_PollUnavailable: String { return self._s[3760]! } + public var VoiceOver_Navigation_Compose: String { return self._s[3761]! } + public var Passport_Identity_EditDriversLicense: String { return self._s[3762]! } + public var Conversation_TapAndHoldToRecord: String { return self._s[3764]! } + public var SettingsSearch_Synonyms_Notifications_BadgeIncludeMutedChats: String { return self._s[3765]! } public func Notification_CallTimeFormat(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3761]!, self._r[3761]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3766]!, self._r[3766]!, [_1, _2]) } - public var Channel_EditAdmin_PermissionInviteViaLink: String { return self._s[3763]! } + public var Channel_EditAdmin_PermissionInviteViaLink: String { return self._s[3768]! } public func Generic_OpenHiddenLinkAlert(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3765]!, self._r[3765]!, [_0]) + return formatWithArgumentRanges(self._s[3770]!, self._r[3770]!, [_0]) } - public var DialogList_Unread: String { return self._s[3766]! } + public var DialogList_Unread: String { return self._s[3771]! } public func PUSH_CHAT_MESSAGE_GIF(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3767]!, self._r[3767]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3772]!, self._r[3772]!, [_1, _2]) } public func Updated_YesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3768]!, self._r[3768]!, [_0]) + return formatWithArgumentRanges(self._s[3773]!, self._r[3773]!, [_0]) } - public var User_DeletedAccount: String { return self._s[3769]! } - public var OwnershipTransfer_SetupTwoStepAuth: String { return self._s[3770]! } + public var User_DeletedAccount: String { return self._s[3774]! } + public var OwnershipTransfer_SetupTwoStepAuth: String { return self._s[3775]! } public func Watch_Time_ShortYesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3771]!, self._r[3771]!, [_0]) + return formatWithArgumentRanges(self._s[3776]!, self._r[3776]!, [_0]) } - public var UserInfo_NotificationsDefault: String { return self._s[3772]! } - public var SharedMedia_CategoryMedia: String { return self._s[3773]! } - public var SocksProxySetup_ProxyStatusUnavailable: String { return self._s[3774]! } - public var Channel_AdminLog_MessageRestrictedForever: String { return self._s[3775]! } - public var Watch_ChatList_Compose: String { return self._s[3776]! } - public var Notifications_MessageNotificationsExceptionsHelp: String { return self._s[3777]! } - public var AutoDownloadSettings_Delimeter: String { return self._s[3778]! } - public var Watch_Microphone_Access: String { return self._s[3779]! } - public var Group_Setup_HistoryHeader: String { return self._s[3780]! } - public var Map_SetThisLocation: String { return self._s[3781]! } - public var Appearance_ThemePreview_Chat_2_ReplyName: String { return self._s[3782]! } - public var Activity_UploadingPhoto: String { return self._s[3783]! } - public var Conversation_Edit: String { return self._s[3785]! } - public var Group_ErrorSendRestrictedMedia: String { return self._s[3786]! } - public var Login_TermsOfServiceDecline: String { return self._s[3787]! } - public var Message_PinnedContactMessage: String { return self._s[3788]! } + public var UserInfo_NotificationsDefault: String { return self._s[3777]! } + public var SharedMedia_CategoryMedia: String { return self._s[3778]! } + public var SocksProxySetup_ProxyStatusUnavailable: String { return self._s[3779]! } + public var Channel_AdminLog_MessageRestrictedForever: String { return self._s[3780]! } + public var Watch_ChatList_Compose: String { return self._s[3781]! } + public var Notifications_MessageNotificationsExceptionsHelp: String { return self._s[3782]! } + public var AutoDownloadSettings_Delimeter: String { return self._s[3783]! } + public var Watch_Microphone_Access: String { return self._s[3784]! } + public var Group_Setup_HistoryHeader: String { return self._s[3785]! } + public var Map_SetThisLocation: String { return self._s[3786]! } + public var Appearance_ThemePreview_Chat_2_ReplyName: String { return self._s[3787]! } + public var Activity_UploadingPhoto: String { return self._s[3788]! } + public var Conversation_Edit: String { return self._s[3790]! } + public var Group_ErrorSendRestrictedMedia: String { return self._s[3791]! } + public var Login_TermsOfServiceDecline: String { return self._s[3792]! } + public var Message_PinnedContactMessage: String { return self._s[3793]! } public func Channel_AdminLog_MessageRestrictedNameUsername(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3789]!, self._r[3789]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3794]!, self._r[3794]!, [_1, _2]) } public func Login_PhoneBannedEmailBody(_ _1: String, _ _2: String, _ _3: String, _ _4: String, _ _5: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3790]!, self._r[3790]!, [_1, _2, _3, _4, _5]) + return formatWithArgumentRanges(self._s[3795]!, self._r[3795]!, [_1, _2, _3, _4, _5]) } - public var Appearance_LargeEmoji: String { return self._s[3791]! } - public var TwoStepAuth_AdditionalPassword: String { return self._s[3793]! } - public var EditTheme_Edit_Preview_IncomingReplyText: String { return self._s[3794]! } + public var Appearance_LargeEmoji: String { return self._s[3796]! } + public var TwoStepAuth_AdditionalPassword: String { return self._s[3798]! } + public var EditTheme_Edit_Preview_IncomingReplyText: String { return self._s[3799]! } public func PUSH_CHAT_DELETE_YOU(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3795]!, self._r[3795]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3800]!, self._r[3800]!, [_1, _2]) } - public var Passport_Phone_EnterOtherNumber: String { return self._s[3796]! } - public var Message_PinnedPhotoMessage: String { return self._s[3797]! } - public var Passport_FieldPhone: String { return self._s[3798]! } - public var TwoStepAuth_RecoveryEmailAddDescription: String { return self._s[3799]! } - public var ChatSettings_AutoPlayGifs: String { return self._s[3800]! } - public var InfoPlist_NSCameraUsageDescription: String { return self._s[3802]! } - public var Conversation_Call: String { return self._s[3803]! } - public var Common_TakePhoto: String { return self._s[3805]! } - public var Group_EditAdmin_RankTitle: String { return self._s[3806]! } - public var Wallet_Receive_CommentHeader: String { return self._s[3807]! } - public var Channel_NotificationLoading: String { return self._s[3808]! } + public var Passport_Phone_EnterOtherNumber: String { return self._s[3801]! } + public var Message_PinnedPhotoMessage: String { return self._s[3802]! } + public var Passport_FieldPhone: String { return self._s[3803]! } + public var TwoStepAuth_RecoveryEmailAddDescription: String { return self._s[3804]! } + public var ChatSettings_AutoPlayGifs: String { return self._s[3805]! } + public var InfoPlist_NSCameraUsageDescription: String { return self._s[3807]! } + public var Conversation_Call: String { return self._s[3808]! } + public var Common_TakePhoto: String { return self._s[3810]! } + public var Group_EditAdmin_RankTitle: String { return self._s[3811]! } + public var Wallet_Receive_CommentHeader: String { return self._s[3812]! } + public var Channel_NotificationLoading: String { return self._s[3813]! } public func Notification_Exceptions_Sound(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3809]!, self._r[3809]!, [_0]) - } - public func ScheduledMessages_ScheduledDate(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3810]!, self._r[3810]!, [_0]) - } - public func PUSH_CHANNEL_MESSAGE_VIDEO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3811]!, self._r[3811]!, [_1]) - } - public var Permissions_SiriTitle_v0: String { return self._s[3812]! } - public func VoiceOver_Chat_VoiceMessageFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3813]!, self._r[3813]!, [_0]) - } - public func Login_ResetAccountProtected_Text(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[3814]!, self._r[3814]!, [_0]) } - public var Channel_MessagePhotoRemoved: String { return self._s[3815]! } - public var Common_edit: String { return self._s[3816]! } - public var PrivacySettings_AuthSessions: String { return self._s[3817]! } - public var Month_ShortJune: String { return self._s[3818]! } - public var PrivacyLastSeenSettings_AlwaysShareWith_Placeholder: String { return self._s[3819]! } - public var Call_ReportSend: String { return self._s[3820]! } - public var Watch_LastSeen_JustNow: String { return self._s[3821]! } - public var Notifications_MessageNotifications: String { return self._s[3822]! } - public var WallpaperSearch_ColorGreen: String { return self._s[3823]! } - public var BroadcastListInfo_AddRecipient: String { return self._s[3825]! } - public var Group_Status: String { return self._s[3826]! } + public func ScheduledMessages_ScheduledDate(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3815]!, self._r[3815]!, [_0]) + } + public func PUSH_CHANNEL_MESSAGE_VIDEO(_ _1: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3816]!, self._r[3816]!, [_1]) + } + public var Permissions_SiriTitle_v0: String { return self._s[3817]! } + public func VoiceOver_Chat_VoiceMessageFrom(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3818]!, self._r[3818]!, [_0]) + } + public func Login_ResetAccountProtected_Text(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3819]!, self._r[3819]!, [_0]) + } + public var Channel_MessagePhotoRemoved: String { return self._s[3820]! } + public var Common_edit: String { return self._s[3821]! } + public var PrivacySettings_AuthSessions: String { return self._s[3822]! } + public var Month_ShortJune: String { return self._s[3823]! } + public var PrivacyLastSeenSettings_AlwaysShareWith_Placeholder: String { return self._s[3824]! } + public var Call_ReportSend: String { return self._s[3825]! } + public var Watch_LastSeen_JustNow: String { return self._s[3826]! } + public var Notifications_MessageNotifications: String { return self._s[3827]! } + public var WallpaperSearch_ColorGreen: String { return self._s[3828]! } + public var BroadcastListInfo_AddRecipient: String { return self._s[3830]! } + public var Group_Status: String { return self._s[3831]! } public func AutoNightTheme_LocationHelp(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3827]!, self._r[3827]!, [_0, _1]) + return formatWithArgumentRanges(self._s[3832]!, self._r[3832]!, [_0, _1]) } - public var TextFormat_AddLinkTitle: String { return self._s[3828]! } - public var ShareMenu_ShareTo: String { return self._s[3829]! } - public var Conversation_Moderate_Ban: String { return self._s[3830]! } + public var TextFormat_AddLinkTitle: String { return self._s[3833]! } + public var ShareMenu_ShareTo: String { return self._s[3834]! } + public var Conversation_Moderate_Ban: String { return self._s[3835]! } public func Conversation_DeleteMessagesFor(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3831]!, self._r[3831]!, [_0]) + return formatWithArgumentRanges(self._s[3836]!, self._r[3836]!, [_0]) } - public var SharedMedia_ViewInChat: String { return self._s[3832]! } - public var Map_LiveLocationFor8Hours: String { return self._s[3833]! } + public var SharedMedia_ViewInChat: String { return self._s[3837]! } + public var Map_LiveLocationFor8Hours: String { return self._s[3838]! } public func PUSH_PINNED_PHOTO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3834]!, self._r[3834]!, [_1]) + return formatWithArgumentRanges(self._s[3839]!, self._r[3839]!, [_1]) } public func PUSH_PINNED_POLL(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3835]!, self._r[3835]!, [_1, _2]) - } - public func Map_AccurateTo(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3837]!, self._r[3837]!, [_0]) - } - public var Map_OpenInHereMaps: String { return self._s[3838]! } - public var Appearance_ReduceMotion: String { return self._s[3839]! } - public func PUSH_MESSAGE_TEXT(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[3840]!, self._r[3840]!, [_1, _2]) } - public var Channel_Setup_TypePublicHelp: String { return self._s[3841]! } - public var Passport_Identity_EditInternalPassport: String { return self._s[3842]! } - public var PhotoEditor_Skip: String { return self._s[3843]! } - public func MessageTimer_Seconds(_ value: Int32) -> String { + public func Map_AccurateTo(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3842]!, self._r[3842]!, [_0]) + } + public var Map_OpenInHereMaps: String { return self._s[3843]! } + public var Appearance_ReduceMotion: String { return self._s[3844]! } + public func PUSH_MESSAGE_TEXT(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3845]!, self._r[3845]!, [_1, _2]) + } + public var Channel_Setup_TypePublicHelp: String { return self._s[3846]! } + public var Passport_Identity_EditInternalPassport: String { return self._s[3847]! } + public var PhotoEditor_Skip: String { return self._s[3848]! } + public func ForwardedPhotos(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[0 * 6 + Int(form.rawValue)]!, stringValue) } - public func MessageTimer_Minutes(_ value: Int32) -> String { + public func Conversation_StatusMembers(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[1 * 6 + Int(form.rawValue)]!, stringValue) } - public func UserCount(_ value: Int32) -> String { + public func SharedMedia_DeleteItemsConfirmation(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[2 * 6 + Int(form.rawValue)]!, stringValue) } - public func SharedMedia_File(_ value: Int32) -> String { + public func SharedMedia_Generic(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[3 * 6 + Int(form.rawValue)]!, stringValue) } - public func ForwardedPhotos(_ value: Int32) -> String { + public func ChatList_DeleteConfirmation(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[4 * 6 + Int(form.rawValue)]!, stringValue) } - public func VoiceOver_Chat_PollOptionCount(_ value: Int32) -> String { + public func Conversation_StatusOnline(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[5 * 6 + Int(form.rawValue)]!, stringValue) } - public func ServiceMessage_GameScoreSimple(_ value: Int32) -> String { + public func ForwardedMessages(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[6 * 6 + Int(form.rawValue)]!, stringValue) } - public func MessageTimer_Weeks(_ value: Int32) -> String { + public func Watch_LastSeen_MinutesAgo(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[7 * 6 + Int(form.rawValue)]!, stringValue) } - public func PUSH_CHAT_MESSAGE_ROUNDS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { + public func Call_Seconds(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[8 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_MESSAGE_ROUNDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, selector) - return String(format: self._ps[8 * 6 + Int(form.rawValue)]!, _2, _1, _3) + return String(format: self._ps[9 * 6 + Int(form.rawValue)]!, _1, _2) } - public func Conversation_StatusSubscribers(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[9 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_Hours(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[10 * 6 + Int(form.rawValue)]!, stringValue) - } - public func VoiceOver_Chat_ContactEmailCount(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[11 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PrivacyLastSeenSettings_AddUsers(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[12 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_MESSAGE_PHOTOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + public func PUSH_CHANNEL_MESSAGE_ROUNDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, selector) - return String(format: self._ps[13 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func InviteText_ContactsCountText(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[14 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_ShortSeconds(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[15 * 6 + Int(form.rawValue)]!, stringValue) - } - public func DialogList_LiveLocationChatsCount(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[16 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Theme_UsersCount(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[17 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MuteFor_Hours(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[18 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ChatList_DeleteConfirmation(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[19 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ServiceMessage_GameScoreSelfSimple(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[20 * 6 + Int(form.rawValue)]!, stringValue) - } - public func VoiceOver_Chat_ContactPhoneNumberCount(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[21 * 6 + Int(form.rawValue)]!, stringValue) - } - public func StickerPack_StickerCount(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[22 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MuteExpires_Minutes(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[23 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MuteExpires_Hours(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[24 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Conversation_StatusMembers(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[25 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Media_ShareVideo(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[26 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Media_ShareItem(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[27 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_CHANNEL_MESSAGES(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, selector) - return String(format: self._ps[28 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func ForwardedAudios(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[29 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_Days(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[30 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Notification_GameScoreSimple(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[31 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_Months(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[32 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MuteExpires_Days(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[33 * 6 + Int(form.rawValue)]!, stringValue) - } - public func SharedMedia_Video(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[34 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_CHANNEL_MESSAGE_PHOTOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, selector) - return String(format: self._ps[35 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func Passport_Scans(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[36 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Notifications_ExceptionMuteExpires_Days(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[37 * 6 + Int(form.rawValue)]!, stringValue) - } - public func CreatePoll_AddMoreOptions(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[38 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Watch_LastSeen_HoursAgo(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[39 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedGifs(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[40 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Watch_LastSeen_MinutesAgo(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[41 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedMessages(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[42 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedVideoMessages(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[43 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ServiceMessage_GameScoreSelfExtended(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[44 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Conversation_SelectedMessages(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[45 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_ShortHours(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[46 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_ShortMinutes(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[47 * 6 + Int(form.rawValue)]!, stringValue) - } - public func AttachmentMenu_SendItem(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[48 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_CHAT_MESSAGE_PHOTOS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, selector) - return String(format: self._ps[49 * 6 + Int(form.rawValue)]!, _2, _1, _3) - } - public func Forward_ConfirmMultipleFiles(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[50 * 6 + Int(form.rawValue)]!, stringValue) - } - public func AttachmentMenu_SendVideo(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[51 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_CHANNEL_MESSAGE_VIDEOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, selector) - return String(format: self._ps[52 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func Watch_UserInfo_Mute(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[53 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Invitation_Members(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[54 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_MESSAGES(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, selector) - return String(format: self._ps[55 * 6 + Int(form.rawValue)]!, _1, _2) + return String(format: self._ps[10 * 6 + Int(form.rawValue)]!, _1, _2) } public func ForwardedStickers(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[56 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[11 * 6 + Int(form.rawValue)]!, stringValue) } - public func ChatList_SelectedChats(_ value: Int32) -> String { + public func Invitation_Members(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[57 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_MESSAGE_FWDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, selector) - return String(format: self._ps[58 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func Chat_DeleteMessagesConfirmation(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[59 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Notification_GameScoreSelfSimple(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[60 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Call_ShortSeconds(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[61 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Updated_MinutesAgo(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[62 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Conversation_LiveLocationMembersCount(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[63 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedVideos(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[64 * 6 + Int(form.rawValue)]!, stringValue) - } - public func StickerPack_AddStickerCount(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[65 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_MESSAGE_ROUNDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, selector) - return String(format: self._ps[66 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func ServiceMessage_GameScoreExtended(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[67 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Notifications_Exceptions(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[68 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Notifications_ExceptionMuteExpires_Hours(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[69 * 6 + Int(form.rawValue)]!, stringValue) - } - public func StickerPack_AddMaskCount(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[70 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Map_ETAHours(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[71 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Call_ShortMinutes(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[72 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_MESSAGE_VIDEOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, selector) - return String(format: self._ps[73 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func Call_Minutes(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[74 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_Years(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[75 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Notification_GameScoreExtended(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[76 * 6 + Int(form.rawValue)]!, stringValue) - } - public func LiveLocation_MenuChatsCount(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[77 * 6 + Int(form.rawValue)]!, stringValue) - } - public func QuickSend_Photos(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[78 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_ShortDays(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[79 * 6 + Int(form.rawValue)]!, stringValue) - } - public func VoiceOver_Chat_PollVotes(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[80 * 6 + Int(form.rawValue)]!, stringValue) - } - public func LastSeen_MinutesAgo(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[81 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Wallpaper_DeleteConfirmation(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[82 * 6 + Int(form.rawValue)]!, stringValue) - } - public func StickerPack_RemoveMaskCount(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[83 * 6 + Int(form.rawValue)]!, stringValue) - } - public func GroupInfo_ParticipantCount(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[84 * 6 + Int(form.rawValue)]!, stringValue) - } - public func AttachmentMenu_SendGif(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[85 * 6 + Int(form.rawValue)]!, stringValue) - } - public func SharedMedia_DeleteItemsConfirmation(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[86 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Contacts_ImportersCount(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[87 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedFiles(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[88 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Map_ETAMinutes(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[89 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedPolls(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[90 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[12 * 6 + Int(form.rawValue)]!, stringValue) } public func LiveLocationUpdated_MinutesAgo(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[91 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[13 * 6 + Int(form.rawValue)]!, stringValue) } - public func SharedMedia_Generic(_ value: Int32) -> String { + public func MessageTimer_Years(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[92 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[14 * 6 + Int(form.rawValue)]!, stringValue) } - public func PUSH_CHAT_MESSAGES(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { + public func Passport_Scans(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[15 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Media_ShareVideo(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[16 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedPolls(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[17 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_MESSAGES(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, selector) - return String(format: self._ps[93 * 6 + Int(form.rawValue)]!, _2, _1, _3) + return String(format: self._ps[18 * 6 + Int(form.rawValue)]!, _1, _2) } - public func PasscodeSettings_FailedAttempts(_ value: Int32) -> String { + public func ForwardedVideoMessages(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[94 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[19 * 6 + Int(form.rawValue)]!, stringValue) } - public func Media_SharePhoto(_ value: Int32) -> String { + public func VoiceOver_Chat_PollVotes(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[95 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[20 * 6 + Int(form.rawValue)]!, stringValue) } - public func SharedMedia_Link(_ value: Int32) -> String { + public func VoiceOver_Chat_ContactEmailCount(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[96 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[21 * 6 + Int(form.rawValue)]!, stringValue) + } + public func QuickSend_Photos(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[22 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_Days(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[23 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedAudios(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[24 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_CHANNEL_MESSAGES(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, selector) + return String(format: self._ps[25 * 6 + Int(form.rawValue)]!, _1, _2) } public func MessagePoll_VotedCount(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[97 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[26 * 6 + Int(form.rawValue)]!, stringValue) } - public func Notification_GameScoreSelfExtended(_ value: Int32) -> String { + public func Media_SharePhoto(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[98 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[27 * 6 + Int(form.rawValue)]!, stringValue) } - public func StickerPack_RemoveStickerCount(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[99 * 6 + Int(form.rawValue)]!, stringValue) - } - public func SharedMedia_Photo(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[100 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_CHANNEL_MESSAGE_FWDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + public func PUSH_CHAT_MESSAGE_PHOTOS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, selector) - return String(format: self._ps[101 * 6 + Int(form.rawValue)]!, _1, _2) + return String(format: self._ps[28 * 6 + Int(form.rawValue)]!, _2, _1, _3) + } + public func StickerPack_AddStickerCount(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[29 * 6 + Int(form.rawValue)]!, stringValue) + } + public func StickerPack_AddMaskCount(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[30 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_CHAT_MESSAGES(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, selector) + return String(format: self._ps[31 * 6 + Int(form.rawValue)]!, _2, _1, _3) + } + public func CreatePoll_AddMoreOptions(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[32 * 6 + Int(form.rawValue)]!, stringValue) } public func ForwardedAuthorsOthers(_ selector: Int32, _ _0: String, _ _1: String) -> String { let form = presentationStringsPluralizationForm(self.lc, selector) - return String(format: self._ps[102 * 6 + Int(form.rawValue)]!, _0, _1) + return String(format: self._ps[33 * 6 + Int(form.rawValue)]!, _0, _1) } - public func Notifications_ExceptionMuteExpires_Minutes(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[103 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_CHAT_MESSAGE_FWDS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { + public func PUSH_CHAT_MESSAGE_ROUNDS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, selector) - return String(format: self._ps[104 * 6 + Int(form.rawValue)]!, _2, _1, _3) + return String(format: self._ps[34 * 6 + Int(form.rawValue)]!, _2, _1, _3) } - public func LastSeen_HoursAgo(_ value: Int32) -> String { + public func MessageTimer_ShortSeconds(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[105 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedContacts(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[106 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Call_Seconds(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[107 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Conversation_StatusOnline(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[108 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MuteFor_Days(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[109 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_CHANNEL_MESSAGE_ROUNDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, selector) - return String(format: self._ps[110 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func ForwardedLocations(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[111 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_ShortWeeks(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[112 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[35 * 6 + Int(form.rawValue)]!, stringValue) } public func AttachmentMenu_SendPhoto(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[113 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[36 * 6 + Int(form.rawValue)]!, stringValue) + } + public func InviteText_ContactsCountText(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[37 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_MESSAGE_FWDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, selector) + return String(format: self._ps[38 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func UserCount(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[39 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MuteExpires_Days(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[40 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedVideos(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[41 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Updated_HoursAgo(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[42 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Notification_GameScoreSimple(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[43 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Wallpaper_DeleteConfirmation(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[44 * 6 + Int(form.rawValue)]!, stringValue) + } + public func LastSeen_HoursAgo(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[45 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_Months(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[46 * 6 + Int(form.rawValue)]!, stringValue) } public func PUSH_CHAT_MESSAGE_VIDEOS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, selector) - return String(format: self._ps[114 * 6 + Int(form.rawValue)]!, _2, _1, _3) + return String(format: self._ps[47 * 6 + Int(form.rawValue)]!, _2, _1, _3) } - public func Updated_HoursAgo(_ value: Int32) -> String { + public func PUSH_MESSAGE_VIDEOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, selector) + return String(format: self._ps[48 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func AttachmentMenu_SendItem(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[49 * 6 + Int(form.rawValue)]!, stringValue) + } + public func AttachmentMenu_SendGif(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[50 * 6 + Int(form.rawValue)]!, stringValue) + } + public func LiveLocation_MenuChatsCount(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[51 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Call_ShortMinutes(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[52 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_Seconds(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[53 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MuteExpires_Minutes(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[54 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_CHANNEL_MESSAGE_VIDEOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, selector) + return String(format: self._ps[55 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func StickerPack_RemoveMaskCount(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[56 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Call_Minutes(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[57 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_ShortDays(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[58 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Forward_ConfirmMultipleFiles(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[59 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_CHANNEL_MESSAGE_PHOTOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, selector) + return String(format: self._ps[60 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func Conversation_StatusSubscribers(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[61 * 6 + Int(form.rawValue)]!, stringValue) + } + public func DialogList_LiveLocationChatsCount(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[62 * 6 + Int(form.rawValue)]!, stringValue) + } + public func GroupInfo_ParticipantCount(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[63 * 6 + Int(form.rawValue)]!, stringValue) + } + public func StickerPack_RemoveStickerCount(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[64 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Contacts_ImportersCount(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[65 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_ShortHours(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[66 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Updated_MinutesAgo(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[67 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ChatList_SelectedChats(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[68 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_Hours(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[69 * 6 + Int(form.rawValue)]!, stringValue) + } + public func LastSeen_MinutesAgo(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[70 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Notifications_ExceptionMuteExpires_Days(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[71 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Notifications_ExceptionMuteExpires_Minutes(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[72 * 6 + Int(form.rawValue)]!, stringValue) + } + public func SharedMedia_Photo(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[73 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_Minutes(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[74 * 6 + Int(form.rawValue)]!, stringValue) + } + public func VoiceOver_Chat_ContactPhoneNumberCount(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[75 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ServiceMessage_GameScoreExtended(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[76 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_ShortWeeks(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[77 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Notification_GameScoreSelfSimple(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[78 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Map_ETAHours(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[79 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Media_ShareItem(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[80 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Notification_GameScoreSelfExtended(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[81 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PasscodeSettings_FailedAttempts(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[82 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Watch_LastSeen_HoursAgo(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[83 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MuteFor_Hours(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[84 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ServiceMessage_GameScoreSimple(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[85 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PrivacyLastSeenSettings_AddUsers(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[86 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_ShortMinutes(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[87 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_MESSAGE_PHOTOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, selector) + return String(format: self._ps[88 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func Conversation_SelectedMessages(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[89 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Chat_DeleteMessagesConfirmation(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[90 * 6 + Int(form.rawValue)]!, stringValue) + } + public func SharedMedia_File(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[91 * 6 + Int(form.rawValue)]!, stringValue) + } + public func AttachmentMenu_SendVideo(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[92 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Call_ShortSeconds(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[93 * 6 + Int(form.rawValue)]!, stringValue) + } + public func SharedMedia_Video(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[94 * 6 + Int(form.rawValue)]!, stringValue) + } + public func SharedMedia_Link(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[95 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Conversation_LiveLocationMembersCount(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[96 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedContacts(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[97 * 6 + Int(form.rawValue)]!, stringValue) + } + public func VoiceOver_Chat_PollOptionCount(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[98 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Map_ETAMinutes(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[99 * 6 + Int(form.rawValue)]!, stringValue) + } + public func StickerPack_StickerCount(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[100 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Theme_UsersCount(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[101 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedLocations(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[102 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ServiceMessage_GameScoreSelfSimple(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[103 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_Weeks(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[104 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedFiles(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[105 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Watch_UserInfo_Mute(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[106 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Notification_GameScoreExtended(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[107 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ServiceMessage_GameScoreSelfExtended(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[108 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Notifications_Exceptions(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[109 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MuteExpires_Hours(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[110 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_CHAT_MESSAGE_FWDS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, selector) + return String(format: self._ps[111 * 6 + Int(form.rawValue)]!, _2, _1, _3) + } + public func MuteFor_Days(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[112 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_CHANNEL_MESSAGE_FWDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, selector) + return String(format: self._ps[113 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func Notifications_ExceptionMuteExpires_Hours(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[114 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedGifs(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[115 * 6 + Int(form.rawValue)]!, stringValue) diff --git a/submodules/TelegramUI/TelegramUI/AppDelegate.swift b/submodules/TelegramUI/TelegramUI/AppDelegate.swift index bad165bda5..70c464b897 100644 --- a/submodules/TelegramUI/TelegramUI/AppDelegate.swift +++ b/submodules/TelegramUI/TelegramUI/AppDelegate.swift @@ -244,8 +244,6 @@ final class SharedApplicationContext { private let deviceToken = Promise(nil) - private var cloudDataContext: Any? - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool { precondition(!testIsLaunched) testIsLaunched = true @@ -262,8 +260,6 @@ final class SharedApplicationContext { self.window = window self.nativeWindow = window - self.cloudDataContext = makeCloudDataContext() - let clearNotificationsManager = ClearNotificationsManager(getNotificationIds: { completion in if #available(iOS 10.0, *) { UNUserNotificationCenter.current().getDeliveredNotifications(completionHandler: { notifications in diff --git a/submodules/TelegramUI/TelegramUI/Resources/PresentationStrings.mapping b/submodules/TelegramUI/TelegramUI/Resources/PresentationStrings.mapping index 8ea969f7a62e3bee42ab332cc4a3116c28d9801a..3deab5d7c9d764ca9c3487d095282fa820001fd8 100644 GIT binary patch delta 26468 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 deliverOnMainQueue).start(error: { [weak controller] _ in controller?.dismiss() }, completed: { [weak controller] in diff --git a/submodules/WalletUI/Sources/WalletSplashScreen.swift b/submodules/WalletUI/Sources/WalletSplashScreen.swift index afce794d44..a93b8fee3f 100644 --- a/submodules/WalletUI/Sources/WalletSplashScreen.swift +++ b/submodules/WalletUI/Sources/WalletSplashScreen.swift @@ -142,14 +142,20 @@ public final class WalletSplashScreen: ViewController { switch error { case .generic: text = strongSelf.presentationData.strings.Login_UnknownError + case .network: + text = strongSelf.presentationData.strings.Wallet_Send_NetworkError + case .notEnoughFunds: + text = strongSelf.presentationData.strings.Wallet_Send_ErrorNotEnoughFunds + case .messageTooLong: + text = strongSelf.presentationData.strings.Login_UnknownError case .invalidAddress: text = strongSelf.presentationData.strings.Wallet_Send_ErrorInvalidAddress case .secretDecryptionFailed: text = strongSelf.presentationData.strings.Wallet_Send_ErrorDecryptionFailed case .destinationIsNotInitialized: if !forceIfDestinationNotInitialized { - text = "This address belongs to an empty wallet. Are you sure you want to transfer grams to it?" - let controller = textAlertController(context: strongSelf.context, title: "Warning", text: text, actions: [ + text = strongSelf.presentationData.strings.Wallet_Send_UninitializedText + let controller = textAlertController(context: strongSelf.context, title: strongSelf.presentationData.strings.Wallet_Send_UninitializedTitle, text: text, actions: [ TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: { if let navigationController = strongSelf.navigationController as? NavigationController { navigationController.popViewController(animated: true) diff --git a/submodules/WalletUI/Sources/WalletUtils.swift b/submodules/WalletUI/Sources/WalletUtils.swift index 92cd45461c..8f63247cd5 100644 --- a/submodules/WalletUI/Sources/WalletUtils.swift +++ b/submodules/WalletUI/Sources/WalletUtils.swift @@ -3,7 +3,7 @@ import TelegramStringFormatting import UrlEscaping let walletAddressLength: Int = 48 -let walletTextLimit: Int = 124 +let walletTextLimit: Int = 1024 func formatAddress(_ address: String) -> String { var address = address diff --git a/submodules/ton/tonlib-src/crypto/CMakeLists.txt b/submodules/ton/tonlib-src/crypto/CMakeLists.txt index c76de707c9..acf88eeef6 100644 --- a/submodules/ton/tonlib-src/crypto/CMakeLists.txt +++ b/submodules/ton/tonlib-src/crypto/CMakeLists.txt @@ -315,6 +315,8 @@ if (NOT CMAKE_CROSSCOMPILING) GenFif(DEST smartcont/config-code.fif SOURCE smartcont/config-code.fc) GenFif(DEST smartcont/wallet-code.fif SOURCE smartcont/wallet-code.fc) GenFif(DEST smartcont/simple-wallet-code.fif SOURCE smartcont/simple-wallet-code.fc) + GenFif(DEST smartcont/highload-wallet-code.fif SOURCE smartcont/highload-wallet-code.fc) + GenFif(DEST smartcont/highload-wallet-v2-code.fif SOURCE smartcont/highload-wallet-v2-code.fc) GenFif(DEST smartcont/elector-code.fif SOURCE smartcont/elector-code.fc) endif() @@ -333,3 +335,6 @@ target_link_libraries(dump-block PUBLIC ton_crypto fift-lib ton_block) if (WINGETOPT_FOUND) target_link_libraries_system(dump-block wingetopt) endif() + +install(TARGETS fift func RUNTIME DESTINATION bin) +install(DIRECTORY fift/lib/ DESTINATION lib/fift) diff --git a/submodules/ton/tonlib-src/crypto/block/block-auto.cpp b/submodules/ton/tonlib-src/crypto/block/block-auto.cpp index 14b34ee6bf..75dd9f659e 100644 --- a/submodules/ton/tonlib-src/crypto/block/block-auto.cpp +++ b/submodules/ton/tonlib-src/crypto/block/block-auto.cpp @@ -8891,6 +8891,7 @@ bool TransactionDescr::skip(vm::CellSlice& cs) const { && cs.advance(2); case trans_split_prepare: return cs.advance(528) + && t_Maybe_TrStoragePhase.skip(cs) && t_TrComputePhase.skip(cs) && t_Maybe_Ref_TrActionPhase.skip(cs) && cs.advance(2); @@ -8902,6 +8903,7 @@ bool TransactionDescr::skip(vm::CellSlice& cs) const { && cs.advance(1); case trans_merge_install: return cs.advance_ext(0x10210) + && t_Maybe_TrStoragePhase.skip(cs) && t_Maybe_TrCreditPhase.skip(cs) && t_TrComputePhase.skip(cs) && t_Maybe_Ref_TrActionPhase.skip(cs) @@ -8932,6 +8934,7 @@ bool TransactionDescr::validate_skip(vm::CellSlice& cs, bool weak) const { && cs.advance(2); case trans_split_prepare: return cs.advance(528) + && t_Maybe_TrStoragePhase.validate_skip(cs, weak) && t_TrComputePhase.validate_skip(cs, weak) && t_Maybe_Ref_TrActionPhase.validate_skip(cs, weak) && cs.advance(2); @@ -8947,6 +8950,7 @@ bool TransactionDescr::validate_skip(vm::CellSlice& cs, bool weak) const { return cs.fetch_ulong(4) == 7 && cs.advance(524) && t_Transaction.validate_skip_ref(cs, weak) + && t_Maybe_TrStoragePhase.validate_skip(cs, weak) && t_Maybe_TrCreditPhase.validate_skip(cs, weak) && t_TrComputePhase.validate_skip(cs, weak) && t_Maybe_Ref_TrActionPhase.validate_skip(cs, weak) @@ -8998,7 +9002,7 @@ bool TransactionDescr::cell_unpack_trans_storage(Ref cell_ref, Ref cell_ref, TransactionDescr::Rec bool TransactionDescr::unpack(vm::CellSlice& cs, TransactionDescr::Record_trans_split_prepare& data) const { return cs.fetch_ulong(4) == 4 && cs.fetch_subslice_to(524, data.split_info) + && t_Maybe_TrStoragePhase.fetch_to(cs, data.storage_ph) && t_TrComputePhase.fetch_to(cs, data.compute_ph) && t_Maybe_Ref_TrActionPhase.fetch_to(cs, data.action) && cs.fetch_bool_to(data.aborted) @@ -9082,6 +9087,7 @@ bool TransactionDescr::unpack(vm::CellSlice& cs, TransactionDescr::Record_trans_ return cs.fetch_ulong(4) == 7 && cs.fetch_subslice_to(524, data.split_info) && cs.fetch_ref_to(data.prepare_transaction) + && t_Maybe_TrStoragePhase.fetch_to(cs, data.storage_ph) && t_Maybe_TrCreditPhase.fetch_to(cs, data.credit_ph) && t_TrComputePhase.fetch_to(cs, data.compute_ph) && t_Maybe_Ref_TrActionPhase.fetch_to(cs, data.action) @@ -9135,7 +9141,7 @@ bool TransactionDescr::cell_pack_trans_storage(Ref& cell_ref, Ref& cell_ref, const TransactionDescr bool TransactionDescr::pack(vm::CellBuilder& cb, const TransactionDescr::Record_trans_split_prepare& data) const { return cb.store_long_bool(4, 4) && cb.append_cellslice_chk(data.split_info, 524) + && t_Maybe_TrStoragePhase.store_from(cb, data.storage_ph) && t_TrComputePhase.store_from(cb, data.compute_ph) && t_Maybe_Ref_TrActionPhase.store_from(cb, data.action) && cb.store_ulong_rchk_bool(data.aborted, 1) @@ -9213,6 +9220,7 @@ bool TransactionDescr::pack(vm::CellBuilder& cb, const TransactionDescr::Record_ return cb.store_long_bool(7, 4) && cb.append_cellslice_chk(data.split_info, 524) && cb.store_ref_bool(data.prepare_transaction) + && t_Maybe_TrStoragePhase.store_from(cb, data.storage_ph) && t_Maybe_TrCreditPhase.store_from(cb, data.credit_ph) && t_TrComputePhase.store_from(cb, data.compute_ph) && t_Maybe_Ref_TrActionPhase.store_from(cb, data.action) @@ -9254,7 +9262,7 @@ bool TransactionDescr::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const { return cs.advance(3) && pp.open("trans_tick_tock") && pp.fetch_uint_field(cs, 1, "is_tock") - && pp.field("storage") + && pp.field("storage_ph") && t_TrStoragePhase.print_skip(pp, cs) && pp.field("compute_ph") && t_TrComputePhase.print_skip(pp, cs) @@ -9268,6 +9276,8 @@ bool TransactionDescr::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const { && pp.open("trans_split_prepare") && pp.field("split_info") && t_SplitMergeInfo.print_skip(pp, cs) + && pp.field("storage_ph") + && t_Maybe_TrStoragePhase.print_skip(pp, cs) && pp.field("compute_ph") && t_TrComputePhase.print_skip(pp, cs) && pp.field("action") @@ -9300,6 +9310,8 @@ bool TransactionDescr::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const { && t_SplitMergeInfo.print_skip(pp, cs) && pp.field("prepare_transaction") && t_Transaction.print_ref(pp, cs.fetch_ref()) + && pp.field("storage_ph") + && t_Maybe_TrStoragePhase.print_skip(pp, cs) && pp.field("credit_ph") && t_Maybe_TrCreditPhase.print_skip(pp, cs) && pp.field("compute_ph") @@ -14089,11 +14101,13 @@ const StoragePrices t_StoragePrices; // // code for type `GasLimitsPrices` // -constexpr unsigned char GasLimitsPrices::cons_tag[2]; +constexpr unsigned char GasLimitsPrices::cons_tag[3]; int GasLimitsPrices::get_tag(const vm::CellSlice& cs) const { - switch (cs.bselect(6, 0x180000000000000ULL)) { + switch (cs.bselect(6, 0x1b0000000000000ULL)) { case 0: + return gas_flat_pfx; + case 2: return cs.bit_at(6) ? gas_prices_ext : gas_prices; default: return -1; @@ -14106,6 +14120,8 @@ int GasLimitsPrices::check_tag(const vm::CellSlice& cs) const { return cs.prefetch_ulong(8) == 0xdd ? gas_prices : -1; case gas_prices_ext: return cs.prefetch_ulong(8) == 0xde ? gas_prices_ext : -1; + case gas_flat_pfx: + return cs.prefetch_ulong(8) == 0xd1 ? gas_flat_pfx : -1; } return -1; } @@ -14116,6 +14132,9 @@ bool GasLimitsPrices::skip(vm::CellSlice& cs) const { return cs.advance(392); case gas_prices_ext: return cs.advance(456); + case gas_flat_pfx: + return cs.advance(136) + && skip(cs); } return false; } @@ -14128,6 +14147,10 @@ bool GasLimitsPrices::validate_skip(vm::CellSlice& cs, bool weak) const { case gas_prices_ext: return cs.fetch_ulong(8) == 0xde && cs.advance(448); + case gas_flat_pfx: + return cs.fetch_ulong(8) == 0xd1 + && cs.advance(128) + && validate_skip(cs, weak); } return false; } @@ -14165,6 +14188,32 @@ bool GasLimitsPrices::cell_unpack(Ref cell_ref, GasLimitsPrices::Recor return unpack(cs, data) && cs.empty_ext(); } +bool GasLimitsPrices::unpack(vm::CellSlice& cs, GasLimitsPrices::Record_gas_flat_pfx& data) const { + return cs.fetch_ulong(8) == 0xd1 + && cs.fetch_uint_to(64, data.flat_gas_limit) + && cs.fetch_uint_to(64, data.flat_gas_price) + && fetch_to(cs, data.other); +} + +bool GasLimitsPrices::unpack_gas_flat_pfx(vm::CellSlice& cs, unsigned long long& flat_gas_limit, unsigned long long& flat_gas_price, Ref& other) const { + return cs.fetch_ulong(8) == 0xd1 + && cs.fetch_uint_to(64, flat_gas_limit) + && cs.fetch_uint_to(64, flat_gas_price) + && fetch_to(cs, other); +} + +bool GasLimitsPrices::cell_unpack(Ref cell_ref, GasLimitsPrices::Record_gas_flat_pfx& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool GasLimitsPrices::cell_unpack_gas_flat_pfx(Ref cell_ref, unsigned long long& flat_gas_limit, unsigned long long& flat_gas_price, Ref& other) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_gas_flat_pfx(cs, flat_gas_limit, flat_gas_price, other) && cs.empty_ext(); +} + bool GasLimitsPrices::pack(vm::CellBuilder& cb, const GasLimitsPrices::Record_gas_prices& data) const { return cb.store_long_bool(0xdd, 8) && cb.store_ulong_rchk_bool(data.gas_price, 64) @@ -14196,6 +14245,30 @@ bool GasLimitsPrices::cell_pack(Ref& cell_ref, const GasLimitsPrices:: return pack(cb, data) && std::move(cb).finalize_to(cell_ref); } +bool GasLimitsPrices::pack(vm::CellBuilder& cb, const GasLimitsPrices::Record_gas_flat_pfx& data) const { + return cb.store_long_bool(0xd1, 8) + && cb.store_ulong_rchk_bool(data.flat_gas_limit, 64) + && cb.store_ulong_rchk_bool(data.flat_gas_price, 64) + && store_from(cb, data.other); +} + +bool GasLimitsPrices::pack_gas_flat_pfx(vm::CellBuilder& cb, unsigned long long flat_gas_limit, unsigned long long flat_gas_price, Ref other) const { + return cb.store_long_bool(0xd1, 8) + && cb.store_ulong_rchk_bool(flat_gas_limit, 64) + && cb.store_ulong_rchk_bool(flat_gas_price, 64) + && store_from(cb, other); +} + +bool GasLimitsPrices::cell_pack(Ref& cell_ref, const GasLimitsPrices::Record_gas_flat_pfx& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool GasLimitsPrices::cell_pack_gas_flat_pfx(Ref& cell_ref, unsigned long long flat_gas_limit, unsigned long long flat_gas_price, Ref other) const { + vm::CellBuilder cb; + return pack_gas_flat_pfx(cb, flat_gas_limit, flat_gas_price, std::move(other)) && std::move(cb).finalize_to(cell_ref); +} + bool GasLimitsPrices::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const { switch (get_tag(cs)) { case gas_prices: @@ -14219,6 +14292,14 @@ bool GasLimitsPrices::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const { && pp.fetch_uint_field(cs, 64, "freeze_due_limit") && pp.fetch_uint_field(cs, 64, "delete_due_limit") && pp.close(); + case gas_flat_pfx: + return cs.fetch_ulong(8) == 0xd1 + && pp.open("gas_flat_pfx") + && pp.fetch_uint_field(cs, 64, "flat_gas_limit") + && pp.fetch_uint_field(cs, 64, "flat_gas_price") + && pp.field("other") + && print_skip(pp, cs) + && pp.close(); } return pp.fail("unknown constructor for GasLimitsPrices"); } diff --git a/submodules/ton/tonlib-src/crypto/block/block-auto.h b/submodules/ton/tonlib-src/crypto/block/block-auto.h index 66b9700333..fb9e1770d6 100644 --- a/submodules/ton/tonlib-src/crypto/block/block-auto.h +++ b/submodules/ton/tonlib-src/crypto/block/block-auto.h @@ -3831,24 +3831,25 @@ struct TransactionDescr::Record_trans_ord { struct TransactionDescr::Record_trans_tick_tock { typedef TransactionDescr type_class; bool is_tock; // is_tock : Bool - Ref storage; // storage : TrStoragePhase + Ref storage_ph; // storage_ph : TrStoragePhase Ref compute_ph; // compute_ph : TrComputePhase Ref action; // action : Maybe ^TrActionPhase bool aborted; // aborted : Bool bool destroyed; // destroyed : Bool Record_trans_tick_tock() = default; - Record_trans_tick_tock(bool _is_tock, Ref _storage, Ref _compute_ph, Ref _action, bool _aborted, bool _destroyed) : is_tock(_is_tock), storage(std::move(_storage)), compute_ph(std::move(_compute_ph)), action(std::move(_action)), aborted(_aborted), destroyed(_destroyed) {} + Record_trans_tick_tock(bool _is_tock, Ref _storage_ph, Ref _compute_ph, Ref _action, bool _aborted, bool _destroyed) : is_tock(_is_tock), storage_ph(std::move(_storage_ph)), compute_ph(std::move(_compute_ph)), action(std::move(_action)), aborted(_aborted), destroyed(_destroyed) {} }; struct TransactionDescr::Record_trans_split_prepare { typedef TransactionDescr type_class; Ref split_info; // split_info : SplitMergeInfo + Ref storage_ph; // storage_ph : Maybe TrStoragePhase Ref compute_ph; // compute_ph : TrComputePhase Ref action; // action : Maybe ^TrActionPhase bool aborted; // aborted : Bool bool destroyed; // destroyed : Bool Record_trans_split_prepare() = default; - Record_trans_split_prepare(Ref _split_info, Ref _compute_ph, Ref _action, bool _aborted, bool _destroyed) : split_info(std::move(_split_info)), compute_ph(std::move(_compute_ph)), action(std::move(_action)), aborted(_aborted), destroyed(_destroyed) {} + Record_trans_split_prepare(Ref _split_info, Ref _storage_ph, Ref _compute_ph, Ref _action, bool _aborted, bool _destroyed) : split_info(std::move(_split_info)), storage_ph(std::move(_storage_ph)), compute_ph(std::move(_compute_ph)), action(std::move(_action)), aborted(_aborted), destroyed(_destroyed) {} }; struct TransactionDescr::Record_trans_split_install { @@ -3873,13 +3874,14 @@ struct TransactionDescr::Record_trans_merge_install { typedef TransactionDescr type_class; Ref split_info; // split_info : SplitMergeInfo Ref prepare_transaction; // prepare_transaction : ^Transaction + Ref storage_ph; // storage_ph : Maybe TrStoragePhase Ref credit_ph; // credit_ph : Maybe TrCreditPhase Ref compute_ph; // compute_ph : TrComputePhase Ref action; // action : Maybe ^TrActionPhase bool aborted; // aborted : Bool bool destroyed; // destroyed : Bool Record_trans_merge_install() = default; - Record_trans_merge_install(Ref _split_info, Ref _prepare_transaction, Ref _credit_ph, Ref _compute_ph, Ref _action, bool _aborted, bool _destroyed) : split_info(std::move(_split_info)), prepare_transaction(std::move(_prepare_transaction)), credit_ph(std::move(_credit_ph)), compute_ph(std::move(_compute_ph)), action(std::move(_action)), aborted(_aborted), destroyed(_destroyed) {} + Record_trans_merge_install(Ref _split_info, Ref _prepare_transaction, Ref _storage_ph, Ref _credit_ph, Ref _compute_ph, Ref _action, bool _aborted, bool _destroyed) : split_info(std::move(_split_info)), prepare_transaction(std::move(_prepare_transaction)), storage_ph(std::move(_storage_ph)), credit_ph(std::move(_credit_ph)), compute_ph(std::move(_compute_ph)), action(std::move(_action)), aborted(_aborted), destroyed(_destroyed) {} }; extern const TransactionDescr t_TransactionDescr; @@ -6166,11 +6168,12 @@ extern const StoragePrices t_StoragePrices; // struct GasLimitsPrices final : TLB_Complex { - enum { gas_prices, gas_prices_ext }; + enum { gas_flat_pfx, gas_prices, gas_prices_ext }; static constexpr int cons_len_exact = 8; - static constexpr unsigned char cons_tag[2] = { 0xdd, 0xde }; + static constexpr unsigned char cons_tag[3] = { 0xd1, 0xdd, 0xde }; struct Record_gas_prices; struct Record_gas_prices_ext; + struct Record_gas_flat_pfx; bool skip(vm::CellSlice& cs) const override; bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record_gas_prices& data) const; @@ -6181,6 +6184,14 @@ struct GasLimitsPrices final : TLB_Complex { bool cell_unpack(Ref cell_ref, Record_gas_prices_ext& data) const; bool pack(vm::CellBuilder& cb, const Record_gas_prices_ext& data) const; bool cell_pack(Ref& cell_ref, const Record_gas_prices_ext& data) const; + bool unpack(vm::CellSlice& cs, Record_gas_flat_pfx& data) const; + bool unpack_gas_flat_pfx(vm::CellSlice& cs, unsigned long long& flat_gas_limit, unsigned long long& flat_gas_price, Ref& other) const; + bool cell_unpack(Ref cell_ref, Record_gas_flat_pfx& data) const; + bool cell_unpack_gas_flat_pfx(Ref cell_ref, unsigned long long& flat_gas_limit, unsigned long long& flat_gas_price, Ref& other) const; + bool pack(vm::CellBuilder& cb, const Record_gas_flat_pfx& data) const; + bool pack_gas_flat_pfx(vm::CellBuilder& cb, unsigned long long flat_gas_limit, unsigned long long flat_gas_price, Ref other) const; + bool cell_pack(Ref& cell_ref, const Record_gas_flat_pfx& data) const; + bool cell_pack_gas_flat_pfx(Ref& cell_ref, unsigned long long flat_gas_limit, unsigned long long flat_gas_price, Ref other) const; bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override; std::ostream& print_type(std::ostream& os) const override { return os << "GasLimitsPrices"; @@ -6214,6 +6225,15 @@ struct GasLimitsPrices::Record_gas_prices_ext { Record_gas_prices_ext(unsigned long long _gas_price, unsigned long long _gas_limit, unsigned long long _special_gas_limit, unsigned long long _gas_credit, unsigned long long _block_gas_limit, unsigned long long _freeze_due_limit, unsigned long long _delete_due_limit) : gas_price(_gas_price), gas_limit(_gas_limit), special_gas_limit(_special_gas_limit), gas_credit(_gas_credit), block_gas_limit(_block_gas_limit), freeze_due_limit(_freeze_due_limit), delete_due_limit(_delete_due_limit) {} }; +struct GasLimitsPrices::Record_gas_flat_pfx { + typedef GasLimitsPrices type_class; + unsigned long long flat_gas_limit; // flat_gas_limit : uint64 + unsigned long long flat_gas_price; // flat_gas_price : uint64 + Ref other; // other : GasLimitsPrices + Record_gas_flat_pfx() = default; + Record_gas_flat_pfx(unsigned long long _flat_gas_limit, unsigned long long _flat_gas_price, Ref _other) : flat_gas_limit(_flat_gas_limit), flat_gas_price(_flat_gas_price), other(std::move(_other)) {} +}; + extern const GasLimitsPrices t_GasLimitsPrices; // @@ -6522,7 +6542,7 @@ extern const ValidatorSignedTempKey t_ValidatorSignedTempKey; // struct ConfigParam final : TLB_Complex { - enum { cons32, cons33, cons34, cons35, cons36, cons37, config_mc_block_limits, config_block_limits, cons14, cons0, cons1, cons2, cons3, cons4, cons6, cons7, cons9, cons12, cons15, cons16, cons17, cons18, cons31, cons39, cons28, cons8, cons29, config_mc_gas_prices, config_gas_prices, config_mc_fwd_prices, config_fwd_prices }; + enum { cons32, cons33, cons34, cons35, cons36, cons37, config_mc_block_limits, config_block_limits, cons14, cons0, cons1, cons2, cons3, cons4, cons6, cons7, cons9, cons12, cons15, cons16, cons17, cons18, cons31, cons39, cons28, cons8, config_mc_gas_prices, config_gas_prices, cons29, config_mc_fwd_prices, config_fwd_prices }; static constexpr int cons_len_exact = 0; int m_; ConfigParam(int m) : m_(m) {} diff --git a/submodules/ton/tonlib-src/crypto/block/block-parse.cpp b/submodules/ton/tonlib-src/crypto/block/block-parse.cpp index 89fc3d6f02..c410e2cb53 100644 --- a/submodules/ton/tonlib-src/crypto/block/block-parse.cpp +++ b/submodules/ton/tonlib-src/crypto/block/block-parse.cpp @@ -1143,6 +1143,20 @@ bool TrStoragePhase::validate_skip(vm::CellSlice& cs, bool weak) const { && t_AccStatusChange.validate_skip(cs, weak); // status_change:AccStatusChange } +bool TrStoragePhase::get_storage_fees(vm::CellSlice& cs, td::RefInt256& storage_fees) const { + return t_Grams.as_integer_skip_to(cs, storage_fees); // storage_fees_collected:Grams +} + +bool TrStoragePhase::maybe_get_storage_fees(vm::CellSlice& cs, td::RefInt256& storage_fees) const { + auto z = cs.fetch_ulong(1); + if (!z) { + storage_fees = td::make_refint(0); + return true; + } else { + return z == 1 && get_storage_fees(cs, storage_fees); + } +} + const TrStoragePhase t_TrStoragePhase; bool TrCreditPhase::skip(vm::CellSlice& cs) const { @@ -1322,13 +1336,14 @@ bool TransactionDescr::skip(vm::CellSlice& cs) const { && t_TrStoragePhase.skip(cs); // storage_ph:TrStoragePhase case trans_tick_tock: return cs.advance(4) // trans_tick_tock$001 is_tock:Bool - && t_TrStoragePhase.skip(cs) // storage:TrStoragePhase + && t_TrStoragePhase.skip(cs) // storage_ph:TrStoragePhase && t_TrComputePhase.skip(cs) // compute_ph:TrComputePhase && Maybe>{}.skip(cs) // action:(Maybe ^TrActionPhase) && cs.advance(2); // aborted:Bool destroyed:Bool case trans_split_prepare: return cs.advance(4) // trans_split_prepare$0100 && t_SplitMergeInfo.skip(cs) // split_info:SplitMergeInfo + && Maybe{}.skip(cs) // storage_ph:(Maybe TrStoragePhase) && t_TrComputePhase.skip(cs) // compute_ph:TrComputePhase && Maybe>{}.skip(cs) // action:(Maybe ^TrActionPhase) && cs.advance(2); // aborted:Bool destroyed:Bool @@ -1346,6 +1361,7 @@ bool TransactionDescr::skip(vm::CellSlice& cs) const { return cs.advance(4) // trans_merge_install$0111 && t_SplitMergeInfo.skip(cs) // split_info:SplitMergeInfo && t_Ref_Transaction.skip(cs) // prepare_transaction:^Transaction + && Maybe{}.skip(cs) // storage_ph:(Maybe TrStoragePhase) && Maybe{}.skip(cs) // credit_ph:(Maybe TrCreditPhase) && Maybe{}.skip(cs) // compute_ph:TrComputePhase && Maybe>{}.skip(cs) // action:(Maybe ^TrActionPhase) @@ -1370,13 +1386,14 @@ bool TransactionDescr::validate_skip(vm::CellSlice& cs, bool weak) const { && t_TrStoragePhase.validate_skip(cs, weak); // storage_ph:TrStoragePhase case trans_tick_tock: return cs.advance(4) // trans_tick_tock$001 is_tock:Bool - && t_TrStoragePhase.validate_skip(cs, weak) // storage:TrStoragePhase + && t_TrStoragePhase.validate_skip(cs, weak) // storage_ph:TrStoragePhase && t_TrComputePhase.validate_skip(cs, weak) // compute_ph:TrComputePhase && Maybe>{}.validate_skip(cs, weak) // action:(Maybe ^TrActionPhase) && cs.advance(2); // aborted:Bool destroyed:Bool case trans_split_prepare: return cs.advance(4) // trans_split_prepare$0100 && t_SplitMergeInfo.validate_skip(cs, weak) // split_info:SplitMergeInfo + && Maybe{}.validate_skip(cs, weak) // storage_ph:(Maybe TrStoragePhase) && t_TrComputePhase.validate_skip(cs, weak) // compute_ph:TrComputePhase && Maybe>{}.validate_skip(cs, weak) // action:(Maybe ^TrActionPhase) && cs.advance(2); // aborted:Bool destroyed:Bool @@ -1394,6 +1411,7 @@ bool TransactionDescr::validate_skip(vm::CellSlice& cs, bool weak) const { return cs.advance(4) // trans_merge_install$0111 && t_SplitMergeInfo.validate_skip(cs, weak) // split_info:SplitMergeInfo && t_Ref_Transaction.validate_skip(cs, weak) // prepare_transaction:^Transaction + && Maybe{}.validate_skip(cs, weak) // storage_ph:(Maybe TrStoragePhase) && Maybe{}.validate_skip(cs, weak) // credit_ph:(Maybe TrCreditPhase) && Maybe{}.validate_skip(cs, weak) // compute_ph:TrComputePhase && Maybe>{}.validate_skip(cs, weak) // action:(Maybe ^TrActionPhase) @@ -1407,6 +1425,53 @@ int TransactionDescr::get_tag(const vm::CellSlice& cs) const { return (t >= 0 && t <= 7) ? (t == 3 ? 2 : t) : -1; } +bool TransactionDescr::skip_to_storage_phase(vm::CellSlice& cs, bool& found) const { + found = false; + switch (get_tag(cs)) { + case trans_ord: + return cs.advance(4 + 1) // trans_ord$0000 storage_first:Bool + && cs.fetch_bool_to(found); // storage_ph:(Maybe TrStoragePhase) + case trans_storage: + return cs.advance(4) // trans_storage$0001 + && (found = true); // storage_ph:TrStoragePhase + case trans_tick_tock: + return cs.advance(4) // trans_tick_tock$001 is_tock:Bool + && (found = true); // storage_ph:TrStoragePhase + case trans_split_prepare: + return cs.advance(4) // trans_split_prepare$0100 + && t_SplitMergeInfo.skip(cs) // split_info:SplitMergeInfo + && cs.fetch_bool_to(found); // storage_ph:(Maybe TrStoragePhase) + case trans_split_install: + return true; + case trans_merge_prepare: + return cs.advance(4) // trans_merge_prepare$0110 + && t_SplitMergeInfo.skip(cs) // split_info:SplitMergeInfo + && (found = true); // storage_ph:TrStoragePhase + case trans_merge_install: + return cs.advance(4) // trans_merge_install$0111 + && t_SplitMergeInfo.skip(cs) // split_info:SplitMergeInfo + && t_Ref_Transaction.skip(cs) // prepare_transaction:^Transaction + && cs.fetch_bool_to(found); // storage_ph:(Maybe TrStoragePhase) + } + return false; +} + +bool TransactionDescr::get_storage_fees(Ref cell, td::RefInt256& storage_fees) const { + if (cell.is_null()) { + return false; + } + auto cs = vm::load_cell_slice(std::move(cell)); + bool found; + if (!skip_to_storage_phase(cs, found)) { + return false; + } else if (found) { + return t_TrStoragePhase.get_storage_fees(cs, storage_fees); + } else { + storage_fees = td::make_refint(0); + return true; + } +} + const TransactionDescr t_TransactionDescr; bool Transaction_aux::skip(vm::CellSlice& cs) const { @@ -1447,6 +1512,32 @@ bool Transaction::validate_skip(vm::CellSlice& cs, bool weak) const { && RefTo{}.validate_skip(cs, weak); // description:^TransactionDescr } +bool Transaction::get_storage_fees(Ref cell, td::RefInt256& storage_fees) const { + Ref tdescr; + return get_descr(std::move(cell), tdescr) && t_TransactionDescr.get_storage_fees(std::move(tdescr), storage_fees); +} + +bool Transaction::get_descr(Ref cell, Ref& tdescr) const { + if (cell.is_null()) { + return false; + } else { + auto cs = vm::load_cell_slice(std::move(cell)); + return cs.is_valid() && get_descr(cs, tdescr) && cs.empty_ext(); + } +} + +bool Transaction::get_descr(vm::CellSlice& cs, Ref& tdescr) const { + return cs.advance( + 4 + 256 + 64 + 256 + 64 + 32 + + 15) // transaction$0111 account_addr:uint256 lt:uint64 prev_trans_hash:bits256 prev_trans_lt:uint64 now:uint32 outmsg_cnt:uint15 + && t_AccountStatus.skip(cs) // orig_status:AccountStatus + && t_AccountStatus.skip(cs) // end_status:AccountStatus + && cs.advance_refs(1) // ^[ in_msg:(Maybe ^Message) out_msgs:(HashmapE 15 ^Message) ] + && t_CurrencyCollection.skip(cs) // total_fees:CurrencyCollection + && cs.advance_refs(1) // state_update:^(MERKLE_UPDATE Account) + && cs.fetch_ref_to(tdescr); // description:^TransactionDescr +} + bool Transaction::get_total_fees(vm::CellSlice&& cs, block::CurrencyCollection& total_fees) const { return cs.is_valid() && cs.fetch_ulong(4) == 7 // transaction$0111 && diff --git a/submodules/ton/tonlib-src/crypto/block/block-parse.h b/submodules/ton/tonlib-src/crypto/block/block-parse.h index 381dc149f3..acbe9dd426 100644 --- a/submodules/ton/tonlib-src/crypto/block/block-parse.h +++ b/submodules/ton/tonlib-src/crypto/block/block-parse.h @@ -614,6 +614,8 @@ extern const AccStatusChange t_AccStatusChange; struct TrStoragePhase final : TLB_Complex { bool skip(vm::CellSlice& cs) const override; bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool get_storage_fees(vm::CellSlice& cs, td::RefInt256& storage_fees) const; + bool maybe_get_storage_fees(vm::CellSlice& cs, td::RefInt256& storage_fees) const; }; extern const TrStoragePhase t_TrStoragePhase; @@ -693,6 +695,8 @@ struct TransactionDescr final : TLB_Complex { bool skip(vm::CellSlice& cs) const override; bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; int get_tag(const vm::CellSlice& cs) const override; + bool skip_to_storage_phase(vm::CellSlice& cs, bool& found) const; + bool get_storage_fees(Ref cell, td::RefInt256& storage_fees) const; }; extern const TransactionDescr t_TransactionDescr; @@ -708,6 +712,9 @@ struct Transaction final : TLB_Complex { bool skip(vm::CellSlice& cs) const override; bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; bool get_total_fees(vm::CellSlice&& cs, block::CurrencyCollection& total_fees) const; + bool get_descr(Ref cell, Ref& tdescr) const; + bool get_descr(vm::CellSlice& cs, Ref& tdescr) const; + bool get_storage_fees(Ref cell, td::RefInt256& storage_fees) const; }; extern const Transaction t_Transaction; diff --git a/submodules/ton/tonlib-src/crypto/block/block.cpp b/submodules/ton/tonlib-src/crypto/block/block.cpp index 6a0234f3ab..7b8074bfbc 100644 --- a/submodules/ton/tonlib-src/crypto/block/block.cpp +++ b/submodules/ton/tonlib-src/crypto/block/block.cpp @@ -368,14 +368,14 @@ std::unique_ptr MsgProcessedUptoCollection::unpack(t return v && v->valid ? std::move(v) : std::unique_ptr{}; } -bool MsgProcessedUpto::contains(const MsgProcessedUpto& other) const& { +bool MsgProcessedUpto::contains(const MsgProcessedUpto& other) const & { return ton::shard_is_ancestor(shard, other.shard) && mc_seqno >= other.mc_seqno && (last_inmsg_lt > other.last_inmsg_lt || (last_inmsg_lt == other.last_inmsg_lt && !(last_inmsg_hash < other.last_inmsg_hash))); } bool MsgProcessedUpto::contains(ton::ShardId other_shard, ton::LogicalTime other_lt, td::ConstBitPtr other_hash, - ton::BlockSeqno other_mc_seqno) const& { + ton::BlockSeqno other_mc_seqno) const & { return ton::shard_is_ancestor(shard, other_shard) && mc_seqno >= other_mc_seqno && (last_inmsg_lt > other_lt || (last_inmsg_lt == other_lt && !(last_inmsg_hash < other_hash))); } @@ -552,7 +552,9 @@ bool MsgProcessedUpto::already_processed(const EnqueuedMsgDescr& msg) const { if (msg.lt_ == last_inmsg_lt && last_inmsg_hash < msg.hash_) { return false; } - if (ton::shard_contains(shard, msg.cur_prefix_.account_id_prefix)) { + if (msg.same_workchain() && ton::shard_contains(shard, msg.cur_prefix_.account_id_prefix)) { + // this branch is needed only for messages generated in the same shard + // (such messages could have been processed without a reference from the masterchain) // ? enable this branch only if an extra boolean parameter is set ? return true; } diff --git a/submodules/ton/tonlib-src/crypto/block/block.h b/submodules/ton/tonlib-src/crypto/block/block.h index 377f99c2b8..9fbeedf29f 100644 --- a/submodules/ton/tonlib-src/crypto/block/block.h +++ b/submodules/ton/tonlib-src/crypto/block/block.h @@ -145,6 +145,9 @@ struct EnqueuedMsgDescr { return false; } bool unpack(vm::CellSlice& cs); + bool same_workchain() const { + return cur_prefix_.workchain == next_prefix_.workchain; + } }; using compute_shard_end_lt_func_t = std::function; diff --git a/submodules/ton/tonlib-src/crypto/block/block.tlb b/submodules/ton/tonlib-src/crypto/block/block.tlb index b9db5fe6ec..5108294770 100644 --- a/submodules/ton/tonlib-src/crypto/block/block.tlb +++ b/submodules/ton/tonlib-src/crypto/block/block.tlb @@ -325,7 +325,7 @@ trans_ord$0000 credit_first:Bool trans_storage$0001 storage_ph:TrStoragePhase = TransactionDescr; -trans_tick_tock$001 is_tock:Bool storage:TrStoragePhase +trans_tick_tock$001 is_tock:Bool storage_ph:TrStoragePhase compute_ph:TrComputePhase action:(Maybe ^TrActionPhase) aborted:Bool destroyed:Bool = TransactionDescr; // @@ -333,6 +333,7 @@ split_merge_info$_ cur_shard_pfx_len:(## 6) acc_split_depth:(## 6) this_addr:bits256 sibling_addr:bits256 = SplitMergeInfo; trans_split_prepare$0100 split_info:SplitMergeInfo + storage_ph:(Maybe TrStoragePhase) compute_ph:TrComputePhase action:(Maybe ^TrActionPhase) aborted:Bool destroyed:Bool = TransactionDescr; @@ -345,6 +346,7 @@ trans_merge_prepare$0110 split_info:SplitMergeInfo = TransactionDescr; trans_merge_install$0111 split_info:SplitMergeInfo prepare_transaction:^Transaction + storage_ph:(Maybe TrStoragePhase) credit_ph:(Maybe TrCreditPhase) compute_ph:TrComputePhase action:(Maybe ^TrActionPhase) aborted:Bool destroyed:Bool @@ -609,6 +611,9 @@ gas_prices_ext#de gas_price:uint64 gas_limit:uint64 special_gas_limit:uint64 gas block_gas_limit:uint64 freeze_due_limit:uint64 delete_due_limit:uint64 = GasLimitsPrices; +gas_flat_pfx#d1 flat_gas_limit:uint64 flat_gas_price:uint64 other:GasLimitsPrices + = GasLimitsPrices; + config_mc_gas_prices#_ GasLimitsPrices = ConfigParam 20; config_gas_prices#_ GasLimitsPrices = ConfigParam 21; diff --git a/submodules/ton/tonlib-src/crypto/block/transaction.cpp b/submodules/ton/tonlib-src/crypto/block/transaction.cpp index 11f118d4d3..24fc731ee4 100644 --- a/submodules/ton/tonlib-src/crypto/block/transaction.cpp +++ b/submodules/ton/tonlib-src/crypto/block/transaction.cpp @@ -672,9 +672,56 @@ bool Transaction::prepare_credit_phase() { return true; } +bool ComputePhaseConfig::parse_GasLimitsPrices(Ref cell, td::RefInt256& freeze_due_limit, + td::RefInt256& delete_due_limit) { + return cell.not_null() && + parse_GasLimitsPrices(vm::load_cell_slice_ref(std::move(cell)), freeze_due_limit, delete_due_limit); +} + +bool ComputePhaseConfig::parse_GasLimitsPrices(Ref cs, td::RefInt256& freeze_due_limit, + td::RefInt256& delete_due_limit) { + if (cs.is_null()) { + return false; + } + block::gen::GasLimitsPrices::Record_gas_flat_pfx flat; + if (tlb::csr_unpack(cs, flat)) { + bool ok = parse_GasLimitsPrices(std::move(flat.other), freeze_due_limit, delete_due_limit); + flat_gas_limit = flat.flat_gas_limit; + flat_gas_price = flat.flat_gas_price; + return ok; + } + flat_gas_limit = flat_gas_price = 0; + auto f = [&](const auto& r, td::uint64 spec_limit) { + gas_limit = r.gas_limit; + special_gas_limit = spec_limit; + gas_credit = r.gas_credit; + gas_price = r.gas_price; + freeze_due_limit = td::RefInt256{true, r.freeze_due_limit}; + delete_due_limit = td::RefInt256{true, r.delete_due_limit}; + }; + block::gen::GasLimitsPrices::Record_gas_prices_ext rec; + if (tlb::csr_unpack(cs, rec)) { + f(rec, rec.special_gas_limit); + } else { + block::gen::GasLimitsPrices::Record_gas_prices rec0; + if (tlb::csr_unpack(std::move(cs), rec0)) { + f(rec0, rec0.gas_limit); + } else { + return false; + } + } + compute_threshold(); + return true; +} + void ComputePhaseConfig::compute_threshold() { gas_price256 = td::RefInt256{true, gas_price}; - max_gas_threshold = td::rshift(gas_price256 * gas_limit, 16, 1); + if (gas_limit > flat_gas_limit) { + max_gas_threshold = + td::rshift(gas_price256 * (gas_limit - flat_gas_limit), 16, 1) + td::make_refint(flat_gas_price); + } else { + max_gas_threshold = td::make_refint(flat_gas_price); + } } td::uint64 ComputePhaseConfig::gas_bought_for(td::RefInt256 nanograms) const { @@ -684,8 +731,11 @@ td::uint64 ComputePhaseConfig::gas_bought_for(td::RefInt256 nanograms) const { if (nanograms >= max_gas_threshold) { return gas_limit; } - auto res = td::div(std::move(nanograms) << 16, gas_price256); - return res->to_long(); + if (nanograms < flat_gas_price) { + return 0; + } + auto res = td::div((std::move(nanograms) - flat_gas_price) << 16, gas_price256); + return res->to_long() + flat_gas_limit; } td::RefInt256 ComputePhaseConfig::compute_gas_price(td::uint64 gas_used) const { @@ -855,6 +905,16 @@ bool Transaction::prepare_compute_phase(const ComputePhaseConfig& cfg) { cp.skip_reason = ComputePhase::sk_no_gas; return true; } + // Compute gas limits + if (!compute_gas_limits(cp, cfg)) { + compute_phase.reset(); + return false; + } + if (!cp.gas_limit && !cp.gas_credit) { + // no gas + cp.skip_reason = ComputePhase::sk_no_gas; + return true; + } if (in_msg_state.not_null()) { LOG(DEBUG) << "HASH(in_msg_state) = " << in_msg_state->get_hash().bits().to_hex(256) << ", account_state_hash = " << account.state_hash.to_hex(); @@ -883,11 +943,6 @@ bool Transaction::prepare_compute_phase(const ComputePhaseConfig& cfg) { } else if (in_msg_state.not_null()) { unpack_msg_state(true); // use only libraries } - // Compute gas limits - if (!compute_gas_limits(cp, cfg)) { - compute_phase.reset(); - return false; - } // initialize VM Ref stack = prepare_vm_stack(cp); if (stack.is_null()) { diff --git a/submodules/ton/tonlib-src/crypto/block/transaction.h b/submodules/ton/tonlib-src/crypto/block/transaction.h index 45e824c1e8..015dc3f39e 100644 --- a/submodules/ton/tonlib-src/crypto/block/transaction.h +++ b/submodules/ton/tonlib-src/crypto/block/transaction.h @@ -98,6 +98,8 @@ struct ComputePhaseConfig { td::uint64 gas_limit; td::uint64 special_gas_limit; td::uint64 gas_credit; + td::uint64 flat_gas_limit = 0; + td::uint64 flat_gas_price = 0; static constexpr td::uint64 gas_infty = (1ULL << 63) - 1; td::RefInt256 gas_price256; td::RefInt256 max_gas_threshold; @@ -126,6 +128,8 @@ struct ComputePhaseConfig { Ref get_lib_root() const { return libraries ? libraries->get_root_cell() : Ref{}; } + bool parse_GasLimitsPrices(Ref cs, td::RefInt256& freeze_due_limit, td::RefInt256& delete_due_limit); + bool parse_GasLimitsPrices(Ref cell, td::RefInt256& freeze_due_limit, td::RefInt256& delete_due_limit); }; // msg_fwd_fees = (lump_price + ceil((bit_price * msg.bits + cell_price * msg.cells)/2^16)) nanograms diff --git a/submodules/ton/tonlib-src/crypto/fift/SourceLookup.h b/submodules/ton/tonlib-src/crypto/fift/SourceLookup.h index 33ee71d4ef..7d51396cb3 100644 --- a/submodules/ton/tonlib-src/crypto/fift/SourceLookup.h +++ b/submodules/ton/tonlib-src/crypto/fift/SourceLookup.h @@ -79,7 +79,7 @@ class SourceLookup { if (os_time_) { return os_time_->now(); } - return static_cast(td::Time::now()); + return static_cast(td::Clocks::system()); } protected: diff --git a/submodules/ton/tonlib-src/crypto/fift/lib/Fift.fif b/submodules/ton/tonlib-src/crypto/fift/lib/Fift.fif index 59cbcb713f..65fecb3116 100644 --- a/submodules/ton/tonlib-src/crypto/fift/lib/Fift.fif +++ b/submodules/ton/tonlib-src/crypto/fift/lib/Fift.fif @@ -25,7 +25,7 @@ { bl word 1 { -rot 2 'nop does swap 0 (create) } } :: 2=: { } : s>c -{ s>c hash } : shash +{ s>c hashB } : shash // to be more efficiently re-implemented in C++ in the future { dup 0< ' negate if } : abs { 2dup > ' swap if } : minmax diff --git a/submodules/ton/tonlib-src/crypto/fift/words.cpp b/submodules/ton/tonlib-src/crypto/fift/words.cpp index 01dcf802c8..0b97ece94e 100644 --- a/submodules/ton/tonlib-src/crypto/fift/words.cpp +++ b/submodules/ton/tonlib-src/crypto/fift/words.cpp @@ -764,13 +764,17 @@ void interpret_string_to_bytes(vm::Stack& stack) { stack.push_bytes(stack.pop_string()); } -void interpret_bytes_hash(vm::Stack& stack) { +void interpret_bytes_hash(vm::Stack& stack, bool as_uint) { std::string str = stack.pop_bytes(); unsigned char buffer[32]; digest::hash_str(buffer, str.c_str(), str.size()); - td::RefInt256 x{true}; - x.write().import_bytes(buffer, 32, false); - stack.push_int(std::move(x)); + if (as_uint) { + td::RefInt256 x{true}; + x.write().import_bytes(buffer, 32, false); + stack.push_int(std::move(x)); + } else { + stack.push_bytes(std::string{(char*)buffer, 32}); + } } void interpret_empty(vm::Stack& stack) { @@ -892,11 +896,15 @@ void interpret_builder_remaining_bitrefs(vm::Stack& stack, int mode) { } } -void interpret_cell_hash(vm::Stack& stack) { +void interpret_cell_hash(vm::Stack& stack, bool as_uint) { auto cell = stack.pop_cell(); - td::RefInt256 hash{true}; - hash.write().import_bytes(cell->get_hash().as_slice().ubegin(), 32, false); - stack.push_int(std::move(hash)); + if (as_uint) { + td::RefInt256 hash{true}; + hash.write().import_bytes(cell->get_hash().as_slice().ubegin(), 32, false); + stack.push_int(std::move(hash)); + } else { + stack.push_bytes(cell->get_hash().as_slice().str()); + } } void interpret_store_ref(vm::Stack& stack) { @@ -934,7 +942,9 @@ void interpret_fetch(vm::Stack& stack, int mode) { auto n = stack.pop_smallint_range(256 + (mode & 1)); auto cs = stack.pop_cellslice(); if (!cs->have(n)) { - stack.push(std::move(cs)); + if (mode & 2) { + stack.push(std::move(cs)); + } stack.push_bool(false); if (!(mode & 4)) { throw IntError{"end of data while reading integer from cell"}; @@ -959,7 +969,9 @@ void interpret_fetch_bytes(vm::Stack& stack, int mode) { unsigned n = stack.pop_smallint_range(127); auto cs = stack.pop_cellslice(); if (!cs->have(n * 8)) { - stack.push(std::move(cs)); + if (mode & 2) { + stack.push(std::move(cs)); + } stack.push_bool(false); if (!(mode & 4)) { throw IntError{"end of data while reading byte string from cell"}; @@ -970,7 +982,7 @@ void interpret_fetch_bytes(vm::Stack& stack, int mode) { if (mode & 2) { cs.write().fetch_bytes(tmp, n); } else { - cs.write().prefetch_bytes(tmp, n); + cs->prefetch_bytes(tmp, n); } std::string s{tmp, tmp + n}; if (mode & 1) { @@ -978,7 +990,9 @@ void interpret_fetch_bytes(vm::Stack& stack, int mode) { } else { stack.push_string(std::move(s)); } - stack.push(std::move(cs)); + if (mode & 2) { + stack.push(std::move(cs)); + } if (mode & 4) { stack.push_bool(true); } @@ -1009,13 +1023,15 @@ void interpret_cell_remaining(vm::Stack& stack) { void interpret_fetch_ref(vm::Stack& stack, int mode) { auto cs = stack.pop_cellslice(); if (!cs->have_refs(1)) { - stack.push(std::move(cs)); + if (mode & 2) { + stack.push(std::move(cs)); + } stack.push_bool(false); if (!(mode & 4)) { throw IntError{"end of data while reading reference from cell"}; } } else { - auto cell = (mode & 2) ? cs.write().fetch_ref() : cs.write().prefetch_ref(); + auto cell = (mode & 2) ? cs.write().fetch_ref() : cs->prefetch_ref(); if (mode & 2) { stack.push(std::move(cs)); } @@ -2474,7 +2490,9 @@ void init_words_common(Dictionary& d) { d.def_stack_word("B>Lu@+ ", std::bind(interpret_bytes_fetch_int, _1, 0x12)); d.def_stack_word("B>Li@+ ", std::bind(interpret_bytes_fetch_int, _1, 0x13)); d.def_stack_word("$>B ", interpret_string_to_bytes); - d.def_stack_word("Bhash ", interpret_bytes_hash); + d.def_stack_word("Bhash ", std::bind(interpret_bytes_hash, _1, true)); + d.def_stack_word("Bhashu ", std::bind(interpret_bytes_hash, _1, true)); + d.def_stack_word("BhashB ", std::bind(interpret_bytes_hash, _1, false)); // cell manipulation (create, write and modify cells) d.def_stack_word("is_empty(); - stack.o << (next_empty ? "WHILEEND:<{" : "WHILE:<{"); + stack.o << "WHILE:<{"; stack.o.indent(); stack.forget_const(); block0->generate_code_all(stack); @@ -638,7 +638,7 @@ bool Op::generate_code_step(Stack& stack) { stack.modified(); stack.o.undent(); Stack stack_copy{stack}; - stack.o << (next_empty ? "}>" : "}>DO<{"); + stack.o << (next_empty ? "}>DO:" : "}>DO<{"); if (!next_empty) { stack.o.indent(); } diff --git a/submodules/ton/tonlib-src/crypto/parser/srcread.cpp b/submodules/ton/tonlib-src/crypto/parser/srcread.cpp index ac031e1e14..3b363242ba 100644 --- a/submodules/ton/tonlib-src/crypto/parser/srcread.cpp +++ b/submodules/ton/tonlib-src/crypto/parser/srcread.cpp @@ -169,6 +169,11 @@ bool SourceReader::load_line() { error("line too long"); return false; } + if (len && cur_line.back() == '\r') { + // CP/M line breaks support + cur_line.pop_back(); + --len; + } loc.text = cur_line; cur_line_len = (int)len; loc.line_pos = 0; diff --git a/submodules/ton/tonlib-src/crypto/smartcont/gen-zerostate-test.fif b/submodules/ton/tonlib-src/crypto/smartcont/gen-zerostate-test.fif index 58161a2318..2e6d87a75e 100644 --- a/submodules/ton/tonlib-src/crypto/smartcont/gen-zerostate-test.fif +++ b/submodules/ton/tonlib-src/crypto/smartcont/gen-zerostate-test.fif @@ -15,10 +15,10 @@ cr ."initial basechain state is:" cr dup B dup Bx. cr dup "basestate0" +suffix +".boc" tuck B>file ."(Initial basechain state saved to file " type .")" cr -Bhash dup =: basestate0_fhash +Bhashu dup =: basestate0_fhash ."file hash=" dup x. space 256 u>B dup B>base64url type cr "basestate0" +suffix +".fhash" B>file -hash dup =: basestate0_rhash +hashu dup =: basestate0_rhash ."root hash=" dup x. space 256 u>B dup B>base64url type cr "basestate0" +suffix +".rhash" B>file @@ -227,10 +227,10 @@ cr cr ."new state is:" cr dup B dup Bx. cr dup "zerostate" +suffix +".boc" tuck B>file ."(Initial masterchain state saved to file " type .")" cr -Bhash dup =: zerostate_fhash +Bhashu dup =: zerostate_fhash ."file hash=" dup x. space 256 u>B dup B>base64url type cr "zerostate" +suffix +".fhash" B>file -hash dup =: zerostate_rhash ."root hash=" dup x. space 256 u>B dup B>base64url type cr +hashu dup =: zerostate_rhash ."root hash=" dup x. space 256 u>B dup B>base64url type cr "zerostate" +suffix +".rhash" B>file basestate0_rhash ."Basestate0 root hash=" dup x. space 256 u>B B>base64url type cr basestate0_fhash ."Basestate0 file hash=" dup x. space 256 u>B B>base64url type cr diff --git a/submodules/ton/tonlib-src/crypto/smartcont/gen-zerostate.fif b/submodules/ton/tonlib-src/crypto/smartcont/gen-zerostate.fif index f5f9aac39e..43ba07b156 100644 --- a/submodules/ton/tonlib-src/crypto/smartcont/gen-zerostate.fif +++ b/submodules/ton/tonlib-src/crypto/smartcont/gen-zerostate.fif @@ -15,10 +15,10 @@ cr ."initial basechain state is:" cr dup B dup Bx. cr dup "basestate0" +suffix +".boc" tuck B>file ."(Initial basechain state saved to file " type .")" cr -Bhash dup =: basestate0_fhash +Bhashu dup =: basestate0_fhash ."file hash=" dup x. space 256 u>B dup B>base64url type cr "basestate0" +suffix +".fhash" B>file -hash dup =: basestate0_rhash +hashu dup =: basestate0_rhash ."root hash=" dup x. space 256 u>B dup B>base64url type cr "basestate0" +suffix +".rhash" B>file @@ -231,10 +231,10 @@ cr cr ."new state is:" cr dup B dup Bx. cr dup "zerostate" +suffix +".boc" tuck B>file ."(Initial masterchain state saved to file " type .")" cr -Bhash dup =: zerostate_fhash +Bhashu dup =: zerostate_fhash ."file hash= " dup X. space 256 u>B dup B>base64url type cr "zerostate" +suffix +".fhash" B>file -hash dup =: zerostate_rhash ."root hash= " dup X. space 256 u>B dup B>base64url type cr +hashu dup =: zerostate_rhash ."root hash= " dup X. space 256 u>B dup B>base64url type cr "zerostate" +suffix +".rhash" B>file basestate0_rhash ."Basestate0 root hash= " dup X. space 256 u>B B>base64url type cr basestate0_fhash ."Basestate0 file hash= " dup X. space 256 u>B B>base64url type cr diff --git a/submodules/ton/tonlib-src/crypto/smartcont/highload-wallet-code.fc b/submodules/ton/tonlib-src/crypto/smartcont/highload-wallet-code.fc new file mode 100644 index 0000000000..70abb48e23 --- /dev/null +++ b/submodules/ton/tonlib-src/crypto/smartcont/highload-wallet-code.fc @@ -0,0 +1,41 @@ +;; Heavy-duty wallet for mass transfers (e.g., for cryptocurrency exchanges) +;; accepts orders for up to 254 internal messages (transfers) in one external message + +() recv_internal(slice in_msg) impure { + ;; do nothing for internal messages +} + +() recv_external(slice in_msg) impure { + var signature = in_msg~load_bits(512); + var cs = in_msg; + var (subwallet_id, valid_until, msg_seqno) = (cs~load_uint(32), cs~load_uint(32), cs~load_uint(32)); + throw_if(35, valid_until <= now()); + var ds = get_data().begin_parse(); + var (stored_seqno, stored_subwallet, public_key) = (ds~load_uint(32), ds~load_uint(32), ds~load_uint(256)); + ds.end_parse(); + throw_unless(33, msg_seqno == stored_seqno); + throw_unless(34, subwallet_id == stored_subwallet); + throw_unless(35, check_signature(slice_hash(in_msg), signature, public_key)); + var dict = cs~load_dict(); + cs.end_parse(); + accept_message(); + int i = -1; + do { + (i, var cs, var f) = dict.idict_get_next?(16, i); + if (f) { + var mode = cs~load_uint(8); + send_raw_message(cs~load_ref(), mode); + } + } until (~ f); + set_data(begin_cell() + .store_uint(stored_seqno + 1, 32) + .store_uint(stored_subwallet, 32) + .store_uint(public_key, 256) + .end_cell()); +} + +;; Get methods + +int seqno() method_id { + return get_data().begin_parse().preload_uint(32); +} diff --git a/submodules/ton/tonlib-src/crypto/smartcont/highload-wallet-code.fif b/submodules/ton/tonlib-src/crypto/smartcont/highload-wallet-code.fif new file mode 100644 index 0000000000..d2122a96fb --- /dev/null +++ b/submodules/ton/tonlib-src/crypto/smartcont/highload-wallet-code.fif @@ -0,0 +1,79 @@ +// automatically generated from `smartcont/stdlib.fc` `smartcont/highload-wallet-code.fc` +PROGRAM{ + DECLPROC recv_internal + DECLPROC recv_external + 85143 DECLMETHOD seqno + recv_internal PROC:<{ + // in_msg + DROP // + }> + recv_external PROC:<{ + // in_msg + 9 PUSHPOW2 // in_msg _3=512 + LDSLICEX // signature in_msg + DUP // signature in_msg cs + 32 LDU // signature in_msg _9 cs + 32 LDU // signature in_msg _9 _12 cs + 32 LDU // signature in_msg subwallet_id valid_until msg_seqno cs + NOW // signature in_msg subwallet_id valid_until msg_seqno cs _19 + s1 s3 XCHG // signature in_msg subwallet_id cs msg_seqno valid_until _19 + LEQ // signature in_msg subwallet_id cs msg_seqno _20 + 35 THROWIF + c4 PUSH // signature in_msg subwallet_id cs msg_seqno _23 + CTOS // signature in_msg subwallet_id cs msg_seqno ds + 32 LDU // signature in_msg subwallet_id cs msg_seqno _28 ds + 32 LDU // signature in_msg subwallet_id cs msg_seqno _28 _31 ds + 256 LDU // signature in_msg subwallet_id cs msg_seqno stored_seqno stored_subwallet public_key ds + ENDS + s3 s2 XCPU // signature in_msg subwallet_id cs public_key stored_seqno stored_subwallet msg_seqno stored_seqno + EQUAL // signature in_msg subwallet_id cs public_key stored_seqno stored_subwallet _39 + 33 THROWIFNOT + s4 s4 XCPU // signature in_msg stored_subwallet cs public_key stored_seqno subwallet_id stored_subwallet + EQUAL // signature in_msg stored_subwallet cs public_key stored_seqno _42 + 34 THROWIFNOT + s0 s4 XCHG // signature stored_seqno stored_subwallet cs public_key in_msg + HASHSU // signature stored_seqno stored_subwallet cs public_key _45 + s0 s5 s5 XC2PU // public_key stored_seqno stored_subwallet cs _45 signature public_key + CHKSIGNU // public_key stored_seqno stored_subwallet cs _46 + 35 THROWIFNOT + LDDICT // public_key stored_seqno stored_subwallet dict cs + ENDS + ACCEPT + -1 PUSHINT // public_key stored_seqno stored_subwallet dict i=-1 + UNTIL:<{ + OVER + 16 PUSHINT // public_key stored_seqno stored_subwallet dict i dict _57=16 + DICTIGETNEXT + NULLSWAPIFNOT + NULLSWAPIFNOT // public_key stored_seqno stored_subwallet dict cs i f + DUP // public_key stored_seqno stored_subwallet dict cs i f f + IF:<{ // public_key stored_seqno stored_subwallet dict cs i f + s0 s2 XCHG // public_key stored_seqno stored_subwallet dict f i cs + 8 LDU // public_key stored_seqno stored_subwallet dict f i mode cs + LDREF // public_key stored_seqno stored_subwallet dict f i mode _100 _99 + DROP // public_key stored_seqno stored_subwallet dict f i mode _63 + SWAP // public_key stored_seqno stored_subwallet dict f i _63 mode + SENDRAWMSG + }>ELSE<{ + s2 POP // public_key stored_seqno stored_subwallet dict f i + }> + SWAP // public_key stored_seqno stored_subwallet dict i f + NOT // public_key stored_seqno stored_subwallet dict i _66 + }> // public_key stored_seqno stored_subwallet dict i + 2DROP // public_key stored_seqno stored_subwallet + SWAP // public_key stored_subwallet stored_seqno + INC // public_key stored_subwallet _68 + NEWC // public_key stored_subwallet _68 _69 + 32 STU // public_key stored_subwallet _71 + 32 STU // public_key _73 + 256 STU // _75 + ENDC // _76 + c4 POP + }> + seqno PROC:<{ + // + c4 PUSH // _0 + CTOS // _1 + 32 PLDU // _3 + }> +}END>c diff --git a/submodules/ton/tonlib-src/crypto/smartcont/highload-wallet-v2-code.fc b/submodules/ton/tonlib-src/crypto/smartcont/highload-wallet-v2-code.fc new file mode 100644 index 0000000000..88d7885563 --- /dev/null +++ b/submodules/ton/tonlib-src/crypto/smartcont/highload-wallet-v2-code.fc @@ -0,0 +1,65 @@ +;; Heavy-duty wallet for mass transfers (e.g., for cryptocurrency exchanges) +;; accepts orders for up to 254 internal messages (transfers) in one external message +;; this version does not use seqno for replay protection; instead, it remembers all recent query_ids +;; in this way several external messages with different query_id can be sent in parallel + +() recv_internal(slice in_msg) impure { + ;; do nothing for internal messages +} + +() recv_external(slice in_msg) impure { + var signature = in_msg~load_bits(512); + var cs = in_msg; + var (subwallet_id, query_id) = (cs~load_uint(32), cs~load_uint(64)); + var bound = (now() << 32); + throw_if(35, query_id < bound); + var ds = get_data().begin_parse(); + var (stored_subwallet, last_cleaned, public_key, old_queries) = (ds~load_uint(32), ds~load_uint(64), ds~load_uint(256), ds~load_dict()); + ds.end_parse(); + (_, var found?) = old_queries.udict_get?(64, query_id); + throw_if(32, found?); + throw_unless(34, subwallet_id == stored_subwallet); + throw_unless(35, check_signature(slice_hash(in_msg), signature, public_key)); + var dict = cs~load_dict(); + cs.end_parse(); + accept_message(); + int i = -1; + do { + (i, var cs, var f) = dict.idict_get_next?(16, i); + if (f) { + var mode = cs~load_uint(8); + send_raw_message(cs~load_ref(), mode); + } + } until (~ f); + bound -= (64 << 32); ;; clean up records expired more than 64 seconds ago + old_queries~udict_set_builder(64, query_id, begin_cell()); + var queries = old_queries; + do { + var (old_queries', i, _, f) = old_queries.udict_delete_get_min(64); + f~touch(); + if (f) { + f = (i < bound); + } + if (f) { + old_queries = old_queries'; + last_cleaned = i; + } + } until (~ f); + set_data(begin_cell() + .store_uint(stored_subwallet, 32) + .store_uint(last_cleaned, 64) + .store_uint(public_key, 256) + .store_dict(old_queries) + .end_cell()); +} + +;; Get methods + +;; returns -1 for processed queries, 0 for unprocessed, 1 for unknown (forgotten) +int processed?(int query_id) method_id { + var ds = get_data().begin_parse(); + var (_, last_cleaned, _, old_queries) = (ds~load_uint(32), ds~load_uint(64), ds~load_uint(256), ds~load_dict()); + ds.end_parse(); + (_, var found) = old_queries.udict_get?(64, query_id); + return found ? true : - (query_id <= last_cleaned); +} diff --git a/submodules/ton/tonlib-src/crypto/smartcont/highload-wallet-v2-code.fif b/submodules/ton/tonlib-src/crypto/smartcont/highload-wallet-v2-code.fif new file mode 100644 index 0000000000..9d5e467de5 --- /dev/null +++ b/submodules/ton/tonlib-src/crypto/smartcont/highload-wallet-v2-code.fif @@ -0,0 +1,134 @@ +// automatically generated from `smartcont/stdlib.fc` `smartcont/highload-wallet-v2-code.fc` +PROGRAM{ + DECLPROC recv_internal + DECLPROC recv_external + 117746 DECLMETHOD processed? + recv_internal PROC:<{ + // in_msg + DROP // + }> + recv_external PROC:<{ + // in_msg + 9 PUSHPOW2 // in_msg _3=512 + LDSLICEX // signature in_msg + DUP // signature in_msg cs + 32 LDU // signature in_msg _8 cs + 64 LDU // signature in_msg subwallet_id query_id cs + NOW // signature in_msg subwallet_id query_id cs _15 + 32 LSHIFT# // signature in_msg subwallet_id query_id cs bound + s2 s0 PUSH2 // signature in_msg subwallet_id query_id cs bound query_id bound + LESS // signature in_msg subwallet_id query_id cs bound _19 + 35 THROWIF + c4 PUSH // signature in_msg subwallet_id query_id cs bound _22 + CTOS // signature in_msg subwallet_id query_id cs bound ds + 32 LDU // signature in_msg subwallet_id query_id cs bound _28 ds + 64 LDU // signature in_msg subwallet_id query_id cs bound _28 _31 ds + 256 LDU // signature in_msg subwallet_id query_id cs bound _28 _31 _34 ds + LDDICT // signature in_msg subwallet_id query_id cs bound stored_subwallet last_cleaned public_key old_queries ds + ENDS + s6 s0 PUSH2 + 64 PUSHINT // signature in_msg subwallet_id query_id cs bound stored_subwallet last_cleaned public_key old_queries query_id old_queries _42=64 + DICTUGET + NULLSWAPIFNOT // signature in_msg subwallet_id query_id cs bound stored_subwallet last_cleaned public_key old_queries _115 _116 + NIP // signature in_msg subwallet_id query_id cs bound stored_subwallet last_cleaned public_key old_queries found? + 32 THROWIF + s7 s3 XCPU // signature in_msg old_queries query_id cs bound stored_subwallet last_cleaned public_key subwallet_id stored_subwallet + EQUAL // signature in_msg old_queries query_id cs bound stored_subwallet last_cleaned public_key _47 + 34 THROWIFNOT + s0 s7 XCHG // signature public_key old_queries query_id cs bound stored_subwallet last_cleaned in_msg + HASHSU // signature public_key old_queries query_id cs bound stored_subwallet last_cleaned _50 + s0 s8 s7 XC2PU // last_cleaned public_key old_queries query_id cs bound stored_subwallet _50 signature public_key + CHKSIGNU // last_cleaned public_key old_queries query_id cs bound stored_subwallet _51 + 35 THROWIFNOT + s0 s2 XCHG // last_cleaned public_key old_queries query_id stored_subwallet bound cs + LDDICT // last_cleaned public_key old_queries query_id stored_subwallet bound dict cs + ENDS + ACCEPT + -1 PUSHINT // last_cleaned public_key old_queries query_id stored_subwallet bound dict i=-1 + UNTIL:<{ + OVER + 16 PUSHINT // last_cleaned public_key old_queries query_id stored_subwallet bound dict i dict _62=16 + DICTIGETNEXT + NULLSWAPIFNOT + NULLSWAPIFNOT // last_cleaned public_key old_queries query_id stored_subwallet bound dict cs i f + DUP // last_cleaned public_key old_queries query_id stored_subwallet bound dict cs i f f + IF:<{ // last_cleaned public_key old_queries query_id stored_subwallet bound dict cs i f + s0 s2 XCHG // last_cleaned public_key old_queries query_id stored_subwallet bound dict f i cs + 8 LDU // last_cleaned public_key old_queries query_id stored_subwallet bound dict f i mode cs + LDREF // last_cleaned public_key old_queries query_id stored_subwallet bound dict f i mode _125 _124 + DROP // last_cleaned public_key old_queries query_id stored_subwallet bound dict f i mode _68 + SWAP // last_cleaned public_key old_queries query_id stored_subwallet bound dict f i _68 mode + SENDRAWMSG + }>ELSE<{ + s2 POP // last_cleaned public_key old_queries query_id stored_subwallet bound dict f i + }> + SWAP // last_cleaned public_key old_queries query_id stored_subwallet bound dict i f + NOT // last_cleaned public_key old_queries query_id stored_subwallet bound dict i _71 + }> // last_cleaned public_key old_queries query_id stored_subwallet bound dict i + 2DROP // last_cleaned public_key old_queries query_id stored_subwallet bound + 38 PUSHPOW2 // last_cleaned public_key old_queries query_id stored_subwallet bound _74 + SUB // last_cleaned public_key old_queries query_id stored_subwallet bound + NEWC // last_cleaned public_key old_queries query_id stored_subwallet bound _77 + s0 s3 s4 XCHG3 + 64 PUSHINT // last_cleaned public_key stored_subwallet bound _77 query_id old_queries _78=64 + DICTUSETB // last_cleaned public_key stored_subwallet bound old_queries + UNTIL:<{ + DUP + 64 PUSHINT // last_cleaned public_key stored_subwallet bound old_queries old_queries _85=64 + DICTUREMMIN + NULLSWAPIFNOT + NULLSWAPIFNOT // last_cleaned public_key stored_subwallet bound old_queries _126 _128 _127 _129 + s2 POP // last_cleaned public_key stored_subwallet bound old_queries old_queries' f i + s1 s0 XCPU // last_cleaned public_key stored_subwallet bound old_queries old_queries' i f f + IF:<{ // last_cleaned public_key stored_subwallet bound old_queries old_queries' i f + DROP // last_cleaned public_key stored_subwallet bound old_queries old_queries' i + s0 s3 PUSH2 // last_cleaned public_key stored_subwallet bound old_queries old_queries' i i bound + LESS // last_cleaned public_key stored_subwallet bound old_queries old_queries' i f + }> // last_cleaned public_key stored_subwallet bound old_queries old_queries' i f + DUP // last_cleaned public_key stored_subwallet bound old_queries old_queries' i f f + IF:<{ // last_cleaned public_key stored_subwallet bound old_queries old_queries' i f + s3 POP + s6 POP // last_cleaned public_key stored_subwallet bound f old_queries + }>ELSE<{ + s3 s1 s3 XCHG3 + 2DROP // last_cleaned public_key stored_subwallet bound f old_queries + }> + SWAP // last_cleaned public_key stored_subwallet bound old_queries f + NOT // last_cleaned public_key stored_subwallet bound old_queries _90 + }> // last_cleaned public_key stored_subwallet bound old_queries + NIP // last_cleaned public_key stored_subwallet old_queries + NEWC // last_cleaned public_key stored_subwallet old_queries _91 + s1 s2 XCHG // last_cleaned public_key old_queries stored_subwallet _91 + 32 STU // last_cleaned public_key old_queries _93 + s1 s3 XCHG // old_queries public_key last_cleaned _93 + 64 STU // old_queries public_key _95 + 256 STU // old_queries _97 + STDICT // _98 + ENDC // _99 + c4 POP + }> + processed? PROC:<{ + // query_id + c4 PUSH // query_id _2 + CTOS // query_id ds + 32 LDU // query_id _29 _28 + NIP // query_id ds + 64 LDU // query_id _11 ds + 256 LDU // query_id _11 _33 _32 + NIP // query_id _11 ds + LDDICT // query_id last_cleaned old_queries ds + ENDS + s2 s(-1) PUXC + 64 PUSHINT // query_id last_cleaned query_id old_queries _22=64 + DICTUGET + NULLSWAPIFNOT // query_id last_cleaned _36 _37 + NIP // query_id last_cleaned found + IF:<{ // query_id last_cleaned + 2DROP // + TRUE // _24 + }>ELSE<{ // query_id last_cleaned + LEQ // _26 + NEGATE // _24 + }> + }> +}END>c diff --git a/submodules/ton/tonlib-src/crypto/smartcont/highload-wallet-v2.fif b/submodules/ton/tonlib-src/crypto/smartcont/highload-wallet-v2.fif new file mode 100644 index 0000000000..76f06ed590 --- /dev/null +++ b/submodules/ton/tonlib-src/crypto/smartcont/highload-wallet-v2.fif @@ -0,0 +1,69 @@ +#!/usr/bin/env fift -s +"TonUtil.fif" include + +{ ."usage: " @' $0 type ." []" cr + ."Creates a request with up to 254 orders loaded from to high-load v2 (sub)wallet created by new-highload-v2-wallet.fif, with private key loaded from file .pk " + ."and address from .addr, and saves it into .boc ('wallet-query.boc' by default)" cr + ." is a text file with lines `SEND `" cr 1 halt +} : usage +$# dup 3 < swap 4 > or ' usage if + +$1 =: file-base +$2 parse-int dup 32 fits ' usage ifnot =: subwallet-id // parse subwallet-id +{ subwallet-id (.) $+ } : +subwallet +$3 =: order-file +def? $4 { @' $4 } { "wallet-query" } cond constant savefile +3 constant send-mode // mode for SENDRAWMSG: +1 - sender pays fees, +2 - ignore errors +60 constant timeout // external message expires in 60 seconds + +file-base +subwallet +".addr" load-address +2dup 2constant wallet_addr +."Source wallet address = " 2dup .addr cr 6 .Addr cr +file-base +".pk" load-keypair nip constant wallet_pk + +variable orders dictnew orders ! +variable order# order# 0! +// c -- +{ = abort"more than 254 orders" + orders @ 16 udict!+ not abort"cannot add order to dictionary" + orders ! order# 1+! +} : add-order +// b body -- b' +{ tuck +} : create-int-msg +// ng wc addr bnc -- +{ ."Transferring " 3 roll .GR ."to account " + -rot 2dup 4 pick 7 + .Addr ." = " .addr ." bounce=" . cr +} : .transfer +// addr$ ng -- c +{ swap parse-smc-addr // ng wc addr bnc + 2over 2over .transfer + create-int-msg +} : create-simple-transfer +// c m -- c' +{ } : create-order + +// addr$ ng -- +{ create-simple-transfer send-mode create-order add-order } : send +{ bl word bl word $>GR send } : SEND + +// parse order file +order-file include + +// create external message +now timeout + 32 << hashu 32 1<<1- and + =: query_id + +dup ."signing message: " +dup ."resulting external message: " B dup Bx. cr +."Query_id is " query_id dup . ."= 0x" X. cr +savefile +".boc" tuck B>file +."(Saved to file " type .")" cr diff --git a/submodules/ton/tonlib-src/crypto/smartcont/highload-wallet.fif b/submodules/ton/tonlib-src/crypto/smartcont/highload-wallet.fif new file mode 100644 index 0000000000..ab69fdf368 --- /dev/null +++ b/submodules/ton/tonlib-src/crypto/smartcont/highload-wallet.fif @@ -0,0 +1,68 @@ +#!/usr/bin/env fift -s +"TonUtil.fif" include + +{ ."usage: " @' $0 type ." []" cr + ."Creates a request with up to 254 orders loaded from to high-load (sub)wallet created by new-highload-wallet.fif, with private key loaded from file .pk " + ."and address from .addr, and saves it into .boc ('wallet-query.boc' by default)" cr + ." is a text file with lines `SEND `" cr 1 halt +} : usage +$# dup 4 < swap 5 > or ' usage if + +$1 =: file-base +$2 parse-int dup 32 fits ' usage ifnot =: subwallet-id // parse subwallet-id +{ subwallet-id (.) $+ } : +subwallet +$3 parse-int =: seqno +$4 =: order-file +def? $5 { @' $5 } { "wallet-query" } cond constant savefile +3 constant send-mode // mode for SENDRAWMSG: +1 - sender pays fees, +2 - ignore errors +60 constant timeout // external message expires in 60 seconds + +file-base +subwallet +".addr" load-address +2dup 2constant wallet_addr +."Source wallet address = " 2dup .addr cr 6 .Addr cr +file-base +".pk" load-keypair nip constant wallet_pk + +variable orders dictnew orders ! +variable order# order# 0! +// c -- +{ = abort"more than 254 orders" + orders @ 16 udict!+ not abort"cannot add order to dictionary" + orders ! order# 1+! +} : add-order +// b body -- b' +{ tuck +} : create-int-msg +// ng wc addr bnc -- +{ ."Transferring " 3 roll .GR ."to account " + -rot 2dup 4 pick 7 + .Addr ." = " .addr ." bounce=" . cr +} : .transfer +// addr$ ng -- c +{ swap parse-smc-addr // ng wc addr bnc + 2over 2over .transfer + create-int-msg +} : create-simple-transfer +// c m -- c' +{ } : create-order + +// addr$ ng -- +{ create-simple-transfer send-mode create-order add-order } : send +{ bl word bl word $>GR send } : SEND + +// parse order file +order-file include + +// create external message + +dup ."signing message: " +dup ."resulting external message: " B dup Bx. cr +savefile +".boc" tuck B>file +."(Saved to file " type .")" cr diff --git a/submodules/ton/tonlib-src/crypto/smartcont/new-highload-wallet-v2.fif b/submodules/ton/tonlib-src/crypto/smartcont/new-highload-wallet-v2.fif new file mode 100644 index 0000000000..df386cc72a --- /dev/null +++ b/submodules/ton/tonlib-src/crypto/smartcont/new-highload-wallet-v2.fif @@ -0,0 +1,47 @@ +#!/usr/bin/env fift -s +"TonUtil.fif" include +"Asm.fif" include + +{ ."usage: " @' $0 type ." []" cr + ."Creates a new v2 high-load wallet in the specified workchain, with the controlling private key saved to or loaded from .pk " + ."('new-wallet.pk' by default)" cr + ." is the 32-bit identifier of this subwallet among all controlled by the same private key" cr 1 halt +} : usage +$# 2- -2 and ' usage if + +$1 parse-workchain-id =: wc // set workchain id from command line argument +$2 parse-int dup =: subwallet-id // parse subwallet-id +32 fits ' usage ifnot +{ subwallet-id (.) $+ } : +subwallet +def? $3 { @' $3 } { "new-wallet" } cond constant file-base +65536 constant timeout // init query times out in 65536 seconds + +."Creating new v2 high-load wallet in workchain " wc . +."with subwallet id " subwallet-id . cr + +// Create new high-load wallet; source code included from `highload-wallet-v2-code.fif` +"highload-wallet-v2-code.fif" include +// code + // data +null // no libraries + // create StateInit +dup ."StateInit: " +dup ."signing message: " +dup ."External message for initialization is " B dup Bx. cr +file-base +subwallet +"-query.boc" tuck B>file +."(Saved wallet creating query to file " type .")" cr diff --git a/submodules/ton/tonlib-src/crypto/smartcont/new-highload-wallet.fif b/submodules/ton/tonlib-src/crypto/smartcont/new-highload-wallet.fif new file mode 100644 index 0000000000..57be6a2311 --- /dev/null +++ b/submodules/ton/tonlib-src/crypto/smartcont/new-highload-wallet.fif @@ -0,0 +1,44 @@ +#!/usr/bin/env fift -s +"TonUtil.fif" include +"Asm.fif" include + +{ ."usage: " @' $0 type ." []" cr + ."Creates a new high-load wallet in the specified workchain, with the controlling private key saved to or loaded from .pk " + ."('new-wallet.pk' by default)" cr + ." is the 32-bit identifier of this subwallet among all controlled by the same private key" cr 1 halt +} : usage +$# 2- -2 and ' usage if + +$1 parse-workchain-id =: wc // set workchain id from command line argument +$2 parse-int dup =: subwallet-id // parse subwallet-id +32 fits ' usage ifnot +{ subwallet-id (.) $+ } : +subwallet +def? $3 { @' $3 } { "new-wallet" } cond constant file-base + +."Creating new high-load wallet in workchain " wc . +."with subwallet id " subwallet-id . cr + +// Create new high-load wallet; source code included from `highload-wallet-code.fif` +"highload-wallet-code.fif" include +// code + // data +null // no libraries + // create StateInit +dup ."StateInit: " +dup ."signing message: " +dup ."External message for initialization is " B dup Bx. cr +file-base +subwallet +"-query.boc" tuck B>file +."(Saved wallet creating query to file " type .")" cr diff --git a/submodules/ton/tonlib-src/crypto/smartcont/new-pinger.fif b/submodules/ton/tonlib-src/crypto/smartcont/new-pinger.fif index b833268889..646bfdf68c 100644 --- a/submodules/ton/tonlib-src/crypto/smartcont/new-pinger.fif +++ b/submodules/ton/tonlib-src/crypto/smartcont/new-pinger.fif @@ -41,7 +41,7 @@ def? $3 { @' $3 } { "new-pinger" } cond constant file-base // no libraries // create StateInit dup ."StateInit: " // create StateInit dup ."StateInit: " // data null // no libraries // create StateInit dup ."StateInit: " dup ."signing message: " dup ."External message for initialization is " B dup Bx. cr diff --git a/submodules/ton/tonlib-src/crypto/smartcont/new-wallet.fif b/submodules/ton/tonlib-src/crypto/smartcont/new-wallet.fif index c1ad403ca5..9bdb0bdb38 100644 --- a/submodules/ton/tonlib-src/crypto/smartcont/new-wallet.fif +++ b/submodules/ton/tonlib-src/crypto/smartcont/new-wallet.fif @@ -47,14 +47,14 @@ null // no libraries // Libs{ x{ABACABADABACABA} drop x{AAAA} s>c public_lib x{1234} x{5678} |_ s>c public_lib }Libs // create StateInit dup ."StateInit: " dup ."signing message: " dup ."External message for initialization is " B dup Bx. cr diff --git a/submodules/ton/tonlib-src/crypto/smartcont/stdlib.fc b/submodules/ton/tonlib-src/crypto/smartcont/stdlib.fc index 4fb30bdd10..fb9b49f56a 100644 --- a/submodules/ton/tonlib-src/crypto/smartcont/stdlib.fc +++ b/submodules/ton/tonlib-src/crypto/smartcont/stdlib.fc @@ -86,6 +86,8 @@ cell dict_set_builder(cell dict, int key_len, slice index, builder value) asm(va (cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT" "NULLSWAPIFNOT"; (int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT" "NULLSWAPIFNOT"; (int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT" "NULLSWAPIFNOT"; +(int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT" "NULLSWAPIFNOT"; +(int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT" "NULLSWAPIFNOT"; cell new_dict() asm "NEWDICT"; int dict_empty?(cell c) asm "DICTEMPTY"; diff --git a/submodules/ton/tonlib-src/crypto/smartcont/update-config-smc.fif b/submodules/ton/tonlib-src/crypto/smartcont/update-config-smc.fif index 3840e128f8..22f01f0456 100644 --- a/submodules/ton/tonlib-src/crypto/smartcont/update-config-smc.fif +++ b/submodules/ton/tonlib-src/crypto/smartcont/update-config-smc.fif @@ -6,7 +6,7 @@ ."with private key loaded from file .pk, " ."and saves it into .boc ('config-query.boc' by default)" cr 1 halt } : usage -def? $# { @' $# dup 2 < swap 3 > or ' usage if } if +$# dup 2 < swap 3 > or ' usage if "config-master" constant file-base 0 constant seqno @@ -15,18 +15,16 @@ true constant bounce "config-code.fif" constant config-source 100 constant interval // valid for 100 seconds -def? $2 { - @' $1 =: file-base - @' $2 parse-int =: seqno -} if -def? $5 { @' $5 } { "config-query" } cond constant savefile +$1 =: file-base +$2 parse-int =: seqno +def? $3 { @' $3 } { "config-query" } cond constant savefile file-base +".addr" load-address 2dup 2constant config_addr ."Configuration smart contract address = " 2dup .addr cr 6 .Addr cr file-base +".pk" load-keypair nip constant config_pk -."Loading new configuration smart contract code from file file " config-source type cr +."Loading new configuration smart contract code from file " config-source type cr "Asm.fif" include config-source include dup dup ."signing message: " dup ."resulting external message: " .pk, " ."and saves it into .boc ('config-query.boc' by default)" cr 1 halt } : usage -def? $# { @' $# dup 4 < swap 5 > or ' usage if } if +$# dup 4 < swap 5 > or ' usage if "config-master" constant file-base 0 constant seqno @@ -15,12 +15,10 @@ true constant bounce "new-value.boc" constant boc-filename 100 constant interval // valid for 100 seconds -def? $4 { - @' $1 =: file-base - @' $2 parse-int =: seqno - @' $3 parse-int =: idx - @' $4 =: boc-filename -} if +$1 =: file-base +$2 parse-int =: seqno +$3 parse-int =: idx +$4 =: boc-filename def? $5 { @' $5 } { "config-query" } cond constant savefile file-base +".addr" load-address @@ -39,7 +37,7 @@ dup idx is-valid-config? not abort"not a valid value for chosen configuration pa // create a message dup ."signing message: " dup ."resulting external message: " .pk, " ."and saves it into .boc ('config-query.boc' by default)" cr 1 halt } : usage -def? $# { @' $# dup 2 < swap 3 > or ' usage if } if +$# dup 2 < swap 3 > or ' usage if "config-master" constant file-base 0 constant seqno @@ -15,18 +15,16 @@ true constant bounce "elector-code.fif" constant elector-source 100 constant interval // valid for 100 seconds -def? $2 { - @' $1 =: file-base - @' $2 parse-int =: seqno -} if -def? $5 { @' $5 } { "config-query" } cond constant savefile +$1 =: file-base +$2 parse-int =: seqno +def? $3 { @' $3 } { "config-query" } cond constant savefile file-base +".addr" load-address 2dup 2constant config_addr ."Configuration smart contract address = " 2dup .addr cr 6 .Addr cr file-base +".pk" load-keypair nip constant config_pk -."Loading new elector smart contract code from file file " elector-source type cr +."Loading new elector smart contract code from file " elector-source type cr "Asm.fif" include elector-source include dup dup ."signing message: " dup ."resulting external message: " dup ."resulting external message: " dup ."resulting external message: " CellSlice::fetch_ref() { } } +bool CellSlice::prefetch_maybe_ref(Ref& res) const { + auto z = prefetch_ulong(1); + if (!z) { + res.clear(); + return true; + } else { + return z == 1 && prefetch_ref_to(res); + } +} + +bool CellSlice::fetch_maybe_ref(Ref& res) { + auto z = prefetch_ulong(1); + if (!z) { + res.clear(); + return advance(1); + } else { + return z == 1 && prefetch_ref_to(res) && advance_ext(1, 1); + } +} + bool CellSlice::begins_with(unsigned bits, unsigned long long value) const { return have(bits) && !((prefetch_ulong(bits) ^ value) & ((1ULL << bits) - 1)); } diff --git a/submodules/ton/tonlib-src/crypto/vm/cells/CellSlice.h b/submodules/ton/tonlib-src/crypto/vm/cells/CellSlice.h index 5d7f906bc4..433344f982 100644 --- a/submodules/ton/tonlib-src/crypto/vm/cells/CellSlice.h +++ b/submodules/ton/tonlib-src/crypto/vm/cells/CellSlice.h @@ -185,6 +185,8 @@ class CellSlice : public td::CntObject { bool prefetch_ref_to(Ref& ref, unsigned offset = 0) const { return (ref = prefetch_ref(offset)).not_null(); } + bool fetch_maybe_ref(Ref& ref); + bool prefetch_maybe_ref(Ref& ref) const; td::BitSlice fetch_bits(unsigned bits); td::BitSlice prefetch_bits(unsigned bits) const; td::Ref fetch_subslice(unsigned bits, unsigned refs = 0); diff --git a/submodules/ton/tonlib-src/crypto/vm/cells/MerkleProof.cpp b/submodules/ton/tonlib-src/crypto/vm/cells/MerkleProof.cpp index 084a973ed8..a373e80468 100644 --- a/submodules/ton/tonlib-src/crypto/vm/cells/MerkleProof.cpp +++ b/submodules/ton/tonlib-src/crypto/vm/cells/MerkleProof.cpp @@ -267,16 +267,18 @@ MerkleProofBuilder::MerkleProofBuilder(Ref root) usage_root = UsageCell::create(orig_root, usage_tree->root_ptr()); } -void MerkleProofBuilder::reset(Ref root) { +Ref MerkleProofBuilder::init(Ref root) { usage_tree = std::make_shared(); orig_root = std::move(root); usage_root = UsageCell::create(orig_root, usage_tree->root_ptr()); + return usage_root; } -void MerkleProofBuilder::clear() { +bool MerkleProofBuilder::clear() { usage_tree.reset(); orig_root.clear(); usage_root.clear(); + return true; } Ref MerkleProofBuilder::extract_proof() const { diff --git a/submodules/ton/tonlib-src/crypto/vm/cells/MerkleProof.h b/submodules/ton/tonlib-src/crypto/vm/cells/MerkleProof.h index 8dfb43a65c..5b3b8ebcef 100644 --- a/submodules/ton/tonlib-src/crypto/vm/cells/MerkleProof.h +++ b/submodules/ton/tonlib-src/crypto/vm/cells/MerkleProof.h @@ -51,9 +51,10 @@ class MerkleProofBuilder { Ref orig_root, usage_root; public: + MerkleProofBuilder() = default; MerkleProofBuilder(Ref root); - void reset(Ref root); - void clear(); + Ref init(Ref root); + bool clear(); Ref root() const { return usage_root; } diff --git a/submodules/ton/tonlib-src/lite-client/lite-client.cpp b/submodules/ton/tonlib-src/lite-client/lite-client.cpp index 0d446e6ec7..3817e987f8 100644 --- a/submodules/ton/tonlib-src/lite-client/lite-client.cpp +++ b/submodules/ton/tonlib-src/lite-client/lite-client.cpp @@ -914,8 +914,10 @@ bool TestNode::do_parse_line() { return parse_block_id_ext(blkid) && parse_account_addr(workchain, addr) && parse_lt(lt) && seekeoln() && get_one_transaction(blkid, workchain, addr, lt, true); } else if (word == "lasttrans" || word == "lasttransdump") { - return parse_account_addr(workchain, addr) && parse_lt(lt) && parse_hash(hash) && seekeoln() && - get_last_transactions(workchain, addr, lt, hash, 10, word == "lasttransdump"); + count = 10; + return parse_account_addr(workchain, addr) && parse_lt(lt) && parse_hash(hash) && + (seekeoln() || parse_uint32(count)) && seekeoln() && + get_last_transactions(workchain, addr, lt, hash, count, word == "lasttransdump"); } else if (word == "listblocktrans" || word == "listblocktransrev") { lt = 0; int mode = (word == "listblocktrans" ? 7 : 0x47); diff --git a/submodules/ton/tonlib-src/tdactor/td/actor/common.h b/submodules/ton/tonlib-src/tdactor/td/actor/common.h index 039f25b2c9..3a29b4736a 100644 --- a/submodules/ton/tonlib-src/tdactor/td/actor/common.h +++ b/submodules/ton/tonlib-src/tdactor/td/actor/common.h @@ -364,7 +364,7 @@ inline void register_actor_info_ptr(core::ActorInfoPtr actor_info_ptr) { } template -core::ActorInfoPtr create_actor(core::ActorOptions &options, ArgsT &&... args) { +core::ActorInfoPtr create_actor(core::ActorOptions &options, ArgsT &&... args) noexcept { auto *scheduler_context = core::SchedulerContext::get(); if (!options.has_scheduler()) { options.on_scheduler(scheduler_context->get_scheduler_id()); diff --git a/submodules/ton/tonlib-src/tdactor/td/actor/core/ActorExecutor.cpp b/submodules/ton/tonlib-src/tdactor/td/actor/core/ActorExecutor.cpp index fcca341fd7..7554a05d10 100644 --- a/submodules/ton/tonlib-src/tdactor/td/actor/core/ActorExecutor.cpp +++ b/submodules/ton/tonlib-src/tdactor/td/actor/core/ActorExecutor.cpp @@ -75,7 +75,7 @@ void ActorExecutor::send(ActorSignals signals) { pending_signals_.add_signals(signals); } -void ActorExecutor::start() { +void ActorExecutor::start() noexcept { //LOG(ERROR) << "START " << actor_info_.get_name() << " " << tag("from_queue", options.from_queue); if (is_closed()) { return; @@ -126,7 +126,7 @@ void ActorExecutor::start() { } } -void ActorExecutor::finish() { +void ActorExecutor::finish() noexcept { //LOG(ERROR) << "FINISH " << actor_info_.get_name() << " " << tag("own_lock", actor_locker_.own_lock()); if (!actor_locker_.own_lock()) { if (!pending_signals_.empty() && actor_locker_.add_signals(pending_signals_)) { diff --git a/submodules/ton/tonlib-src/tdactor/td/actor/core/ActorExecutor.h b/submodules/ton/tonlib-src/tdactor/td/actor/core/ActorExecutor.h index d11c77b2c2..53fc1e11ac 100644 --- a/submodules/ton/tonlib-src/tdactor/td/actor/core/ActorExecutor.h +++ b/submodules/ton/tonlib-src/tdactor/td/actor/core/ActorExecutor.h @@ -106,8 +106,8 @@ class ActorExecutor { return flags_; } - void start(); - void finish(); + void start() noexcept; + void finish() noexcept; bool flush_one(ActorSignals &signals); bool flush_one_signal(ActorSignals &signals); diff --git a/submodules/ton/tonlib-src/tdutils/td/utils/Status.h b/submodules/ton/tonlib-src/tdutils/td/utils/Status.h index f96ca82776..1759c0abef 100644 --- a/submodules/ton/tonlib-src/tdutils/td/utils/Status.h +++ b/submodules/ton/tonlib-src/tdutils/td/utils/Status.h @@ -50,6 +50,9 @@ #define TRY_RESULT(name, result) TRY_RESULT_IMPL(TD_CONCAT(TD_CONCAT(r_, name), __LINE__), auto name, result) +#define TRY_RESULT_PROMISE(promise_name, name, result) \ + TRY_RESULT_PROMISE_IMPL(promise_name, TD_CONCAT(TD_CONCAT(r_, name), __LINE__), auto name, result) + #define TRY_RESULT_ASSIGN(name, result) TRY_RESULT_IMPL(TD_CONCAT(TD_CONCAT(r_, name), __LINE__), name, result) #define TRY_RESULT_PREFIX(name, result, prefix) \ @@ -78,10 +81,18 @@ } \ name = r_name.move_as_ok(); +#define TRY_RESULT_PROMISE_IMPL(promise_name, r_name, name, result) \ + auto r_name = (result); \ + if (r_name.is_error()) { \ + promise_name.set_error(r_name.move_as_error()); \ + return; \ + } \ + name = r_name.move_as_ok(); + #define TRY_RESULT_PROMISE_PREFIX_IMPL(promise_name, r_name, name, result, prefix) \ auto r_name = (result); \ if (r_name.is_error()) { \ - promise.set_error(r_name.move_as_error()); \ + promise_name.set_error(r_name.move_as_error_prefix(prefix)); \ return; \ } \ name = r_name.move_as_ok(); @@ -298,14 +309,31 @@ class Status { return std::move(*this); } - Status move_as_error_prefix(Slice prefix) TD_WARN_UNUSED_RESULT { + Status move_as_error_prefix(const Status &status) const TD_WARN_UNUSED_RESULT { + return status.move_as_error_suffix(message()); + } + + Status move_as_error_prefix(Slice prefix) const TD_WARN_UNUSED_RESULT { CHECK(is_error()); Info info = get_info(); switch (info.error_type) { case ErrorType::general: - return Error(code(), PSLICE() << prefix << message()); + return Error(code(), PSLICE() << prefix << " " << message()); case ErrorType::os: - return Status(false, ErrorType::os, code(), PSLICE() << prefix << message()); + return Status(false, ErrorType::os, code(), PSLICE() << prefix << " " << message()); + default: + UNREACHABLE(); + return {}; + } + } + Status move_as_error_suffix(Slice suffix) const TD_WARN_UNUSED_RESULT { + CHECK(is_error()); + Info info = get_info(); + switch (info.error_type) { + case ErrorType::general: + return Error(code(), PSLICE() << message() << " " << suffix); + case ErrorType::os: + return Status(false, ErrorType::os, code(), PSLICE() << message() << " " << suffix); default: UNREACHABLE(); return {}; @@ -488,6 +516,18 @@ class Result { }; return status_.move_as_error_prefix(prefix); } + Status move_as_error_prefix(const Status &prefix) TD_WARN_UNUSED_RESULT { + SCOPE_EXIT { + status_ = Status::Error<-5>(); + }; + return status_.move_as_error_prefix(prefix); + } + Status move_as_error_suffix(Slice suffix) TD_WARN_UNUSED_RESULT { + SCOPE_EXIT { + status_ = Status::Error<-5>(); + }; + return status_.move_as_error_suffix(suffix); + } const T &ok() const { LOG_CHECK(status_.is_ok()) << status_; return value_; diff --git a/submodules/ton/tonlib-src/tdutils/td/utils/tl_helpers.h b/submodules/ton/tonlib-src/tdutils/td/utils/tl_helpers.h index 30cf09556a..df89ed1a71 100644 --- a/submodules/ton/tonlib-src/tdutils/td/utils/tl_helpers.h +++ b/submodules/ton/tonlib-src/tdutils/td/utils/tl_helpers.h @@ -32,10 +32,10 @@ #include #include -#define BEGIN_STORE_FLAGS() \ - do { \ - uint32 flags_store = 0; \ - uint32 bit_offset_store = 0 +#define BEGIN_STORE_FLAGS() \ + do { \ + td::uint32 flags_store = 0; \ + td::uint32 bit_offset_store = 0 #define STORE_FLAG(flag) \ flags_store |= (flag) << bit_offset_store; \ @@ -47,10 +47,10 @@ } \ while (false) -#define BEGIN_PARSE_FLAGS() \ - do { \ - uint32 flags_parse; \ - uint32 bit_offset_parse = 0; \ +#define BEGIN_PARSE_FLAGS() \ + do { \ + td::uint32 flags_parse; \ + td::uint32 bit_offset_parse = 0; \ td::parse(flags_parse, parser) #define PARSE_FLAG(flag) \ diff --git a/submodules/ton/tonlib-src/tdutils/td/utils/tl_parsers.h b/submodules/ton/tonlib-src/tdutils/td/utils/tl_parsers.h index 734afdb713..e0fc419447 100644 --- a/submodules/ton/tonlib-src/tdutils/td/utils/tl_parsers.h +++ b/submodules/ton/tonlib-src/tdutils/td/utils/tl_parsers.h @@ -99,6 +99,16 @@ class TlParser { } } + bool can_prefetch_int() const { + return get_left_len() >= sizeof(int32); + } + + int32 prefetch_int_unsafe() const { + int32 result; + std::memcpy(&result, data, sizeof(int32)); + return result; + } + int32 fetch_int_unsafe() { int32 result; std::memcpy(&result, data, sizeof(int32)); diff --git a/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api.cpp b/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api.cpp index c6c6f32804..810c29527e 100644 --- a/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api.cpp +++ b/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api.cpp @@ -244,6 +244,8 @@ object_ptr Object::fetch(td::TlParser &p) { return db_state_destroyedSessions::fetch(p); case db_state_gcBlockId::ID: return db_state_gcBlockId::fetch(p); + case db_state_hardforks::ID: + return db_state_hardforks::fetch(p); case db_state_initBlockId::ID: return db_state_initBlockId::fetch(p); case db_state_key_destroyedSessions::ID: @@ -256,6 +258,8 @@ object_ptr Object::fetch(td::TlParser &p) { return db_state_key_shardClient::fetch(p); case db_state_key_asyncSerializer::ID: return db_state_key_asyncSerializer::fetch(p); + case db_state_key_hardforks::ID: + return db_state_key_hardforks::fetch(p); case db_state_shardClient::ID: return db_state_shardClient::fetch(p); case dht_key::ID: @@ -498,6 +502,8 @@ object_ptr Object::fetch(td::TlParser &p) { return tonNode_zeroStateIdExt::fetch(p); case validator_group::ID: return validator_group::fetch(p); + case validator_groupEx::ID: + return validator_groupEx::fetch(p); case validator_config_global::ID: return validator_config_global::fetch(p); case validator_config_local::ID: @@ -5905,6 +5911,44 @@ void db_state_gcBlockId::store(td::TlStorerToString &s, const char *field_name) } } +db_state_hardforks::db_state_hardforks() + : blocks_() +{} + +db_state_hardforks::db_state_hardforks(std::vector> &&blocks_) + : blocks_(std::move(blocks_)) +{} + +const std::int32_t db_state_hardforks::ID; + +object_ptr db_state_hardforks::fetch(td::TlParser &p) { + return make_object(p); +} + +db_state_hardforks::db_state_hardforks(td::TlParser &p) +#define FAIL(error) p.set_error(error) + : blocks_(TlFetchVector>::parse(p)) +#undef FAIL +{} + +void db_state_hardforks::store(td::TlStorerCalcLength &s) const { + (void)sizeof(s); + TlStoreVector::store(blocks_, s); +} + +void db_state_hardforks::store(td::TlStorerUnsafe &s) const { + (void)sizeof(s); + TlStoreVector::store(blocks_, s); +} + +void db_state_hardforks::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "db_state_hardforks"); + { const std::vector> &v = blocks_; const std::uint32_t multiplicity = static_cast(v.size()); const auto vector_name = "vector[" + td::to_string(multiplicity)+ "]"; s.store_class_begin("blocks", vector_name.c_str()); for (std::uint32_t i = 0; i < multiplicity; i++) { if (v[i] == nullptr) { s.store_field("", "null"); } else { v[i]->store(s, ""); } } s.store_class_end(); } + s.store_class_end(); + } +} + db_state_initBlockId::db_state_initBlockId() : block_() {} @@ -5957,6 +6001,8 @@ object_ptr db_state_Key::fetch(td::TlParser &p) { return db_state_key_shardClient::fetch(p); case db_state_key_asyncSerializer::ID: return db_state_key_asyncSerializer::fetch(p); + case db_state_key_hardforks::ID: + return db_state_key_hardforks::fetch(p); default: FAIL(PSTRING() << "Unknown constructor found " << td::format::as_hex(constructor)); } @@ -6118,6 +6164,37 @@ void db_state_key_asyncSerializer::store(td::TlStorerToString &s, const char *fi } } +db_state_key_hardforks::db_state_key_hardforks() { +} + +const std::int32_t db_state_key_hardforks::ID; + +object_ptr db_state_key_hardforks::fetch(td::TlParser &p) { + return make_object(p); +} + +db_state_key_hardforks::db_state_key_hardforks(td::TlParser &p) +#define FAIL(error) p.set_error(error) +#undef FAIL +{ + (void)p; +} + +void db_state_key_hardforks::store(td::TlStorerCalcLength &s) const { + (void)sizeof(s); +} + +void db_state_key_hardforks::store(td::TlStorerUnsafe &s) const { + (void)sizeof(s); +} + +void db_state_key_hardforks::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "db_state_key_hardforks"); + s.store_class_end(); + } +} + db_state_shardClient::db_state_shardClient() : block_() {} @@ -11755,6 +11832,20 @@ void tonNode_zeroStateIdExt::store(td::TlStorerToString &s, const char *field_na } } +object_ptr validator_Group::fetch(td::TlParser &p) { +#define FAIL(error) p.set_error(error); return nullptr; + int constructor = p.fetch_int(); + switch (constructor) { + case validator_group::ID: + return validator_group::fetch(p); + case validator_groupEx::ID: + return validator_groupEx::fetch(p); + default: + FAIL(PSTRING() << "Unknown constructor found " << td::format::as_hex(constructor)); + } +#undef FAIL +} + validator_group::validator_group() : workchain_() , shard_() @@ -11773,7 +11864,7 @@ validator_group::validator_group(std::int32_t workchain_, std::int64_t shard_, s const std::int32_t validator_group::ID; -object_ptr validator_group::fetch(td::TlParser &p) { +object_ptr validator_group::fetch(td::TlParser &p) { return make_object(p); } @@ -11817,6 +11908,74 @@ void validator_group::store(td::TlStorerToString &s, const char *field_name) con } } +validator_groupEx::validator_groupEx() + : workchain_() + , shard_() + , vertical_seqno_() + , catchain_seqno_() + , config_hash_() + , members_() +{} + +validator_groupEx::validator_groupEx(std::int32_t workchain_, std::int64_t shard_, std::int32_t vertical_seqno_, std::int32_t catchain_seqno_, td::Bits256 const &config_hash_, std::vector> &&members_) + : workchain_(workchain_) + , shard_(shard_) + , vertical_seqno_(vertical_seqno_) + , catchain_seqno_(catchain_seqno_) + , config_hash_(config_hash_) + , members_(std::move(members_)) +{} + +const std::int32_t validator_groupEx::ID; + +object_ptr validator_groupEx::fetch(td::TlParser &p) { + return make_object(p); +} + +validator_groupEx::validator_groupEx(td::TlParser &p) +#define FAIL(error) p.set_error(error) + : workchain_(TlFetchInt::parse(p)) + , shard_(TlFetchLong::parse(p)) + , vertical_seqno_(TlFetchInt::parse(p)) + , catchain_seqno_(TlFetchInt::parse(p)) + , config_hash_(TlFetchInt256::parse(p)) + , members_(TlFetchVector>::parse(p)) +#undef FAIL +{} + +void validator_groupEx::store(td::TlStorerCalcLength &s) const { + (void)sizeof(s); + TlStoreBinary::store(workchain_, s); + TlStoreBinary::store(shard_, s); + TlStoreBinary::store(vertical_seqno_, s); + TlStoreBinary::store(catchain_seqno_, s); + TlStoreBinary::store(config_hash_, s); + TlStoreVector::store(members_, s); +} + +void validator_groupEx::store(td::TlStorerUnsafe &s) const { + (void)sizeof(s); + TlStoreBinary::store(workchain_, s); + TlStoreBinary::store(shard_, s); + TlStoreBinary::store(vertical_seqno_, s); + TlStoreBinary::store(catchain_seqno_, s); + TlStoreBinary::store(config_hash_, s); + TlStoreVector::store(members_, s); +} + +void validator_groupEx::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "validator_groupEx"); + s.store_field("workchain", workchain_); + s.store_field("shard", shard_); + s.store_field("vertical_seqno", vertical_seqno_); + s.store_field("catchain_seqno", catchain_seqno_); + s.store_field("config_hash", config_hash_); + { const std::vector> &v = members_; const std::uint32_t multiplicity = static_cast(v.size()); const auto vector_name = "vector[" + td::to_string(multiplicity)+ "]"; s.store_class_begin("members", vector_name.c_str()); for (std::uint32_t i = 0; i < multiplicity; i++) { if (v[i] == nullptr) { s.store_field("", "null"); } else { v[i]->store(s, ""); } } s.store_class_end(); } + s.store_class_end(); + } +} + validator_config_global::validator_config_global() : zero_state_() , init_block_() diff --git a/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api.h b/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api.h index 537ece403d..3f3f8e8ad8 100644 --- a/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api.h +++ b/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api.h @@ -162,6 +162,8 @@ class db_state_destroyedSessions; class db_state_gcBlockId; +class db_state_hardforks; + class db_state_initBlockId; class db_state_Key; @@ -344,7 +346,7 @@ class tonNode_success; class tonNode_zeroStateIdExt; -class validator_group; +class validator_Group; class validator_config_global; @@ -3215,6 +3217,30 @@ class db_state_gcBlockId final : public Object { void store(td::TlStorerToString &s, const char *field_name) const final; }; +class db_state_hardforks final : public Object { + public: + std::vector> blocks_; + + db_state_hardforks(); + + explicit db_state_hardforks(std::vector> &&blocks_); + + static const std::int32_t ID = -2047668988; + std::int32_t get_id() const final { + return ID; + } + + static object_ptr fetch(td::TlParser &p); + + explicit db_state_hardforks(td::TlParser &p); + + void store(td::TlStorerCalcLength &s) const final; + + void store(td::TlStorerUnsafe &s) const final; + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + class db_state_initBlockId final : public Object { public: object_ptr block_; @@ -3350,6 +3376,27 @@ class db_state_key_asyncSerializer final : public db_state_Key { void store(td::TlStorerToString &s, const char *field_name) const final; }; +class db_state_key_hardforks final : public db_state_Key { + public: + + db_state_key_hardforks(); + + static const std::int32_t ID = -420206662; + std::int32_t get_id() const final { + return ID; + } + + static object_ptr fetch(td::TlParser &p); + + explicit db_state_key_hardforks(td::TlParser &p); + + void store(td::TlStorerCalcLength &s) const final; + + void store(td::TlStorerUnsafe &s) const final; + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + class db_state_shardClient final : public Object { public: object_ptr block_; @@ -6440,7 +6487,13 @@ class tonNode_zeroStateIdExt final : public Object { void store(td::TlStorerToString &s, const char *field_name) const final; }; -class validator_group final : public Object { +class validator_Group: public Object { + public: + + static object_ptr fetch(td::TlParser &p); +}; + +class validator_group final : public validator_Group { public: std::int32_t workchain_; std::int64_t shard_; @@ -6457,7 +6510,7 @@ class validator_group final : public Object { return ID; } - static object_ptr fetch(td::TlParser &p); + static object_ptr fetch(td::TlParser &p); explicit validator_group(td::TlParser &p); @@ -6468,6 +6521,35 @@ class validator_group final : public Object { void store(td::TlStorerToString &s, const char *field_name) const final; }; +class validator_groupEx final : public validator_Group { + public: + std::int32_t workchain_; + std::int64_t shard_; + std::int32_t vertical_seqno_; + std::int32_t catchain_seqno_; + td::Bits256 config_hash_; + std::vector> members_; + + validator_groupEx(); + + validator_groupEx(std::int32_t workchain_, std::int64_t shard_, std::int32_t vertical_seqno_, std::int32_t catchain_seqno_, td::Bits256 const &config_hash_, std::vector> &&members_); + + static const std::int32_t ID = 479350270; + std::int32_t get_id() const final { + return ID; + } + + static object_ptr fetch(td::TlParser &p); + + explicit validator_groupEx(td::TlParser &p); + + void store(td::TlStorerCalcLength &s) const final; + + void store(td::TlStorerUnsafe &s) const final; + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + class validator_config_global final : public Object { public: object_ptr zero_state_; diff --git a/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api.hpp b/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api.hpp index 1f033147db..29f45bb527 100644 --- a/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api.hpp +++ b/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api.hpp @@ -344,6 +344,9 @@ bool downcast_call(Object &obj, const T &func) { case db_state_gcBlockId::ID: func(static_cast(obj)); return true; + case db_state_hardforks::ID: + func(static_cast(obj)); + return true; case db_state_initBlockId::ID: func(static_cast(obj)); return true; @@ -362,6 +365,9 @@ bool downcast_call(Object &obj, const T &func) { case db_state_key_asyncSerializer::ID: func(static_cast(obj)); return true; + case db_state_key_hardforks::ID: + func(static_cast(obj)); + return true; case db_state_shardClient::ID: func(static_cast(obj)); return true; @@ -725,6 +731,9 @@ bool downcast_call(Object &obj, const T &func) { case validator_group::ID: func(static_cast(obj)); return true; + case validator_groupEx::ID: + func(static_cast(obj)); + return true; case validator_config_global::ID: func(static_cast(obj)); return true; @@ -1470,6 +1479,9 @@ bool downcast_call(db_state_Key &obj, const T &func) { case db_state_key_asyncSerializer::ID: func(static_cast(obj)); return true; + case db_state_key_hardforks::ID: + func(static_cast(obj)); + return true; default: return false; } @@ -1874,6 +1886,26 @@ bool downcast_call(tonNode_PreparedState &obj, const T &func) { } } +/** + * Calls specified function object with the specified object downcasted to the most-derived type. + * \param[in] obj Object to pass as an argument to the function object. + * \param[in] func Function object to which the object will be passed. + * \returns whether function object call has happened. Should always return true for correct parameters. + */ +template +bool downcast_call(validator_Group &obj, const T &func) { + switch (obj.get_id()) { + case validator_group::ID: + func(static_cast(obj)); + return true; + case validator_groupEx::ID: + func(static_cast(obj)); + return true; + default: + return false; + } +} + /** * Calls specified function object with the specified object downcasted to the most-derived type. * \param[in] obj Object to pass as an argument to the function object. diff --git a/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api_json.cpp b/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api_json.cpp index 66c7c9df17..df0f134a1d 100644 --- a/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api_json.cpp +++ b/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api_json.cpp @@ -226,7 +226,8 @@ Result tl_constructor_from_string(ton_api::db_state_Key *object, const st {"db.state.key.initBlockId", 1971484899}, {"db.state.key.gcBlockId", -1015417890}, {"db.state.key.shardClient", -912576121}, - {"db.state.key.asyncSerializer", 699304479} + {"db.state.key.asyncSerializer", 699304479}, + {"db.state.key.hardforks", -420206662} }; auto it = m.find(str); if (it == m.end()) { @@ -445,6 +446,17 @@ Result tl_constructor_from_string(ton_api::tonNode_PreparedState *object, } return it->second; } +Result tl_constructor_from_string(ton_api::validator_Group *object, const std::string &str) { + static const std::unordered_map m = { + {"validator.group", -120029535}, + {"validator.groupEx", 479350270} + }; + auto it = m.find(str); + if (it == m.end()) { + return Status::Error(str + "Unknown class"); + } + return it->second; +} Result tl_constructor_from_string(ton_api::validator_config_Local *object, const std::string &str) { static const std::unordered_map m = { {"validator.config.local", 1716256616}, @@ -596,12 +608,14 @@ Result tl_constructor_from_string(ton_api::Object *object, const std::str {"db.state.asyncSerializer", -751883871}, {"db.state.destroyedSessions", -1381443196}, {"db.state.gcBlockId", -550453937}, + {"db.state.hardforks", -2047668988}, {"db.state.initBlockId", 1932303605}, {"db.state.key.destroyedSessions", -386404007}, {"db.state.key.initBlockId", 1971484899}, {"db.state.key.gcBlockId", -1015417890}, {"db.state.key.shardClient", -912576121}, {"db.state.key.asyncSerializer", 699304479}, + {"db.state.key.hardforks", -420206662}, {"db.state.shardClient", 186033821}, {"dht.key", -160964977}, {"dht.keyDescription", 673009157}, @@ -723,6 +737,7 @@ Result tl_constructor_from_string(ton_api::Object *object, const std::str {"tonNode.success", -1063902129}, {"tonNode.zeroStateIdExt", 494024110}, {"validator.group", -120029535}, + {"validator.groupEx", 479350270}, {"validator.config.global", -2038562966}, {"validator.config.local", 1716256616}, {"validator.config.random.local", 1501795426}, @@ -2554,6 +2569,15 @@ Status from_json(ton_api::db_state_gcBlockId &to, JsonObject &from) { } return Status::OK(); } +Status from_json(ton_api::db_state_hardforks &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "blocks", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.blocks_, value)); + } + } + return Status::OK(); +} Status from_json(ton_api::db_state_initBlockId &to, JsonObject &from) { { TRY_RESULT(value, get_json_object_field(from, "block", JsonValue::Type::Null, true)); @@ -2578,6 +2602,9 @@ Status from_json(ton_api::db_state_key_shardClient &to, JsonObject &from) { Status from_json(ton_api::db_state_key_asyncSerializer &to, JsonObject &from) { return Status::OK(); } +Status from_json(ton_api::db_state_key_hardforks &to, JsonObject &from) { + return Status::OK(); +} Status from_json(ton_api::db_state_shardClient &to, JsonObject &from) { { TRY_RESULT(value, get_json_object_field(from, "block", JsonValue::Type::Null, true)); @@ -4507,6 +4534,45 @@ Status from_json(ton_api::validator_group &to, JsonObject &from) { } return Status::OK(); } +Status from_json(ton_api::validator_groupEx &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "workchain", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.workchain_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "shard", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.shard_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "vertical_seqno", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.vertical_seqno_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "catchain_seqno", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.catchain_seqno_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "config_hash", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.config_hash_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "members", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.members_, value)); + } + } + return Status::OK(); +} Status from_json(ton_api::validator_config_global &to, JsonObject &from) { { TRY_RESULT(value, get_json_object_field(from, "zero_state", JsonValue::Type::Null, true)); @@ -6631,6 +6697,11 @@ void to_json(JsonValueScope &jv, const ton_api::db_state_gcBlockId &object) { jo << ctie("block", ToJson(object.block_)); } } +void to_json(JsonValueScope &jv, const ton_api::db_state_hardforks &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "db.state.hardforks"); + jo << ctie("blocks", ToJson(object.blocks_)); +} void to_json(JsonValueScope &jv, const ton_api::db_state_initBlockId &object) { auto jo = jv.enter_object(); jo << ctie("@type", "db.state.initBlockId"); @@ -6661,6 +6732,10 @@ void to_json(JsonValueScope &jv, const ton_api::db_state_key_asyncSerializer &ob auto jo = jv.enter_object(); jo << ctie("@type", "db.state.key.asyncSerializer"); } +void to_json(JsonValueScope &jv, const ton_api::db_state_key_hardforks &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "db.state.key.hardforks"); +} void to_json(JsonValueScope &jv, const ton_api::db_state_shardClient &object) { auto jo = jv.enter_object(); jo << ctie("@type", "db.state.shardClient"); @@ -7535,6 +7610,9 @@ void to_json(JsonValueScope &jv, const ton_api::tonNode_zeroStateIdExt &object) jo << ctie("root_hash", ToJson(object.root_hash_)); jo << ctie("file_hash", ToJson(object.file_hash_)); } +void to_json(JsonValueScope &jv, const ton_api::validator_Group &object) { + ton_api::downcast_call(const_cast(object), [&jv](const auto &object) { to_json(jv, object); }); +} void to_json(JsonValueScope &jv, const ton_api::validator_group &object) { auto jo = jv.enter_object(); jo << ctie("@type", "validator.group"); @@ -7544,6 +7622,16 @@ void to_json(JsonValueScope &jv, const ton_api::validator_group &object) { jo << ctie("config_hash", ToJson(object.config_hash_)); jo << ctie("members", ToJson(object.members_)); } +void to_json(JsonValueScope &jv, const ton_api::validator_groupEx &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "validator.groupEx"); + jo << ctie("workchain", ToJson(object.workchain_)); + jo << ctie("shard", ToJson(JsonInt64{object.shard_})); + jo << ctie("vertical_seqno", ToJson(object.vertical_seqno_)); + jo << ctie("catchain_seqno", ToJson(object.catchain_seqno_)); + jo << ctie("config_hash", ToJson(object.config_hash_)); + jo << ctie("members", ToJson(object.members_)); +} void to_json(JsonValueScope &jv, const ton_api::validator_config_global &object) { auto jo = jv.enter_object(); jo << ctie("@type", "validator.config.global"); diff --git a/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api_json.h b/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api_json.h index cfa271e76f..da8fa1524d 100644 --- a/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api_json.h +++ b/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api_json.h @@ -45,6 +45,7 @@ Result tl_constructor_from_string(ton_api::tonNode_DataFull *object, cons Result tl_constructor_from_string(ton_api::tonNode_Prepared *object, const std::string &str); Result tl_constructor_from_string(ton_api::tonNode_PreparedProof *object, const std::string &str); Result tl_constructor_from_string(ton_api::tonNode_PreparedState *object, const std::string &str); +Result tl_constructor_from_string(ton_api::validator_Group *object, const std::string &str); Result tl_constructor_from_string(ton_api::validator_config_Local *object, const std::string &str); Result tl_constructor_from_string(ton_api::validatorSession_Message *object, const std::string &str); Result tl_constructor_from_string(ton_api::validatorSession_round_Message *object, const std::string &str); @@ -160,12 +161,14 @@ Status from_json(ton_api::db_root_key_config &to, JsonObject &from); Status from_json(ton_api::db_state_asyncSerializer &to, JsonObject &from); Status from_json(ton_api::db_state_destroyedSessions &to, JsonObject &from); Status from_json(ton_api::db_state_gcBlockId &to, JsonObject &from); +Status from_json(ton_api::db_state_hardforks &to, JsonObject &from); Status from_json(ton_api::db_state_initBlockId &to, JsonObject &from); Status from_json(ton_api::db_state_key_destroyedSessions &to, JsonObject &from); Status from_json(ton_api::db_state_key_initBlockId &to, JsonObject &from); Status from_json(ton_api::db_state_key_gcBlockId &to, JsonObject &from); Status from_json(ton_api::db_state_key_shardClient &to, JsonObject &from); Status from_json(ton_api::db_state_key_asyncSerializer &to, JsonObject &from); +Status from_json(ton_api::db_state_key_hardforks &to, JsonObject &from); Status from_json(ton_api::db_state_shardClient &to, JsonObject &from); Status from_json(ton_api::dht_key &to, JsonObject &from); Status from_json(ton_api::dht_keyDescription &to, JsonObject &from); @@ -287,6 +290,7 @@ Status from_json(ton_api::tonNode_shardPublicOverlayId &to, JsonObject &from); Status from_json(ton_api::tonNode_success &to, JsonObject &from); Status from_json(ton_api::tonNode_zeroStateIdExt &to, JsonObject &from); Status from_json(ton_api::validator_group &to, JsonObject &from); +Status from_json(ton_api::validator_groupEx &to, JsonObject &from); Status from_json(ton_api::validator_config_global &to, JsonObject &from); Status from_json(ton_api::validator_config_local &to, JsonObject &from); Status from_json(ton_api::validator_config_random_local &to, JsonObject &from); @@ -505,6 +509,7 @@ void to_json(JsonValueScope &jv, const ton_api::db_root_key_config &object); void to_json(JsonValueScope &jv, const ton_api::db_state_asyncSerializer &object); void to_json(JsonValueScope &jv, const ton_api::db_state_destroyedSessions &object); void to_json(JsonValueScope &jv, const ton_api::db_state_gcBlockId &object); +void to_json(JsonValueScope &jv, const ton_api::db_state_hardforks &object); void to_json(JsonValueScope &jv, const ton_api::db_state_initBlockId &object); void to_json(JsonValueScope &jv, const ton_api::db_state_Key &object); void to_json(JsonValueScope &jv, const ton_api::db_state_key_destroyedSessions &object); @@ -512,6 +517,7 @@ void to_json(JsonValueScope &jv, const ton_api::db_state_key_initBlockId &object void to_json(JsonValueScope &jv, const ton_api::db_state_key_gcBlockId &object); void to_json(JsonValueScope &jv, const ton_api::db_state_key_shardClient &object); void to_json(JsonValueScope &jv, const ton_api::db_state_key_asyncSerializer &object); +void to_json(JsonValueScope &jv, const ton_api::db_state_key_hardforks &object); void to_json(JsonValueScope &jv, const ton_api::db_state_shardClient &object); void to_json(JsonValueScope &jv, const ton_api::dht_key &object); void to_json(JsonValueScope &jv, const ton_api::dht_keyDescription &object); @@ -650,7 +656,9 @@ void to_json(JsonValueScope &jv, const ton_api::tonNode_sessionId &object); void to_json(JsonValueScope &jv, const ton_api::tonNode_shardPublicOverlayId &object); void to_json(JsonValueScope &jv, const ton_api::tonNode_success &object); void to_json(JsonValueScope &jv, const ton_api::tonNode_zeroStateIdExt &object); +void to_json(JsonValueScope &jv, const ton_api::validator_Group &object); void to_json(JsonValueScope &jv, const ton_api::validator_group &object); +void to_json(JsonValueScope &jv, const ton_api::validator_groupEx &object); void to_json(JsonValueScope &jv, const ton_api::validator_config_global &object); void to_json(JsonValueScope &jv, const ton_api::validator_config_Local &object); void to_json(JsonValueScope &jv, const ton_api::validator_config_local &object); diff --git a/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api.cpp b/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api.cpp index 3a3e034c82..16050639bc 100644 --- a/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api.cpp +++ b/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api.cpp @@ -199,6 +199,36 @@ void key::store(td::TlStorerToString &s, const char *field_name) const { } } +keyStoreTypeDirectory::keyStoreTypeDirectory() + : directory_() +{} + +keyStoreTypeDirectory::keyStoreTypeDirectory(std::string const &directory_) + : directory_(std::move(directory_)) +{} + +const std::int32_t keyStoreTypeDirectory::ID; + +void keyStoreTypeDirectory::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "keyStoreTypeDirectory"); + s.store_field("directory", directory_); + s.store_class_end(); + } +} + +keyStoreTypeInMemory::keyStoreTypeInMemory() { +} + +const std::int32_t keyStoreTypeInMemory::ID; + +void keyStoreTypeInMemory::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "keyStoreTypeInMemory"); + s.store_class_end(); + } +} + logStreamDefault::logStreamDefault() { } @@ -294,12 +324,12 @@ void ok::store(td::TlStorerToString &s, const char *field_name) const { options::options() : config_() - , keystore_directory_() + , keystore_type_() {} -options::options(object_ptr &&config_, std::string const &keystore_directory_) +options::options(object_ptr &&config_, object_ptr &&keystore_type_) : config_(std::move(config_)) - , keystore_directory_(std::move(keystore_directory_)) + , keystore_type_(std::move(keystore_type_)) {} const std::int32_t options::ID; @@ -308,17 +338,19 @@ void options::store(td::TlStorerToString &s, const char *field_name) const { if (!LOG_IS_STRIPPED(ERROR)) { s.store_class_begin(field_name, "options"); if (config_ == nullptr) { s.store_field("config", "null"); } else { config_->store(s, "config"); } - s.store_field("keystore_directory", keystore_directory_); + if (keystore_type_ == nullptr) { s.store_field("keystore_type", "null"); } else { keystore_type_->store(s, "keystore_type"); } s.store_class_end(); } } sendGramsResult::sendGramsResult() : sent_until_() + , body_hash_() {} -sendGramsResult::sendGramsResult(std::int64_t sent_until_) +sendGramsResult::sendGramsResult(std::int64_t sent_until_, std::string const &body_hash_) : sent_until_(sent_until_) + , body_hash_(std::move(body_hash_)) {} const std::int32_t sendGramsResult::ID; @@ -327,6 +359,7 @@ void sendGramsResult::store(td::TlStorerToString &s, const char *field_name) con if (!LOG_IS_STRIPPED(ERROR)) { s.store_class_begin(field_name, "sendGramsResult"); s.store_field("sent_until", sent_until_); + s.store_bytes_field("body_hash", body_hash_); s.store_class_end(); } } @@ -545,13 +578,21 @@ raw_message::raw_message() : source_() , destination_() , value_() + , fwd_fee_() + , ihr_fee_() + , created_lt_() + , body_hash_() , message_() {} -raw_message::raw_message(std::string const &source_, std::string const &destination_, std::int64_t value_, std::string const &message_) +raw_message::raw_message(std::string const &source_, std::string const &destination_, std::int64_t value_, std::int64_t fwd_fee_, std::int64_t ihr_fee_, std::int64_t created_lt_, std::string const &body_hash_, std::string const &message_) : source_(std::move(source_)) , destination_(std::move(destination_)) , value_(value_) + , fwd_fee_(fwd_fee_) + , ihr_fee_(ihr_fee_) + , created_lt_(created_lt_) + , body_hash_(std::move(body_hash_)) , message_(std::move(message_)) {} @@ -563,6 +604,10 @@ void raw_message::store(td::TlStorerToString &s, const char *field_name) const { s.store_field("source", source_); s.store_field("destination", destination_); s.store_field("value", value_); + s.store_field("fwd_fee", fwd_fee_); + s.store_field("ihr_fee", ihr_fee_); + s.store_field("created_lt", created_lt_); + s.store_bytes_field("body_hash", body_hash_); s.store_bytes_field("message", message_); s.store_class_end(); } @@ -573,15 +618,19 @@ raw_transaction::raw_transaction() , data_() , transaction_id_() , fee_() + , storage_fee_() + , other_fee_() , in_msg_() , out_msgs_() {} -raw_transaction::raw_transaction(std::int64_t utime_, std::string const &data_, object_ptr &&transaction_id_, std::int64_t fee_, object_ptr &&in_msg_, std::vector> &&out_msgs_) +raw_transaction::raw_transaction(std::int64_t utime_, std::string const &data_, object_ptr &&transaction_id_, std::int64_t fee_, std::int64_t storage_fee_, std::int64_t other_fee_, object_ptr &&in_msg_, std::vector> &&out_msgs_) : utime_(utime_) , data_(std::move(data_)) , transaction_id_(std::move(transaction_id_)) , fee_(fee_) + , storage_fee_(storage_fee_) + , other_fee_(other_fee_) , in_msg_(std::move(in_msg_)) , out_msgs_(std::move(out_msgs_)) {} @@ -595,6 +644,8 @@ void raw_transaction::store(td::TlStorerToString &s, const char *field_name) con s.store_bytes_field("data", data_); if (transaction_id_ == nullptr) { s.store_field("transaction_id", "null"); } else { transaction_id_->store(s, "transaction_id"); } s.store_field("fee", fee_); + s.store_field("storage_fee", storage_fee_); + s.store_field("other_fee", other_fee_); if (in_msg_ == nullptr) { s.store_field("in_msg", "null"); } else { in_msg_->store(s, "in_msg"); } { const std::vector> &v = out_msgs_; const std::uint32_t multiplicity = static_cast(v.size()); const auto vector_name = "vector[" + td::to_string(multiplicity)+ "]"; s.store_class_begin("out_msgs", vector_name.c_str()); for (std::uint32_t i = 0; i < multiplicity; i++) { if (v[i] == nullptr) { s.store_field("", "null"); } else { v[i]->store(s, ""); } } s.store_class_end(); } s.store_class_end(); @@ -841,6 +892,18 @@ void createNewKey::store(td::TlStorerToString &s, const char *field_name) const } } +deleteAllKeys::deleteAllKeys() { +} + +const std::int32_t deleteAllKeys::ID; + +void deleteAllKeys::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "deleteAllKeys"); + s.store_class_end(); + } +} + deleteKey::deleteKey() : key_() {} diff --git a/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api.h b/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api.h index c4a9fa6d15..8d8275b55e 100644 --- a/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api.h +++ b/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api.h @@ -62,6 +62,8 @@ class inputKey; class key; +class KeyStoreType; + class LogStream; class logTags; @@ -264,6 +266,39 @@ class key final : public Object { void store(td::TlStorerToString &s, const char *field_name) const final; }; +class KeyStoreType: public Object { + public: +}; + +class keyStoreTypeDirectory final : public KeyStoreType { + public: + std::string directory_; + + keyStoreTypeDirectory(); + + explicit keyStoreTypeDirectory(std::string const &directory_); + + static const std::int32_t ID = -378990038; + std::int32_t get_id() const final { + return ID; + } + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class keyStoreTypeInMemory final : public KeyStoreType { + public: + + keyStoreTypeInMemory(); + + static const std::int32_t ID = -2106848825; + std::int32_t get_id() const final { + return ID; + } + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + class LogStream: public Object { public: }; @@ -359,13 +394,13 @@ class ok final : public Object { class options final : public Object { public: object_ptr config_; - std::string keystore_directory_; + object_ptr keystore_type_; options(); - options(object_ptr &&config_, std::string const &keystore_directory_); + options(object_ptr &&config_, object_ptr &&keystore_type_); - static const std::int32_t ID = 789823302; + static const std::int32_t ID = -1924388359; std::int32_t get_id() const final { return ID; } @@ -376,12 +411,13 @@ class options final : public Object { class sendGramsResult final : public Object { public: std::int64_t sent_until_; + std::string body_hash_; sendGramsResult(); - explicit sendGramsResult(std::int64_t sent_until_); + sendGramsResult(std::int64_t sent_until_, std::string const &body_hash_); - static const std::int32_t ID = -858318471; + static const std::int32_t ID = 426872238; std::int32_t get_id() const final { return ID; } @@ -568,13 +604,17 @@ class raw_message final : public Object { std::string source_; std::string destination_; std::int64_t value_; + std::int64_t fwd_fee_; + std::int64_t ihr_fee_; + std::int64_t created_lt_; + std::string body_hash_; std::string message_; raw_message(); - raw_message(std::string const &source_, std::string const &destination_, std::int64_t value_, std::string const &message_); + raw_message(std::string const &source_, std::string const &destination_, std::int64_t value_, std::int64_t fwd_fee_, std::int64_t ihr_fee_, std::int64_t created_lt_, std::string const &body_hash_, std::string const &message_); - static const std::int32_t ID = -259956097; + static const std::int32_t ID = -906281442; std::int32_t get_id() const final { return ID; } @@ -588,14 +628,16 @@ class raw_transaction final : public Object { std::string data_; object_ptr transaction_id_; std::int64_t fee_; + std::int64_t storage_fee_; + std::int64_t other_fee_; object_ptr in_msg_; std::vector> out_msgs_; raw_transaction(); - raw_transaction(std::int64_t utime_, std::string const &data_, object_ptr &&transaction_id_, std::int64_t fee_, object_ptr &&in_msg_, std::vector> &&out_msgs_); + raw_transaction(std::int64_t utime_, std::string const &data_, object_ptr &&transaction_id_, std::int64_t fee_, std::int64_t storage_fee_, std::int64_t other_fee_, object_ptr &&in_msg_, std::vector> &&out_msgs_); - static const std::int32_t ID = -1159530820; + static const std::int32_t ID = 1887601793; std::int32_t get_id() const final { return ID; } @@ -612,7 +654,7 @@ class raw_transactions final : public Object { raw_transactions(std::vector> &&transactions_, object_ptr &&previous_transaction_id_); - static const std::int32_t ID = 240548986; + static const std::int32_t ID = -2063931155; std::int32_t get_id() const final { return ID; } @@ -800,6 +842,21 @@ class createNewKey final : public Function { void store(td::TlStorerToString &s, const char *field_name) const final; }; +class deleteAllKeys final : public Function { + public: + + deleteAllKeys(); + + static const std::int32_t ID = 1608776483; + std::int32_t get_id() const final { + return ID; + } + + using ReturnType = object_ptr; + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + class deleteKey final : public Function { public: object_ptr key_; diff --git a/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api.hpp b/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api.hpp index 920df0e9eb..b5d3bd076c 100644 --- a/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api.hpp +++ b/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api.hpp @@ -41,6 +41,12 @@ bool downcast_call(Object &obj, const T &func) { case key::ID: func(static_cast(obj)); return true; + case keyStoreTypeDirectory::ID: + func(static_cast(obj)); + return true; + case keyStoreTypeInMemory::ID: + func(static_cast(obj)); + return true; case logStreamDefault::ID: func(static_cast(obj)); return true; @@ -148,6 +154,9 @@ bool downcast_call(Function &obj, const T &func) { case createNewKey::ID: func(static_cast(obj)); return true; + case deleteAllKeys::ID: + func(static_cast(obj)); + return true; case deleteKey::ID: func(static_cast(obj)); return true; @@ -270,6 +279,26 @@ bool downcast_call(Function &obj, const T &func) { } } +/** + * Calls specified function object with the specified object downcasted to the most-derived type. + * \param[in] obj Object to pass as an argument to the function object. + * \param[in] func Function object to which the object will be passed. + * \returns whether function object call has happened. Should always return true for correct parameters. + */ +template +bool downcast_call(KeyStoreType &obj, const T &func) { + switch (obj.get_id()) { + case keyStoreTypeDirectory::ID: + func(static_cast(obj)); + return true; + case keyStoreTypeInMemory::ID: + func(static_cast(obj)); + return true; + default: + return false; + } +} + /** * Calls specified function object with the specified object downcasted to the most-derived type. * \param[in] obj Object to pass as an argument to the function object. diff --git a/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api_json.cpp b/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api_json.cpp index 29ee340f62..c0b6ec7cea 100644 --- a/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api_json.cpp +++ b/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api_json.cpp @@ -14,6 +14,17 @@ namespace ton { namespace tonlib_api{ using namespace td; +Result tl_constructor_from_string(tonlib_api::KeyStoreType *object, const std::string &str) { + static const std::unordered_map m = { + {"keyStoreTypeDirectory", -378990038}, + {"keyStoreTypeInMemory", -2106848825} + }; + auto it = m.find(str); + if (it == m.end()) { + return Status::Error(str + "Unknown class"); + } + return it->second; +} Result tl_constructor_from_string(tonlib_api::LogStream *object, const std::string &str) { static const std::unordered_map m = { {"logStreamDefault", 1390581436}, @@ -51,14 +62,16 @@ Result tl_constructor_from_string(tonlib_api::Object *object, const std:: {"exportedPemKey", 1425473725}, {"inputKey", 869287093}, {"key", -1978362923}, + {"keyStoreTypeDirectory", -378990038}, + {"keyStoreTypeInMemory", -2106848825}, {"logStreamDefault", 1390581436}, {"logStreamFile", -1880085930}, {"logStreamEmpty", -499912244}, {"logTags", -1604930601}, {"logVerbosityLevel", 1734624234}, {"ok", -722616727}, - {"options", 789823302}, - {"sendGramsResult", -858318471}, + {"options", -1924388359}, + {"sendGramsResult", 426872238}, {"unpackedAccountAddress", 1892946998}, {"updateSendLiteServerQuery", -1555130916}, {"generic.accountStateRaw", -1387096685}, @@ -69,9 +82,9 @@ Result tl_constructor_from_string(tonlib_api::Object *object, const std:: {"internal.transactionId", -989527262}, {"raw.accountState", 461615898}, {"raw.initialAccountState", 777456197}, - {"raw.message", -259956097}, - {"raw.transaction", -1159530820}, - {"raw.transactions", 240548986}, + {"raw.message", -906281442}, + {"raw.transaction", 1887601793}, + {"raw.transactions", -2063931155}, {"testGiver.accountState", 860930426}, {"testWallet.accountState", 305698744}, {"testWallet.initialAccountState", -1231516227}, @@ -91,6 +104,7 @@ Result tl_constructor_from_string(tonlib_api::Function *object, const std {"changeLocalPassword", -1685491421}, {"close", -1187782273}, {"createNewKey", -1861385712}, + {"deleteAllKeys", 1608776483}, {"deleteKey", -1579595571}, {"exportEncryptedKey", 155352861}, {"exportKey", 399723440}, @@ -254,6 +268,18 @@ Status from_json(tonlib_api::key &to, JsonObject &from) { } return Status::OK(); } +Status from_json(tonlib_api::keyStoreTypeDirectory &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "directory", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.directory_, value)); + } + } + return Status::OK(); +} +Status from_json(tonlib_api::keyStoreTypeInMemory &to, JsonObject &from) { + return Status::OK(); +} Status from_json(tonlib_api::logStreamDefault &to, JsonObject &from) { return Status::OK(); } @@ -304,9 +330,9 @@ Status from_json(tonlib_api::options &to, JsonObject &from) { } } { - TRY_RESULT(value, get_json_object_field(from, "keystore_directory", JsonValue::Type::Null, true)); + TRY_RESULT(value, get_json_object_field(from, "keystore_type", JsonValue::Type::Null, true)); if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.keystore_directory_, value)); + TRY_STATUS(from_json(to.keystore_type_, value)); } } return Status::OK(); @@ -318,6 +344,12 @@ Status from_json(tonlib_api::sendGramsResult &to, JsonObject &from) { TRY_STATUS(from_json(to.sent_until_, value)); } } + { + TRY_RESULT(value, get_json_object_field(from, "body_hash", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json_bytes(to.body_hash_, value)); + } + } return Status::OK(); } Status from_json(tonlib_api::unpackedAccountAddress &to, JsonObject &from) { @@ -489,6 +521,30 @@ Status from_json(tonlib_api::raw_message &to, JsonObject &from) { TRY_STATUS(from_json(to.value_, value)); } } + { + TRY_RESULT(value, get_json_object_field(from, "fwd_fee", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.fwd_fee_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "ihr_fee", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.ihr_fee_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "created_lt", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.created_lt_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "body_hash", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json_bytes(to.body_hash_, value)); + } + } { TRY_RESULT(value, get_json_object_field(from, "message", JsonValue::Type::Null, true)); if (value.type() != JsonValue::Type::Null) { @@ -522,6 +578,18 @@ Status from_json(tonlib_api::raw_transaction &to, JsonObject &from) { TRY_STATUS(from_json(to.fee_, value)); } } + { + TRY_RESULT(value, get_json_object_field(from, "storage_fee", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.storage_fee_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "other_fee", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.other_fee_, value)); + } + } { TRY_RESULT(value, get_json_object_field(from, "in_msg", JsonValue::Type::Null, true)); if (value.type() != JsonValue::Type::Null) { @@ -725,6 +793,9 @@ Status from_json(tonlib_api::createNewKey &to, JsonObject &from) { } return Status::OK(); } +Status from_json(tonlib_api::deleteAllKeys &to, JsonObject &from) { + return Status::OK(); +} Status from_json(tonlib_api::deleteKey &to, JsonObject &from) { { TRY_RESULT(value, get_json_object_field(from, "key", JsonValue::Type::Null, true)); @@ -1291,6 +1362,18 @@ void to_json(JsonValueScope &jv, const tonlib_api::key &object) { jo << ctie("public_key", ToJson(object.public_key_)); jo << ctie("secret", ToJson(JsonBytes{object.secret_})); } +void to_json(JsonValueScope &jv, const tonlib_api::KeyStoreType &object) { + tonlib_api::downcast_call(const_cast(object), [&jv](const auto &object) { to_json(jv, object); }); +} +void to_json(JsonValueScope &jv, const tonlib_api::keyStoreTypeDirectory &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "keyStoreTypeDirectory"); + jo << ctie("directory", ToJson(object.directory_)); +} +void to_json(JsonValueScope &jv, const tonlib_api::keyStoreTypeInMemory &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "keyStoreTypeInMemory"); +} void to_json(JsonValueScope &jv, const tonlib_api::LogStream &object) { tonlib_api::downcast_call(const_cast(object), [&jv](const auto &object) { to_json(jv, object); }); } @@ -1328,12 +1411,15 @@ void to_json(JsonValueScope &jv, const tonlib_api::options &object) { if (object.config_) { jo << ctie("config", ToJson(object.config_)); } - jo << ctie("keystore_directory", ToJson(object.keystore_directory_)); + if (object.keystore_type_) { + jo << ctie("keystore_type", ToJson(object.keystore_type_)); + } } void to_json(JsonValueScope &jv, const tonlib_api::sendGramsResult &object) { auto jo = jv.enter_object(); jo << ctie("@type", "sendGramsResult"); jo << ctie("sent_until", ToJson(object.sent_until_)); + jo << ctie("body_hash", ToJson(JsonBytes{object.body_hash_})); } void to_json(JsonValueScope &jv, const tonlib_api::unpackedAccountAddress &object) { auto jo = jv.enter_object(); @@ -1416,6 +1502,10 @@ void to_json(JsonValueScope &jv, const tonlib_api::raw_message &object) { jo << ctie("source", ToJson(object.source_)); jo << ctie("destination", ToJson(object.destination_)); jo << ctie("value", ToJson(JsonInt64{object.value_})); + jo << ctie("fwd_fee", ToJson(JsonInt64{object.fwd_fee_})); + jo << ctie("ihr_fee", ToJson(JsonInt64{object.ihr_fee_})); + jo << ctie("created_lt", ToJson(JsonInt64{object.created_lt_})); + jo << ctie("body_hash", ToJson(JsonBytes{object.body_hash_})); jo << ctie("message", ToJson(JsonBytes{object.message_})); } void to_json(JsonValueScope &jv, const tonlib_api::raw_transaction &object) { @@ -1427,6 +1517,8 @@ void to_json(JsonValueScope &jv, const tonlib_api::raw_transaction &object) { jo << ctie("transaction_id", ToJson(object.transaction_id_)); } jo << ctie("fee", ToJson(JsonInt64{object.fee_})); + jo << ctie("storage_fee", ToJson(JsonInt64{object.storage_fee_})); + jo << ctie("other_fee", ToJson(JsonInt64{object.other_fee_})); if (object.in_msg_) { jo << ctie("in_msg", ToJson(object.in_msg_)); } @@ -1514,6 +1606,10 @@ void to_json(JsonValueScope &jv, const tonlib_api::createNewKey &object) { jo << ctie("mnemonic_password", ToJson(JsonBytes{object.mnemonic_password_})); jo << ctie("random_extra_seed", ToJson(JsonBytes{object.random_extra_seed_})); } +void to_json(JsonValueScope &jv, const tonlib_api::deleteAllKeys &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "deleteAllKeys"); +} void to_json(JsonValueScope &jv, const tonlib_api::deleteKey &object) { auto jo = jv.enter_object(); jo << ctie("@type", "deleteKey"); diff --git a/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api_json.h b/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api_json.h index ebe3a9cfd7..a53d9030aa 100644 --- a/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api_json.h +++ b/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api_json.h @@ -11,6 +11,7 @@ namespace ton { namespace tonlib_api{ using namespace td; +Result tl_constructor_from_string(tonlib_api::KeyStoreType *object, const std::string &str); Result tl_constructor_from_string(tonlib_api::LogStream *object, const std::string &str); Result tl_constructor_from_string(tonlib_api::generic_AccountState *object, const std::string &str); Result tl_constructor_from_string(tonlib_api::Object *object, const std::string &str); @@ -24,6 +25,8 @@ Status from_json(tonlib_api::exportedKey &to, JsonObject &from); Status from_json(tonlib_api::exportedPemKey &to, JsonObject &from); Status from_json(tonlib_api::inputKey &to, JsonObject &from); Status from_json(tonlib_api::key &to, JsonObject &from); +Status from_json(tonlib_api::keyStoreTypeDirectory &to, JsonObject &from); +Status from_json(tonlib_api::keyStoreTypeInMemory &to, JsonObject &from); Status from_json(tonlib_api::logStreamDefault &to, JsonObject &from); Status from_json(tonlib_api::logStreamFile &to, JsonObject &from); Status from_json(tonlib_api::logStreamEmpty &to, JsonObject &from); @@ -55,6 +58,7 @@ Status from_json(tonlib_api::addLogMessage &to, JsonObject &from); Status from_json(tonlib_api::changeLocalPassword &to, JsonObject &from); Status from_json(tonlib_api::close &to, JsonObject &from); Status from_json(tonlib_api::createNewKey &to, JsonObject &from); +Status from_json(tonlib_api::deleteAllKeys &to, JsonObject &from); Status from_json(tonlib_api::deleteKey &to, JsonObject &from); Status from_json(tonlib_api::exportEncryptedKey &to, JsonObject &from); Status from_json(tonlib_api::exportKey &to, JsonObject &from); @@ -103,6 +107,9 @@ void to_json(JsonValueScope &jv, const tonlib_api::exportedKey &object); void to_json(JsonValueScope &jv, const tonlib_api::exportedPemKey &object); void to_json(JsonValueScope &jv, const tonlib_api::inputKey &object); void to_json(JsonValueScope &jv, const tonlib_api::key &object); +void to_json(JsonValueScope &jv, const tonlib_api::KeyStoreType &object); +void to_json(JsonValueScope &jv, const tonlib_api::keyStoreTypeDirectory &object); +void to_json(JsonValueScope &jv, const tonlib_api::keyStoreTypeInMemory &object); void to_json(JsonValueScope &jv, const tonlib_api::LogStream &object); void to_json(JsonValueScope &jv, const tonlib_api::logStreamDefault &object); void to_json(JsonValueScope &jv, const tonlib_api::logStreamFile &object); @@ -136,6 +143,7 @@ void to_json(JsonValueScope &jv, const tonlib_api::addLogMessage &object); void to_json(JsonValueScope &jv, const tonlib_api::changeLocalPassword &object); void to_json(JsonValueScope &jv, const tonlib_api::close &object); void to_json(JsonValueScope &jv, const tonlib_api::createNewKey &object); +void to_json(JsonValueScope &jv, const tonlib_api::deleteAllKeys &object); void to_json(JsonValueScope &jv, const tonlib_api::deleteKey &object); void to_json(JsonValueScope &jv, const tonlib_api::exportEncryptedKey &object); void to_json(JsonValueScope &jv, const tonlib_api::exportKey &object); diff --git a/submodules/ton/tonlib-src/tl/generate/scheme/ton_api.tl b/submodules/ton/tonlib-src/tl/generate/scheme/ton_api.tl index 89827f7f5c..942ec47ef9 100644 --- a/submodules/ton/tonlib-src/tl/generate/scheme/ton_api.tl +++ b/submodules/ton/tonlib-src/tl/generate/scheme/ton_api.tl @@ -444,12 +444,14 @@ db.state.initBlockId block:tonNode.blockIdExt = db.state.InitBlockId; db.state.gcBlockId block:tonNode.blockIdExt = db.state.GcBlockId; db.state.shardClient block:tonNode.blockIdExt = db.state.ShardClient; db.state.asyncSerializer block:tonNode.blockIdExt last:tonNode.blockIdExt last_ts:int = db.state.AsyncSerializer; +db.state.hardforks blocks:(vector tonNode.blockIdExt) = db.state.Hardforks; db.state.key.destroyedSessions = db.state.Key; db.state.key.initBlockId = db.state.Key; db.state.key.gcBlockId = db.state.Key; db.state.key.shardClient = db.state.Key; db.state.key.asyncSerializer = db.state.Key; +db.state.key.hardforks = db.state.Key; db.lt.el.key workchain:int shard:long idx:int = db.lt.Key; db.lt.desc.key workchain:int shard:long = db.lt.Key; @@ -466,6 +468,7 @@ db.lt.status.value total_shards:int = db.lt.status.Value; validator.groupMember public_key_hash:int256 adnl:int256 weight:long = engine.validator.GroupMember; validator.group workchain:int shard:long catchain_seqno:int config_hash:int256 members:(vector validator.groupMember) = validator.Group; +validator.groupEx workchain:int shard:long vertical_seqno:int catchain_seqno:int config_hash:int256 members:(vector validator.groupMember) = validator.Group; ---functions--- diff --git a/submodules/ton/tonlib-src/tl/generate/scheme/ton_api.tlo b/submodules/ton/tonlib-src/tl/generate/scheme/ton_api.tlo index 6959d9a3c980cb5ecd17266f18386e40d8a183c9..6727841e909c603c2b4c1c5eaf299095414b0573 100644 GIT binary patch delta 456 zcmeycg!#t`X5L4$^{p77V9iF}+1%nRyq{ZzQj+wFOA<>`^*j=bQquB^vWqA8bNh zueX&!H97-kGy_O{@`DpDEMP`N>;wsrMK_NL`G8zj?*Hu6N@frY DcM+wN delta 261 zcmeydg89P|X5L4$^{p77VD(1c+1!(FaGQw!IcT|$CnZU*xFoS8RnI%M5~zZ8vm%eN zpvc0y8$bBV5_2+B5=-)n^xTW`OA96+V3ye2Ae+L($hY~a{CeBTEO9LoATw?r6Y>EW zUgXTC!(rQY5F|EvL7Wb5$tQ6dxFuEM@#xHmH^8ZL^N08o4lE$2Pu{cO3Yf8Z&!Rns E0G)$qng9R* diff --git a/submodules/ton/tonlib-src/tl/generate/scheme/tonlib_api.tl b/submodules/ton/tonlib-src/tl/generate/scheme/tonlib_api.tl index 07a2f32c14..deae3fa970 100644 --- a/submodules/ton/tonlib-src/tl/generate/scheme/tonlib_api.tl +++ b/submodules/ton/tonlib-src/tl/generate/scheme/tonlib_api.tl @@ -16,8 +16,12 @@ vector {t:Type} # [ t ] = Vector t; error code:int32 message:string = Error; ok = Ok; +keyStoreTypeDirectory directory:string = KeyStoreType; +keyStoreTypeInMemory = KeyStoreType; + config config:string blockchain_name:string use_callbacks_for_network:Bool ignore_cache:Bool = Config; -options config:config keystore_directory:string = Options; + +options config:config keystore_type:KeyStoreType = Options; key public_key:string secret:secureBytes = Key; inputKey key:key local_password:secureBytes = InputKey; @@ -35,9 +39,9 @@ internal.transactionId lt:int64 hash:bytes = internal.TransactionId; raw.initialAccountState code:bytes data:bytes = raw.InitialAccountState; raw.accountState balance:int64 code:bytes data:bytes last_transaction_id:internal.transactionId sync_utime:int53 = raw.AccountState; -raw.message source:string destination:string value:int64 message:bytes = raw.Message; -raw.transaction utime:int53 data:bytes transaction_id:internal.transactionId fee:int64 in_msg:raw.message out_msgs:vector = raw.Transaction; -raw.transactions transactions:vector previous_transaction_id:internal.transactionId = raw.Transactions; +raw.message source:string destination:string value:int64 fwd_fee:int64 ihr_fee:int64 created_lt:int64 body_hash:bytes message:bytes = raw.Message; +raw.transaction utime:int53 data:bytes transaction_id:internal.transactionId fee:int64 storage_fee:int64 other_fee:int64 in_msg:raw.message out_msgs:vector = raw.Transaction; +raw.transactions transactions:vector previous_transaction_id:internal.transactionId = raw.Transactions; testWallet.initialAccountState public_key:string = testWallet.InitialAccountState; testWallet.accountState balance:int64 seqno:int32 last_transaction_id:internal.transactionId sync_utime:int53 = testWallet.AccountState; @@ -59,7 +63,7 @@ generic.accountStateWallet account_state:wallet.accountState = generic.AccountSt generic.accountStateTestGiver account_state:testGiver.accountState = generic.AccountState; generic.accountStateUninited account_state:uninited.accountState = generic.AccountState; -sendGramsResult sent_until:int53 = SendGramsResult; +sendGramsResult sent_until:int53 body_hash:bytes = SendGramsResult; updateSendLiteServerQuery id:int64 data:bytes = Update; @@ -90,6 +94,7 @@ options.setConfig config:config = Ok; createNewKey local_password:secureBytes mnemonic_password:secureBytes random_extra_seed:secureBytes = Key; deleteKey key:key = Ok; +deleteAllKeys = Ok; exportKey input_key:inputKey = ExportedKey; exportPemKey input_key:inputKey key_password:secureBytes = ExportedPemKey; exportEncryptedKey input_key:inputKey key_password:secureBytes = ExportedEncryptedKey; diff --git a/submodules/ton/tonlib-src/tl/generate/scheme/tonlib_api.tlo b/submodules/ton/tonlib-src/tl/generate/scheme/tonlib_api.tlo index b77565e03e200204e3f53b0210c4bd17840045c8..180f3521725fa8e4ac53b9db1d7e62587be7636c 100644 GIT binary patch delta 811 zcmcbRcp{be(QJJy1}MB$vLb69?A`t(kg zU@l=<*IOvLc>?neMix1{-zO*gu&RhOwlo#+7bTYKg%l;`6(=T_Waj5hZeWyPdHdp5 z%jN~F8H|jEn>pF@SfV?sWRKnF=byRXTa0+*Y- zo=?^VBoA}!RXMJhTLY$AA}TR58fc@g+cSLo9-6gINnR3ase@Uxh3vF!+m8^HSW45_5}#Qj1G- zN=+0)8X;?q)7Cx1|oWY5ef0<$j&NN{r{7o{eaq^88@luSM^Aj!pvY=zk5 zAG#X4Aj4n|2Za|rmP!z@1QLT-xK*s1ha2R7pfljMaORg}q=GGF0NFCxL0kY5>mlMM z8X)sQaRmaffB~5Y5n*5e*$GMjlQ)QqfK$Tc6XF)EAQg<0StaZtiNizU2Q#D2W=EOd zj6%x4AII~iq~@fSq&nv0cmtzja-6K%W*a#ZCQewOvQN&{)tdRYjTF}4v3J7-T|o43;jDhAp2k* F0RRe;ABF$` delta 507 zcmX?+dLfbb(QJJy1}MkWFV`OVR8Yx3=3Gr9R3PfkX`)6sd*{xMTxn^ zL8-;1IVB*mo5zHF7$+MFs84>w%K>pwhkys0B*;bFMTzBlxv9m)iRq~zK1eOgw-jJ9=$5Z6$5fQKS)POQDRR*W`t@l za%R)vux&dCQjKh46)*rM7f6b*fEgW<7OY?ulaET;gM~J8Nc~`D)ZWY}_nUFEiGm3e z#Qix+9E=cFh4L0=a1d-ZP(Q-N2{H!c8m7q$^|U8%&|;aaqh$awDM9N8MEB$v-6;^w eUvx7d#!ODo-vJSlF*pDfdSG~m2NZlT=K=uPL$>t* diff --git a/submodules/ton/tonlib-src/tonlib/CMakeLists.txt b/submodules/ton/tonlib-src/tonlib/CMakeLists.txt index 3867779643..a46f3d3c7b 100644 --- a/submodules/ton/tonlib-src/tonlib/CMakeLists.txt +++ b/submodules/ton/tonlib-src/tonlib/CMakeLists.txt @@ -5,6 +5,7 @@ if (NOT OPENSSL_FOUND) endif() set(TONLIB_SOURCE + tonlib/CellString.cpp tonlib/Client.cpp tonlib/Config.cpp tonlib/ExtClient.cpp @@ -12,6 +13,7 @@ set(TONLIB_SOURCE tonlib/ExtClientOutbound.cpp tonlib/GenericAccount.cpp tonlib/KeyStorage.cpp + tonlib/KeyValue.cpp tonlib/LastBlock.cpp tonlib/LastBlockStorage.cpp tonlib/Logging.cpp @@ -21,6 +23,7 @@ set(TONLIB_SOURCE tonlib/utils.cpp tonlib/Wallet.cpp + tonlib/CellString.h tonlib/Client.h tonlib/Config.h tonlib/ExtClient.h @@ -28,6 +31,7 @@ set(TONLIB_SOURCE tonlib/ExtClientOutbound.h tonlib/GenericAccount.h tonlib/KeyStorage.h + tonlib/KeyValue.h tonlib/LastBlock.h tonlib/LastBlockStorage.h tonlib/Logging.h diff --git a/submodules/ton/tonlib-src/tonlib/test/offline.cpp b/submodules/ton/tonlib-src/tonlib/test/offline.cpp index 63a52fae39..d6f6d92ce1 100644 --- a/submodules/ton/tonlib-src/tonlib/test/offline.cpp +++ b/submodules/ton/tonlib-src/tonlib/test/offline.cpp @@ -28,6 +28,7 @@ #include "vm/boc.h" #include "vm/cells/MerkleProof.h" +#include "tonlib/CellString.h" #include "tonlib/utils.h" #include "tonlib/TestGiver.h" #include "tonlib/TestWallet.h" @@ -53,6 +54,20 @@ #include "tonlib/keys/Mnemonic.h" #include "tonlib/keys/SimpleEncryption.h" +TEST(Tonlib, CellString) { + for (unsigned size : + {0, 1, 7, 8, 35, 127, 128, 255, 256, (int)vm::CellString::max_bytes - 1, (int)vm::CellString::max_bytes}) { + auto str = td::rand_string('a', 'z', size); + for (unsigned head : {0, 1, 7, 8, 127, 35 * 8, 127 * 8, 1023, 1024}) { + vm::CellBuilder cb; + vm::CellString::store(cb, str, head).ensure(); + auto cs = vm::load_cell_slice(cb.finalize()); + auto got_str = vm::CellString::load(cs, head).move_as_ok(); + ASSERT_EQ(str, got_str); + } + } +}; + using namespace tonlib; std::string current_dir() { @@ -268,20 +283,23 @@ static auto sync_send = [](auto &client, auto query) { TEST(Tonlib, InitClose) { using tonlib_api::make_object; auto cfg = [](auto str) { return make_object(str, "", false, false); }; + auto dir = [](auto str) { return make_object(str); }; { Client client; sync_send(client, make_object()).ensure(); - sync_send(client, make_object(make_object(nullptr, "."))).ensure_error(); + sync_send(client, make_object(make_object(nullptr, dir(".")))) + .ensure_error(); } { Client client; sync_send(client, make_object(nullptr)).ensure_error(); - sync_send(client, make_object(make_object(cfg("fdajkfldsjkafld"), "."))) + sync_send(client, make_object(make_object(cfg("fdajkfldsjkafld"), dir(".")))) .ensure_error(); - sync_send(client, make_object(make_object(nullptr, "fdhskfds"))) + sync_send(client, make_object(make_object(nullptr, dir("fdhskfds")))) + .ensure_error(); + sync_send(client, make_object(make_object(nullptr, dir(".")))).ensure(); + sync_send(client, make_object(make_object(nullptr, dir(".")))) .ensure_error(); - sync_send(client, make_object(make_object(nullptr, "."))).ensure(); - sync_send(client, make_object(make_object(nullptr, "."))).ensure_error(); td::Slice bad_config = R"abc( { @@ -294,7 +312,8 @@ TEST(Tonlib, InitClose) { sync_send(client, make_object()).ensure_error(); sync_send(client, make_object()).ensure(); sync_send(client, make_object()).ensure_error(); - sync_send(client, make_object(make_object(nullptr, "."))).ensure_error(); + sync_send(client, make_object(make_object(nullptr, dir(".")))) + .ensure_error(); } } @@ -389,7 +408,9 @@ TEST(Tonlib, ParseAddres) { Client client; // init - sync_send(client, make_object(make_object(nullptr, "."))).ensure(); + sync_send(client, make_object( + make_object(nullptr, make_object(".")))) + .ensure(); sync_send(client, make_object("hello")).ensure_error(); auto addr = @@ -409,7 +430,9 @@ TEST(Tonlib, KeysApi) { Client client; // init - sync_send(client, make_object(make_object(nullptr, "."))).ensure(); + sync_send(client, make_object( + make_object(nullptr, make_object(".")))) + .ensure(); auto local_password = td::SecureString("local password"); auto mnemonic_password = td::SecureString("mnemonic password"); { diff --git a/submodules/ton/tonlib-src/tonlib/test/online.cpp b/submodules/ton/tonlib-src/tonlib/test/online.cpp index 0425f53757..6ac47921df 100644 --- a/submodules/ton/tonlib-src/tonlib/test/online.cpp +++ b/submodules/ton/tonlib-src/tonlib/test/online.cpp @@ -197,7 +197,8 @@ int main(int argc, char* argv[]) { Client client; { sync_send(client, make_object(make_object( - make_object(global_config_str, "", false, false), "."))) + make_object(global_config_str, "", false, false), + make_object(".")))) .ensure(); } //dump_transaction_history(client, get_test_giver_address(client)); @@ -211,7 +212,8 @@ int main(int argc, char* argv[]) { { // init sync_send(client, make_object(make_object( - make_object(global_config_str, "", false, false), "."))) + make_object(global_config_str, "", false, false), + make_object(".")))) .ensure(); auto key = sync_send(client, make_object( diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/.TonlibClient.cpp.swp b/submodules/ton/tonlib-src/tonlib/tonlib/.TonlibClient.cpp.swp deleted file mode 100644 index a3dd3f30b99a9cce56d2bc84b63efbe45bd6a75c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 90112 zcmeI537lM2mH%7ZKtw^s1($h5jn&ZUEXZOJT9c53nAPqM3bKnG+%@!CJ8H>H&;9<=(^ITB!s^Tk%jDK< zpH=!?W69=XX?3l(bIG=Pt-n$$6)UNiE_MknE!9TDrOjGZP$`eNuVMXbO{E-GoBgG! zsnq-3Kf4s@QeZzRFx?zma>@}sC#+bm_{RgD(zbJM8f%g7-`~CIQ{Ri3WTkQ8g+{65E=^t&cpJl%%Q}^wk zJ;&PnpGw`or@g+^e*Y+S|6ca`>Gu0b`-02=-uC)x`#qexf2h6g+UJ$2`?k7054O+! zFm>Nv?tXPC(4|0^0$mDpDbS@rmjYc1bScoKK$ikt3LGQ~6i0h{M92Gv{D%@;v-$i9 zh56sW=fNJ31K&r<{s_1h>;yURBNX%Zg7<*)!F|Eu;5#Vvw}2bL4dC@)57-V)1`h{! zU{v@X_#}8IxD;FhM!`DpIB;L^8;lFT2Hyg=fRBUMf!Bg(fb&5CYyum>Dd0Zf5b$3Z z9=-zhff=wH>;fCXlfkc0TrUSN1up@Q1c!isN8x=fD1+7D;ot~xIQTD=<*$Ql!4+T+ zm;k8Nlfa4KPbka30~dki;0A0F zuLds%mxJelonQ!@26Es?@J-rK+fmyv2%4k$JiZu{ZaOw86S}0@?;oPntI(9VyHQ~YIL+7HX1?Ee9PUbdU;o|8RmP) zYaa+)KK+fbSulC#!aeS1p&pL)O1b2dj}po?q}G$QU183q-P_wI`Fl4iO}VC}^{&d_ za^2CwyJau+_6B=<5RlY7rM-wAQ>*9mtKE!{&6o8VnDfT{v@d zu30OL6f4DQDJ<0Lh2})Pw%a41yCrSbOREX72E)d5rMXgm(%nva`~c;5Y2?fUV=H$} z=JRX9N@a-hh6910PO2PqC+Q8Q=h(7IDnrd;bGnhwudUZ>_1vO$#d0MaC97b%I#n#~ zbV&xe6}^kJKb6OV9Ek;|ou*aSvgIybwtds4VCBl-q!Vl}C{B}xKIf8HGC&0?wd#0I z)7jsW#HFyc?JqY9)#*wl=jUwi1*f?V(X5Q*^UcEgdU3MRUu+a8cQ_u_3yq!Sshp!* zL&&J5OAyx8prH3j^Emec4K{ac#Vy`xvq?+Yj=ZX*Y(|pEbS7>(sV0@zvjug7Iq1SH@tLO9u3ML1`(E z!6Is78IS4p__4-Bu|8U8_po<2{mMvXC#mZQFV#beR8aaA%A+}39!Z&};uq(9r95gL z&S(kg*+Qyfvs}t*slXPZXj-qJ)PM=VfSQ#;ZRCQm)GSOj>nrtArA&E?Q{{YKehr27 zU35(Q>X6WPAdpH3d-Yp^cX19hFHRPB!dWz3Ni(`0%CH`Q)yOFCm$uKr!|k7wOfkiA zuF#5gh7VoYdo@|gREjo<0z*1}Cs(Rf8%^z(Qtau*V*8ku{L!P~Sh*THjyTpEH0v{k zvD}Wu=LLHmyBs?;*w<@nIR}H-HneHOnzgxJ;W~@f*P1~w*fq&?PztAH`pyT7T%_OpJpr@x=gy1mMQ2HtKl;(VNxmv1BkA}gb=IGMt zX1UT>I#sJTmrfO%6a5p5vhFv-MzbOJvTic5*DJN+XgJ#D?ZIMov^JS~eb?mDky
HZVV=2U*^(%rjv_m5Yn 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 V-%_;74hj52eLR@^cRS&d@Na5XROA2v literal 0 HcmV?d00001 diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/.Wallet.cpp.swp b/submodules/ton/tonlib-src/tonlib/tonlib/.Wallet.cpp.swp index 61ab3cfd77c15374f1acaed3f8b729a3faec398c..e45873644ba6cb1bde23b2268f363ea8c5627985 100644 GIT binary patch delta 720 zcmYk)PiWIn90%}UI(1vCZ3SVY;`ZyLUFy2gKP#)zqT-x$APOBjR7AS=tpt)(nkZtK zD|phWDDfiVVW5J7x)HpH2*Mbm;6VftcF>C`dJu$xc<~$A?0)bG@6YeOykGJf4XM$P zLX(M!BS$$qkR(KqsJ?jfWOaU;K94ShRsvGq-Wu#~-|S8z#+}{4H-Rl1(9|S6kdFk; z&&(m?0+gWy#~=ks=!P!v!6P5hH4qSjPUwKAUZOitfWwf17wts%AOmSg!BQL13HZ}W z^a<|6^;VjpLuhos(k7x?U_k+fVGz0?1n)Nz-GBlNf)75To;lE92mdS#V#Dlc}t`F>|F>)OC|{oN)W<6w7NPIqpx!xQGT6u|NKTWxLoHyh-k1#?8)W>Pk{ERtJtDJs z02dc=0Ru?l2tMu>d5t>GVh|~O+a@tn&u*D4`9DO(F|;fikk_!`pz!B>J(*%0KZH>-Yj6 zb;WiylE$6Psrlz^x|X_huq-korde=`rGm@LOHj>NcEZ2a@k*((j@u{wiO$bTUyDW# zWJ<*;^N!d?^0@X*-5iI~@D+UDt`89&x%CqygD(kmT7ZCi%}<^QEWXUzt5Yxjl@^}O`gdX6_m gn+=g(H2y9(^EZ~LM{#buchvCDgoB1&9$4kDEyvS+FaQ7m diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/CellString.cpp b/submodules/ton/tonlib-src/tonlib/tonlib/CellString.cpp new file mode 100644 index 0000000000..ad2cbf5f8f --- /dev/null +++ b/submodules/ton/tonlib-src/tonlib/tonlib/CellString.cpp @@ -0,0 +1,64 @@ +#include "CellString.h" +#include "td/utils/misc.h" + +#include "vm/cells/CellSlice.h" + +namespace vm { +td::Status CellString::store(CellBuilder &cb, td::Slice slice, unsigned int top_bits) { + td::uint32 size = td::narrow_cast(slice.size() * 8); + return store(cb, td::BitSlice(slice.ubegin(), size), top_bits); +} + +td::Status CellString::store(CellBuilder &cb, td::BitSlice slice, unsigned int top_bits) { + if (slice.size() > max_bytes * 8) { + return td::Status::Error("String is too long (1)"); + } + unsigned int head = td::min(slice.size(), td::min(cb.remaining_bits(), top_bits)) / 8 * 8; + auto max_bits = vm::Cell::max_bits / 8 * 8; + auto depth = 1 + (slice.size() - head + max_bits - 1) / max_bits; + if (depth > max_chain_length) { + return td::Status::Error("String is too long (2)"); + } + cb.append_bitslice(slice.subslice(0, head)); + slice.advance(head); + if (slice.size() == 0) { + return td::Status::OK(); + } + CellBuilder child_cb; + store(child_cb, std::move(slice)); + cb.store_ref(child_cb.finalize()); + return td::Status::OK(); +} + +template +void CellString::for_each(F &&f, CellSlice &cs, unsigned int top_bits) { + unsigned int head = td::min(cs.size(), top_bits); + f(cs.prefetch_bits(head)); + if (!cs.have_refs()) { + return; + } + auto ref = cs.prefetch_ref(); + while (true) { + auto cs = vm::load_cell_slice(ref); + f(cs.prefetch_bits(cs.size())); + if (!cs.have_refs()) { + return; + } + ref = cs.prefetch_ref(); + } +} + +td::Result CellString::load(CellSlice &cs, unsigned int top_bits) { + unsigned int size = 0; + for_each([&](auto slice) { size += slice.size(); }, cs, top_bits); + if (size % 8 != 0) { + return td::Status::Error("Size is not divisible by 8"); + } + std::string res(size / 8, 0); + + td::BitPtr to(td::MutableSlice(res).ubegin()); + for_each([&](auto slice) { to.concat(slice); }, cs, top_bits); + CHECK(to.offs == (int)size); + return res; +} +} // namespace vm diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/CellString.h b/submodules/ton/tonlib-src/tonlib/tonlib/CellString.h new file mode 100644 index 0000000000..89c933d876 --- /dev/null +++ b/submodules/ton/tonlib-src/tonlib/tonlib/CellString.h @@ -0,0 +1,22 @@ +#pragma once + +#include "td/utils/Status.h" + +#include "vm/cells/CellBuilder.h" + +namespace vm { +class CellString { + public: + static constexpr unsigned int max_bytes = 1024; + static constexpr unsigned int max_chain_length = 16; + + static td::Status store(CellBuilder &cb, td::Slice slice, unsigned int top_bits = Cell::max_bits); + static td::Status store(CellBuilder &cb, td::BitSlice slice, unsigned int top_bits = Cell::max_bits); + static td::Result load(CellSlice &cs, unsigned int top_bits = Cell::max_bits); + + private: + template + static void for_each(F &&f, CellSlice &cs, unsigned int top_bits = Cell::max_bits); +}; + +} // namespace vm diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/ExtClient.cpp b/submodules/ton/tonlib-src/tonlib/tonlib/ExtClient.cpp index 0ec942ed90..442d65033a 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/ExtClient.cpp +++ b/submodules/ton/tonlib-src/tonlib/tonlib/ExtClient.cpp @@ -30,7 +30,7 @@ void ExtClient::with_last_block(td::Promise promise) { }); }; if (client_.last_block_actor_.empty()) { - return P.set_error(td::Status::Error(500, "No lite clients")); + return P.set_error(TonlibError::NoLiteServers()); } td::actor::send_closure(client_.last_block_actor_, &LastBlock::get_last_block, std::move(P)); } @@ -44,7 +44,7 @@ void ExtClient::send_raw_query(td::BufferSlice query, td::Promise void send_query(QueryT query, td::Promise promise) { auto raw_query = ton::serialize_tl_object(&query, true); - LOG(ERROR) << "send query to liteserver: " << to_string(query); + td::uint32 tag = td::Random::fast_uint32(); + VLOG(lite_server) << "send query to liteserver: " << tag << " " << to_string(query); td::BufferSlice liteserver_query = ton::serialize_tl_object(ton::create_tl_object(std::move(raw_query)), true); - send_raw_query(std::move(liteserver_query), [promise = std::move(promise)](td::Result R) mutable { - promise.set_result([&]() -> td::Result { - TRY_RESULT(data, std::move(R)); - auto r_error = ton::fetch_tl_object(data.clone(), true); - if (r_error.is_ok()) { - auto f = r_error.move_as_ok(); - return td::Status::Error(f->code_, f->message_); - } - return ton::fetch_result(std::move(data)); - }()); - }); + send_raw_query( + std::move(liteserver_query), [promise = std::move(promise), tag](td::Result R) mutable { + auto res = [&]() -> td::Result { + TRY_RESULT_PREFIX(data, std::move(R), TonlibError::LiteServerNetwork()); + auto r_error = ton::fetch_tl_object(data.clone(), true); + if (r_error.is_ok()) { + auto f = r_error.move_as_ok(); + return TonlibError::LiteServer(f->code_, f->message_); + } + return ton::fetch_result(std::move(data)); + } + (); + VLOG_IF(lite_server, res.is_ok()) + << "got result from liteserver: " << tag << " " << td::Slice(to_string(res.ok())).truncate(1 << 12); + VLOG_IF(lite_server, res.is_error()) << "got error from liteserver: " << tag << " " << res.error(); + promise.set_result(std::move(res)); + }); } private: diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/ExtClientOutbound.cpp b/submodules/ton/tonlib-src/tonlib/tonlib/ExtClientOutbound.cpp index a20a8c59f2..f1746af5d6 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/ExtClientOutbound.cpp +++ b/submodules/ton/tonlib-src/tonlib/tonlib/ExtClientOutbound.cpp @@ -18,6 +18,7 @@ Copyright 2017-2019 Telegram Systems LLP */ #include "ExtClientOutbound.h" +#include "TonlibError.h" #include namespace tonlib { @@ -40,7 +41,7 @@ class ExtClientOutboundImp : public ExtClientOutbound { void on_query_result(td::int64 id, td::Result r_data, td::Promise promise) override { auto it = queries_.find(id); if (it == queries_.end()) { - promise.set_error(td::Status::Error(400, "Unknown query id")); + promise.set_error(TonlibError::Internal("Unknown query id")); } it->second.set_result(std::move(r_data)); queries_.erase(it); @@ -54,7 +55,7 @@ class ExtClientOutboundImp : public ExtClientOutbound { void tear_down() override { for (auto &it : queries_) { - it.second.set_error(td::Status::Error(400, "Query cancelled")); + it.second.set_error(TonlibError::Cancelled()); } queries_.clear(); } diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/GenericAccount.cpp b/submodules/ton/tonlib-src/tonlib/tonlib/GenericAccount.cpp index 08ea33bdc9..9f44ede274 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/GenericAccount.cpp +++ b/submodules/ton/tonlib-src/tonlib/tonlib/GenericAccount.cpp @@ -20,18 +20,19 @@ #include "tonlib/utils.h" #include "block/block-auto.h" namespace tonlib { -td::Ref GenericAccount::get_init_state(td::Ref code, td::Ref data) { +td::Ref GenericAccount::get_init_state(td::Ref code, td::Ref data) noexcept { return vm::CellBuilder() .append_cellslice(binary_bitstring_to_cellslice("b{00110}").move_as_ok()) .store_ref(std::move(code)) .store_ref(std::move(data)) .finalize(); } -block::StdAddress GenericAccount::get_address(ton::WorkchainId workchain_id, const td::Ref& init_state) { +block::StdAddress GenericAccount::get_address(ton::WorkchainId workchain_id, + const td::Ref& init_state) noexcept { return block::StdAddress(workchain_id, init_state->get_hash().bits(), true /*bounce*/); } td::Ref GenericAccount::create_ext_message(const block::StdAddress& address, td::Ref new_state, - td::Ref body) { + td::Ref body) noexcept { block::gen::Message::Record message; /*info*/ { block::gen::CommonMsgInfo::Record_ext_in_msg_info info; diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/GenericAccount.h b/submodules/ton/tonlib-src/tonlib/tonlib/GenericAccount.h index 253274f05e..4a36d78a53 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/GenericAccount.h +++ b/submodules/ton/tonlib-src/tonlib/tonlib/GenericAccount.h @@ -22,9 +22,9 @@ namespace tonlib { class GenericAccount { public: - static td::Ref get_init_state(td::Ref code, td::Ref data); - static block::StdAddress get_address(ton::WorkchainId workchain_id, const td::Ref& init_state); + static td::Ref get_init_state(td::Ref code, td::Ref data) noexcept; + static block::StdAddress get_address(ton::WorkchainId workchain_id, const td::Ref& init_state) noexcept; static td::Ref create_ext_message(const block::StdAddress& address, td::Ref new_state, - td::Ref body); + td::Ref body) noexcept; }; } // namespace tonlib diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/KeyStorage.cpp b/submodules/ton/tonlib-src/tonlib/tonlib/KeyStorage.cpp index 6137c0e347..85aec05263 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/KeyStorage.cpp +++ b/submodules/ton/tonlib-src/tonlib/tonlib/KeyStorage.cpp @@ -22,34 +22,26 @@ #include "tonlib/keys/DecryptedKey.h" #include "tonlib/keys/EncryptedKey.h" +#include "tonlib/TonlibError.h" + #include "td/utils/filesystem.h" #include "td/utils/port/path.h" #include "td/utils/crypto.h" +#include "td/utils/PathView.h" namespace tonlib { +namespace { std::string to_file_name_old(const KeyStorage::Key &key) { return td::buffer_to_hex(key.public_key); } -std::string KeyStorage::to_file_path_old(const Key &key) { - return directory_ + TD_DIR_SLASH + to_file_name_old(key); -} - std::string to_file_name(const KeyStorage::Key &key) { return td::buffer_to_hex(td::sha512(key.secret.as_slice()).substr(0, 32)); } +} // namespace -std::string KeyStorage::to_file_path(const Key &key) { - return directory_ + TD_DIR_SLASH + to_file_name(key); -} -td::Status KeyStorage::set_directory(std::string directory) { - TRY_RESULT(path, td::realpath(directory)); - TRY_RESULT(stat, td::stat(path)); - if (!stat.is_dir_) { - return td::Status::Error("not a directory"); - } - directory_ = std::move(path); - return td::Status::OK(); +void KeyStorage::set_key_value(std::shared_ptr kv) { + kv_ = std::move(kv); } td::Result KeyStorage::save_key(const DecryptedKey &decrypted_key, td::Slice local_password) { @@ -58,17 +50,7 @@ td::Result KeyStorage::save_key(const DecryptedKey &decrypted_k Key res; res.public_key = encrypted_key.public_key.as_octet_string(); res.secret = std::move(encrypted_key.secret); - - auto size = encrypted_key.encrypted_data.size(); - - LOG(ERROR) << "SAVE " << to_file_name(res); - TRY_RESULT(to_file, td::FileFd::open(to_file_path(res), td::FileFd::CreateNew | td::FileFd::Write)); - TRY_RESULT(written, to_file.write(encrypted_key.encrypted_data)); - if (written != static_cast(size)) { - return td::Status::Error(PSLICE() << "Failed to write file: written " << written << " bytes instead of " << size); - } - to_file.close(); - + TRY_STATUS_PREFIX(kv_->set(to_file_name(res), encrypted_key.encrypted_data), TonlibError::Internal()); return std::move(res); } @@ -83,19 +65,22 @@ td::Result KeyStorage::create_new_key(td::Slice local_password, } td::Result KeyStorage::export_decrypted_key(InputKey input_key) { - auto r_encrypted_data = td::read_file_secure(to_file_path(input_key.key)); + auto r_encrypted_data = kv_->get(to_file_name(input_key.key)); if (r_encrypted_data.is_error()) { - r_encrypted_data = td::read_file_secure(to_file_path_old(input_key.key)); + r_encrypted_data = kv_->get(to_file_name_old(input_key.key)); if (r_encrypted_data.is_ok()) { - LOG(WARNING) << "Restore private from deprecated location " << to_file_path_old(input_key.key) << " --> " - << to_file_path(input_key.key); - td::rename(to_file_path_old(input_key.key), to_file_path(input_key.key)).ignore(); + LOG(WARNING) << "Restore private from deprecated location " << to_file_name_old(input_key.key) << " --> " + << to_file_name(input_key.key); + TRY_STATUS_PREFIX(kv_->set(to_file_name(input_key.key), r_encrypted_data.ok()), TonlibError::Internal()); + kv_->erase(to_file_name_old(input_key.key)).ignore(); } } - TRY_RESULT(encrypted_data, std::move(r_encrypted_data)); + TRY_RESULT_PREFIX(encrypted_data, std::move(r_encrypted_data), TonlibError::KeyUnknown()); EncryptedKey encrypted_key{std::move(encrypted_data), td::Ed25519::PublicKey(std::move(input_key.key.public_key)), std::move(input_key.key.secret)}; - return encrypted_key.decrypt(std::move(input_key.local_password)); + TRY_RESULT_PREFIX(decrypted_key, encrypted_key.decrypt(std::move(input_key.local_password)), + TonlibError::KeyDecrypt()); + return decrypted_key; } td::Result KeyStorage::export_key(InputKey input_key) { @@ -113,7 +98,26 @@ td::Result KeyStorage::load_private_key(InputKey input_k } td::Status KeyStorage::delete_key(const Key &key) { - return td::unlink(to_file_path(key)); + LOG(WARNING) << "Delete private key stored at " << to_file_name(key); + return kv_->erase(to_file_name(key)); +} + +td::Status KeyStorage::delete_all_keys() { + std::vector keys; + kv_->foreach_key([&](td::Slice key) { + if (td::PathView(key).extension().empty()) { + keys.push_back(key.str()); + } + }); + td::Status status; + for (auto key : keys) { + LOG(WARNING) << "Delete private key stored at " << key; + auto err = kv_->erase(key); + if (err.is_error() && status.is_ok()) { + status = std::move(err); + } + } + return status; } td::Result KeyStorage::import_key(td::Slice local_password, td::Slice mnemonic_password, @@ -121,16 +125,16 @@ td::Result KeyStorage::import_key(td::Slice local_password, td: TRY_RESULT(mnemonic, Mnemonic::create(std::move(exported_key.mnemonic_words), td::SecureString(mnemonic_password))); if (!mnemonic.is_basic_seed()) { if (mnemonic_password.empty() && mnemonic.is_password_seed()) { - return td::Status::Error("Mnemonic password is expected"); + return TonlibError::NeedMnemonicPassword(); } - return td::Status::Error("Invalid mnemonic words or password (invalid checksum)"); + return TonlibError::InvalidMnemonic(); } return save_key(DecryptedKey(std::move(mnemonic)), local_password); } td::Result KeyStorage::export_pem_key(InputKey input_key, td::Slice key_password) { TRY_RESULT(decrypted_key, export_decrypted_key(std::move(input_key))); - TRY_RESULT(pem, decrypted_key.private_key.as_pem(key_password)); + TRY_RESULT_PREFIX(pem, decrypted_key.private_key.as_pem(key_password), TonlibError::Internal()); return ExportedPemKey{std::move(pem)}; } @@ -140,13 +144,15 @@ td::Result KeyStorage::change_local_password(InputKey input_key Key res; res.public_key = std::move(input_key.key.public_key); res.secret = std::move(new_secret); - TRY_STATUS(td::copy_file(to_file_path(input_key.key), to_file_path(res))); + TRY_RESULT_PREFIX(value, kv_->get(to_file_name(input_key.key)), TonlibError::KeyUnknown()); + TRY_STATUS_PREFIX(kv_->add(to_file_name(res), value), TonlibError::Internal()); return std::move(res); } td::Result KeyStorage::import_pem_key(td::Slice local_password, td::Slice key_password, ExportedPemKey exported_key) { - TRY_RESULT(key, td::Ed25519::PrivateKey::from_pem(exported_key.pem, key_password)); + TRY_RESULT_PREFIX(key, td::Ed25519::PrivateKey::from_pem(exported_key.pem, key_password), + TonlibError::InvalidPemKey()); return save_key(DecryptedKey({}, std::move(key)), local_password); } @@ -162,7 +168,7 @@ td::Result KeyStorage::import_encrypted_key(td::Slice local_pas ExportedEncryptedKey exported_key) { EncryptedKey encrypted_key{std::move(exported_key.data), td::Ed25519::PublicKey(td::SecureString()), td::SecureString(dummy_secret)}; - TRY_RESULT(decrypted_key, encrypted_key.decrypt(key_password, false)); + TRY_RESULT_PREFIX(decrypted_key, encrypted_key.decrypt(key_password, false), TonlibError::KeyDecrypt()); return save_key(std::move(decrypted_key), local_password); } diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/KeyStorage.h b/submodules/ton/tonlib-src/tonlib/tonlib/KeyStorage.h index f7982805ef..1e37082885 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/KeyStorage.h +++ b/submodules/ton/tonlib-src/tonlib/tonlib/KeyStorage.h @@ -21,6 +21,8 @@ #include "td/utils/Status.h" #include "td/utils/SharedSlice.h" +#include "KeyValue.h" + #include namespace tonlib { @@ -48,7 +50,7 @@ class KeyStorage { td::SecureString private_key; }; - td::Status set_directory(std::string directory); + void set_key_value(std::shared_ptr kv); td::Result create_new_key(td::Slice local_password, td::Slice key_password, td::Slice entropy); @@ -58,6 +60,7 @@ class KeyStorage { td::Result change_local_password(InputKey input_key, td::Slice new_local_password); td::Status delete_key(const Key& key); + td::Status delete_all_keys(); td::Result import_key(td::Slice local_password, td::Slice mnemonic_password, ExportedKey exported_key); td::Result import_pem_key(td::Slice local_password, td::Slice key_password, ExportedPemKey exported_key); @@ -67,12 +70,9 @@ class KeyStorage { td::Result load_private_key(InputKey input_key); private: - std::string directory_; + std::shared_ptr kv_; td::Result save_key(const DecryptedKey& mnemonic, td::Slice local_password); td::Result export_decrypted_key(InputKey input_key); - - std::string to_file_path(const Key& key); - std::string to_file_path_old(const Key& key); }; } // namespace tonlib diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/KeyValue.cpp b/submodules/ton/tonlib-src/tonlib/tonlib/KeyValue.cpp new file mode 100644 index 0000000000..d71744f04d --- /dev/null +++ b/submodules/ton/tonlib-src/tonlib/tonlib/KeyValue.cpp @@ -0,0 +1,124 @@ +#include "KeyValue.h" + +#include "td/utils/filesystem.h" +#include "td/utils/port/path.h" + +#include +#include + +namespace tonlib { +namespace detail { +class KeyValueDir : public KeyValue { + public: + static td::Result> create(td::CSlice directory) { + TRY_RESULT(path, td::realpath(directory)); + TRY_RESULT(stat, td::stat(path)); + if (!stat.is_dir_) { + return td::Status::Error("not a directory"); + } + return td::make_unique(path); + } + + KeyValueDir(std::string directory) : directory_(std::move(directory)) { + } + + td::Status add(td::Slice key, td::Slice value) override { + auto path = to_file_path(key.str()); + if (td::stat(path).is_ok()) { + return td::Status::Error(PSLICE() << "File " << path << "already exists"); + } + return td::atomic_write_file(path, value); + } + + td::Status set(td::Slice key, td::Slice value) override { + return td::atomic_write_file(to_file_path(key.str()), value); + } + + td::Result get(td::Slice key) override { + return td::read_file_secure(to_file_path(key.str())); + } + + td::Status erase(td::Slice key) override { + return td::unlink(key.str()); + } + + void foreach_key(std::function f) override { + int cnt = 0; + td::WalkPath::run(directory_, [&](td::Slice path, td::WalkPath::Type type) { + cnt++; + if (type == td::WalkPath::Type::EnterDir) { + if (cnt != 1) { + return td::WalkPath::Action::SkipDir; + } + } else if (type == td::WalkPath::Type::NotDir) { + f(path); + } + + return td::WalkPath::Action::Continue; + }).ignore(); + } + + private: + std::string directory_; + + std::string to_file_path(std::string key) { + return directory_ + TD_DIR_SLASH + key; + } +}; + +class KeyValueInmemory : public KeyValue { + public: + td::Status add(td::Slice key, td::Slice value) override { + auto res = map_.insert(std::make_pair(key.str(), td::SecureString(value))); + if (!res.second) { + return td::Status::Error(PSLICE() << "Add failed: value with key=`" << key << "` already exists"); + } + return td::Status::OK(); + } + + td::Status set(td::Slice key, td::Slice value) override { + map_[key.str()] = td::SecureString(value); + return td::Status::OK(); + } + td::Result get(td::Slice key) override { + auto it = map_.find(key); + if (it == map_.end()) { + return td::Status::Error("Unknown key"); + } + return it->second.copy(); + } + static td::Result> create() { + return td::make_unique(); + } + td::Status erase(td::Slice key) override { + auto it = map_.find(key); + if (it == map_.end()) { + return td::Status::Error("Unknown key"); + } + map_.erase(it); + return td::Status::OK(); + } + void foreach_key(std::function f) override { + for (auto &it : map_) { + f(it.first); + } + } + + private: + class Cmp : public std::less<> { + public: + using is_transparent = void; + }; + std::map map_; +}; +} // namespace detail + +td::Result> KeyValue::create_dir(td::CSlice dir) { + TRY_RESULT(res, detail::KeyValueDir::create(dir.str())); + return std::move(res); +} +td::Result> KeyValue::create_inmemory() { + TRY_RESULT(res, detail::KeyValueInmemory::create()); + return std::move(res); +} +} // namespace tonlib diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/KeyValue.h b/submodules/ton/tonlib-src/tonlib/tonlib/KeyValue.h new file mode 100644 index 0000000000..75b3df9c79 --- /dev/null +++ b/submodules/ton/tonlib-src/tonlib/tonlib/KeyValue.h @@ -0,0 +1,19 @@ +#pragma once +#include "td/utils/SharedSlice.h" +#include "td/utils/Slice.h" +#include "td/utils/Status.h" + +namespace tonlib { +class KeyValue { + public: + virtual ~KeyValue() = default; + virtual td::Status add(td::Slice key, td::Slice value) = 0; + virtual td::Status set(td::Slice key, td::Slice value) = 0; + virtual td::Status erase(td::Slice key) = 0; + virtual td::Result get(td::Slice key) = 0; + virtual void foreach_key(std::function f) = 0; + + static td::Result> create_dir(td::CSlice dir); + static td::Result> create_inmemory(); +}; +} // namespace tonlib diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/LastBlock.cpp b/submodules/ton/tonlib-src/tonlib/tonlib/LastBlock.cpp index 7c4cda5dd3..05f078e086 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/LastBlock.cpp +++ b/submodules/ton/tonlib-src/tonlib/tonlib/LastBlock.cpp @@ -18,12 +18,18 @@ */ #include "tonlib/LastBlock.h" +#include "tonlib/utils.h" + #include "ton/lite-tl.hpp" #include "lite-client/lite-client-common.h" namespace tonlib { +// init_state <-> last_key_block +// state.valitated_init_state +// last_key_block -> +// td::StringBuilder& operator<<(td::StringBuilder& sb, const LastBlockState& state) { return sb << td::tag("last_block", state.last_block_id.to_str()) << td::tag("last_key_block", state.last_key_block_id.to_str()) << td::tag("utime", state.utime); @@ -32,9 +38,10 @@ td::StringBuilder& operator<<(td::StringBuilder& sb, const LastBlockState& state LastBlock::LastBlock(ExtClientRef client, LastBlockState state, Config config, td::unique_ptr callback) : state_(std::move(state)), config_(std::move(config)), callback_(std::move(callback)) { client_.set_client(client); - if (!config_.init_block_id.is_valid()) { - check_init_block_state_ = QueryState::Done; - } + state_.last_block_id = state_.last_key_block_id; + + VLOG(last_block) << "check_init_block: skip - FIXME before release"; + check_init_block_state_ = QueryState::Done; } void LastBlock::get_last_block(td::Promise promise) { @@ -42,9 +49,13 @@ void LastBlock::get_last_block(td::Promise promise) { promise.set_error(fatal_error_.clone()); return; } + if (promises_.empty() && get_last_block_state_ == QueryState::Done) { + VLOG(last_block) << "sync: start"; + VLOG(last_block) << "get_last_block: reset"; get_last_block_state_ = QueryState::Empty; } + promises_.push_back(std::move(promise)); sync_loop(); } @@ -54,36 +65,43 @@ void LastBlock::sync_loop() { return; } - update_zero_state(state_.zero_state_id); + update_zero_state(state_.zero_state_id, "cache"); update_zero_state(ton::ZeroStateIdExt(config_.zero_state_id.id.workchain, config_.zero_state_id.root_hash, - config_.zero_state_id.file_hash)); + config_.zero_state_id.file_hash), + "config"); if (get_mc_info_state_ == QueryState::Empty) { + VLOG(last_block) << "get_masterchain_info: start"; get_mc_info_state_ = QueryState::Active; client_.send_query(ton::lite_api::liteServer_getMasterchainInfo(), [this](auto r_info) { this->on_masterchain_info(std::move(r_info)); }); } - if (get_last_block_state_ == QueryState::Empty) { - get_last_block_state_ = QueryState::Active; - total_sync_ = td::Timer(); - validate_ = td::Timer(true); - queries_ = 0; - LOG(INFO) << "Begin last block synchronization " << state_; - do_get_last_block(); + if (check_init_block_state_ == QueryState::Empty) { + if (!config_.init_block_id.is_valid()) { + check_init_block_state_ = QueryState::Done; + VLOG(last_block) << "check_init_block: skip - no init_block in config"; + } else if (config_.init_block_id == state_.init_block_id) { + check_init_block_state_ = QueryState::Done; + VLOG(last_block) << "check_init_block: skip - was checked before"; + } else { + check_init_block_state_ = QueryState::Active; + check_init_block_stats_.start(); + if (state_.last_block_id.id.seqno >= config_.init_block_id.id.seqno) { + VLOG(last_block) << "check_init_block: start - init_block -> last_block"; + do_check_init_block(config_.init_block_id, state_.last_key_block_id); + } else { + VLOG(last_block) << "check_init_block: start - last_block -> init_block"; + do_check_init_block(state_.last_key_block_id, config_.init_block_id); + } + } } - if (check_init_block_state_ == QueryState::Empty) { - if (state_.last_block_id.id.seqno >= config_.init_block_id.id.seqno) { - check_init_block_state_ = QueryState::Active; - // validate - //total_sync_ = td::Timer(); - //validate_ = td::Timer(true); - //queries_ = 0; - LOG(INFO) << "Begin last block synchronization (check init_block)" << state_; - do_check_init_block(state_.last_key_block_id); - } else { - } + if (get_last_block_state_ == QueryState::Empty && check_init_block_state_ == QueryState::Done) { + VLOG(last_block) << "get_last_block: start"; + get_last_block_stats_.start(); + get_last_block_state_ = QueryState::Active; + do_get_last_block(); } if (get_mc_info_state_ == QueryState::Done && get_last_block_state_ == QueryState::Done && @@ -94,7 +112,8 @@ void LastBlock::sync_loop() { void LastBlock::do_get_last_block() { //liteServer.getBlockProof mode:# known_block:tonNode.blockIdExt target_block:mode.0?tonNode.blockIdExt = liteServer.PartialBlockProof; - queries_++; + VLOG(last_block) << "get_last_block: continue " << state_.last_key_block_id.to_str() << " -> ?"; + get_last_block_stats_.queries_++; client_.send_query( ton::lite_api::liteServer_getBlockProof(0, create_tl_lite_block_id(state_.last_key_block_id), nullptr), [this, from = state_.last_key_block_id](auto r_block_proof) { @@ -102,64 +121,69 @@ void LastBlock::do_get_last_block() { }); } -void LastBlock::do_check_init_block(ton::BlockIdExt from) { +void LastBlock::do_check_init_block(ton::BlockIdExt from, ton::BlockIdExt to) { + VLOG(last_block) << "check_init_block: continue " << from.to_str() << " -> " << to.to_str(); //liteServer.getBlockProof mode:# known_block:tonNode.blockIdExt target_block:mode.0?tonNode.blockIdExt = liteServer.PartialBlockProof; - //queries_++; - client_.send_query(ton::lite_api::liteServer_getBlockProof(1, create_tl_lite_block_id(from), - create_tl_lite_block_id(config_.init_block_id)), - [this, from = state_.last_key_block_id](auto r_block_proof) { - this->on_init_block_proof(from, std::move(r_block_proof)); - }); + check_init_block_stats_.queries_++; + client_.send_query( + ton::lite_api::liteServer_getBlockProof(1, create_tl_lite_block_id(from), create_tl_lite_block_id(to)), + [this, from, to](auto r_block_proof) { this->on_init_block_proof(from, to, std::move(r_block_proof)); }); } td::Result> LastBlock::process_block_proof( ton::BlockIdExt from, td::Result> r_block_proof) { - TRY_RESULT(block_proof, std::move(r_block_proof)); - LOG(DEBUG) << "Got proof FROM\n" << to_string(block_proof->from_) << "TO\n" << to_string(block_proof->to_); + TRY_RESULT(block_proof, std::move(r_block_proof)); //TODO: it is fatal? + TRY_RESULT_PREFIX(chain, TRY_VM(process_block_proof(from, std::move(block_proof))), + TonlibError::ValidateBlockProof()); + return chain; +} + +td::Result> LastBlock::process_block_proof( + ton::BlockIdExt from, ton::ton_api::object_ptr block_proof) { + VLOG(last_block) << "Got proof FROM\n" << to_string(block_proof->from_) << "TO\n" << to_string(block_proof->to_); TRY_RESULT(chain, liteclient::deserialize_proof_chain(std::move(block_proof))); if (chain->from != from) { return td::Status::Error(PSLICE() << "block proof chain starts from block " << chain->from.to_str() << ", not from requested block " << from.to_str()); } TRY_STATUS(chain->validate()); + return chain; +} + +void LastBlock::update_state(block::BlockProofChain& chain) { + // Update state_ bool is_changed = false; - is_changed |= update_mc_last_block(chain->to); - if (chain->has_key_block) { - is_changed |= update_mc_last_key_block(chain->key_blkid); + is_changed |= update_mc_last_block(chain.to); + if (chain.has_key_block) { + is_changed |= update_mc_last_key_block(chain.key_blkid); } - if (chain->has_utime) { - update_utime(chain->last_utime); + if (chain.has_utime) { + update_utime(chain.last_utime); } if (is_changed) { callback_->on_state_changed(state_); } - return std::move(chain); } void LastBlock::on_block_proof( ton::BlockIdExt from, td::Result> r_block_proof) { - validate_.resume(); + get_last_block_stats_.validate_.resume(); auto r_chain = process_block_proof(from, std::move(r_block_proof)); - validate_.pause(); - bool is_ready; + get_last_block_stats_.validate_.pause(); if (r_chain.is_error()) { - LOG(WARNING) << "Error during last block synchronization " << r_chain.error(); - if (config_.init_block_id.is_valid()) { - if (state_.last_key_block_id.id.seqno < config_.init_block_id.id.seqno) { - on_sync_error(td::Status::Error(PSLICE() << "Sync failed and we can't validate config.init_block: " - << r_chain.move_as_error())); - } - } - is_ready = true; - } else { - is_ready = r_chain.ok()->complete; + get_last_block_state_ = QueryState::Empty; + VLOG(last_block) << "get_last_block: error " << r_chain.error(); + on_sync_error(r_chain.move_as_error_suffix("(during last block synchronization)")); + return; } - if (is_ready) { - LOG(INFO) << "End last block synchronization " << state_ << "\n" - << " net queries: " << queries_ << "\n" - << " total: " << total_sync_ << " validation: " << validate_; + + auto chain = r_chain.move_as_ok(); + CHECK(chain); + update_state(*chain); + if (chain->complete) { + VLOG(last_block) << "get_last_block: done\n" << get_last_block_stats_; get_last_block_state_ = QueryState::Done; sync_loop(); } else { @@ -168,26 +192,26 @@ void LastBlock::on_block_proof( } void LastBlock::on_init_block_proof( - ton::BlockIdExt from, + ton::BlockIdExt from, ton::BlockIdExt to, td::Result> r_block_proof) { - validate_.resume(); + check_init_block_stats_.validate_.resume(); auto r_chain = process_block_proof(from, std::move(r_block_proof)); - validate_.pause(); + check_init_block_stats_.validate_.pause(); if (r_chain.is_error()) { check_init_block_state_ = QueryState::Empty; - on_sync_error( - td::Status::Error(PSLICE() << "Error during last block synchronization (check init_block)" << r_chain.error())); + VLOG(last_block) << "check_init_block: error " << r_chain.error(); + on_sync_error(r_chain.move_as_error_suffix("(during check init block)")); return; } auto chain = r_chain.move_as_ok(); + CHECK(chain); + update_state(*chain); if (chain->complete) { - LOG(INFO) << "End last block synchronization " << state_ << "\n" - << " net queries: " << queries_ << "\n" - << " total: " << total_sync_ << " validation: " << validate_; - get_last_block_state_ = QueryState::Done; + VLOG(last_block) << "check_init_block: done\n" << check_init_block_stats_; + check_init_block_state_ = QueryState::Done; sync_loop(); } else { - do_check_init_block(chain->to); + do_check_init_block(chain->to, to); } } @@ -195,28 +219,30 @@ void LastBlock::on_masterchain_info( td::Result> r_info) { if (r_info.is_ok()) { auto info = r_info.move_as_ok(); - update_zero_state(create_zero_state_id(info->init_)); - update_mc_last_block(create_block_id(info->last_)); + update_zero_state(create_zero_state_id(info->init_), "masterchain info"); + // last block is not validated! Do not update it get_mc_info_state_ = QueryState::Done; + VLOG(last_block) << "get_masterchain_info: done"; } else { get_mc_info_state_ = QueryState::Empty; + VLOG(last_block) << "get_masterchain_info: error " << r_info.error(); LOG(WARNING) << "Failed liteServer_getMasterchainInfo " << r_info.error(); on_sync_error(r_info.move_as_error()); } sync_loop(); } -void LastBlock::update_zero_state(ton::ZeroStateIdExt zero_state_id) { +void LastBlock::update_zero_state(ton::ZeroStateIdExt zero_state_id, td::Slice source) { if (has_fatal_error()) { return; } if (!zero_state_id.is_valid()) { - LOG(ERROR) << "Ignore invalid zero state update"; + LOG(ERROR) << "Ignore invalid zero state update from " << source; return; } if (!state_.zero_state_id.is_valid()) { - LOG(INFO) << "Init zerostate: " << zero_state_id.to_str(); + LOG(INFO) << "Init zerostate from " << source << ": " << zero_state_id.to_str(); state_.zero_state_id = std::move(zero_state_id); return; } @@ -225,8 +251,9 @@ void LastBlock::update_zero_state(ton::ZeroStateIdExt zero_state_id) { return; } - on_fatal_error(td::Status::Error(PSLICE() << "Masterchain zerostate mismatch: expected: " - << state_.zero_state_id.to_str() << ", found " << zero_state_id.to_str())); + on_fatal_error(TonlibError::ValidateZeroState(PSLICE() << "Masterchain zerostate mismatch: expected: " + << state_.zero_state_id.to_str() << ", found " + << zero_state_id.to_str() << " from " << source)); } bool LastBlock::update_mc_last_block(ton::BlockIdExt mc_block_id) { @@ -256,6 +283,9 @@ bool LastBlock::update_mc_last_key_block(ton::BlockIdExt mc_key_block_id) { if (!state_.last_key_block_id.is_valid() || state_.last_key_block_id.id.seqno < mc_key_block_id.id.seqno) { state_.last_key_block_id = mc_key_block_id; LOG(INFO) << "Update masterchain key block id: " << state_.last_key_block_id.to_str(); + //LOG(ERROR) << td::int64(state_.last_key_block_id.id.shard) << " " + //<< td::base64_encode(state_.last_key_block_id.file_hash.as_slice()) << " " + //<< td::base64_encode(state_.last_key_block_id.root_hash.as_slice()); return true; } return false; @@ -268,6 +298,7 @@ void LastBlock::update_utime(td::int64 utime) { } void LastBlock::on_sync_ok() { + VLOG(last_block) << "sync: ok " << state_; for (auto& promise : promises_) { auto state = state_; promise.set_value(std::move(state)); @@ -275,12 +306,14 @@ void LastBlock::on_sync_ok() { promises_.clear(); } void LastBlock::on_sync_error(td::Status status) { + VLOG(last_block) << "sync: error " << status; for (auto& promise : promises_) { promise.set_error(status.clone()); } promises_.clear(); } void LastBlock::on_fatal_error(td::Status status) { + VLOG(last_block) << "sync: fatal error " << status; fatal_error_ = std::move(status); on_sync_error(fatal_error_.clone()); } diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/LastBlock.h b/submodules/ton/tonlib-src/tonlib/tonlib/LastBlock.h index 2add3bcfb9..bb2a62ed4e 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/LastBlock.h +++ b/submodules/ton/tonlib-src/tonlib/tonlib/LastBlock.h @@ -22,6 +22,8 @@ #include "tonlib/Config.h" #include "tonlib/ExtClient.h" +#include "td/utils/tl_helpers.h" + namespace block { struct BlockProofChain; } @@ -89,25 +91,44 @@ struct LastBlockState { ton::BlockIdExt last_key_block_id; ton::BlockIdExt last_block_id; td::int64 utime{0}; + ton::BlockIdExt init_block_id; + + static constexpr td::int32 magic = 0xa7f171a4; + enum Version { None = 0, Magic, InitBlock, Next }; + static constexpr td::int32 version = Version::Next - 1; template void store(StorerT &storer) const { using td::store; using tonlib::store; + store(magic, storer); + store(version, storer); + store(zero_state_id, storer); store(last_key_block_id, storer); store(last_block_id, storer); store(utime, storer); + store(init_block_id, storer); } template void parse(ParserT &parser) { using td::parse; using tonlib::parse; + td::int32 version = 0; + if (parser.can_prefetch_int() && parser.prefetch_int_unsafe() == magic) { + td::int32 magic; + parse(magic, parser); + parse(version, parser); + } + parse(zero_state_id, parser); parse(last_key_block_id, parser); parse(last_block_id, parser); parse(utime, parser); + if (version >= InitBlock) { + parse(init_block_id, parser); + } } }; @@ -132,20 +153,36 @@ class LastBlock : public td::actor::Actor { td::Status fatal_error_; enum class QueryState { Empty, Active, Done }; - QueryState get_mc_info_state_{QueryState::Empty}; - QueryState get_last_block_state_{QueryState::Empty}; - QueryState check_init_block_state_{QueryState::Empty}; + QueryState get_mc_info_state_{QueryState::Empty}; // just to check zero state + QueryState check_init_block_state_{QueryState::Empty}; // init_block <---> last_key_block (from older to newer) + QueryState get_last_block_state_{QueryState::Empty}; // last_key_block_id --> ? // stats - td::Timer total_sync_; - td::Timer validate_; - td::uint32 queries_; + struct Stats { + td::Timer total_sync_; + td::Timer validate_; + td::uint32 queries_; + + void start() { + total_sync_ = td::Timer(); + validate_ = td::Timer(true); + queries_ = 0; + } + + friend td::StringBuilder &operator<<(td::StringBuilder &sb, const Stats &stats) { + return sb << " net queries: " << stats.queries_ << "\n" + << " total: " << stats.total_sync_ << " validation: " << stats.validate_; + } + }; + + Stats check_init_block_stats_; + Stats get_last_block_stats_; std::vector> promises_; - void do_check_init_block(ton::BlockIdExt from); + void do_check_init_block(ton::BlockIdExt from, ton::BlockIdExt to); void on_init_block_proof( - ton::BlockIdExt from, + ton::BlockIdExt from, ton::BlockIdExt to, td::Result> r_block_proof); void on_masterchain_info(td::Result> r_info); void do_get_last_block(); @@ -155,7 +192,11 @@ class LastBlock : public td::actor::Actor { ton::BlockIdExt from, td::Result> r_block_proof); - void update_zero_state(ton::ZeroStateIdExt zero_state_id); + td::Result> process_block_proof( + ton::BlockIdExt from, ton::ton_api::object_ptr block_proof); + + void update_state(block::BlockProofChain &chain); + void update_zero_state(ton::ZeroStateIdExt zero_state_id, td::Slice source); bool update_mc_last_block(ton::BlockIdExt mc_block_id); bool update_mc_last_key_block(ton::BlockIdExt mc_key_block_id); diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/LastBlockStorage.cpp b/submodules/ton/tonlib-src/tonlib/tonlib/LastBlockStorage.cpp index 684b2c056c..dff4265d62 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/LastBlockStorage.cpp +++ b/submodules/ton/tonlib-src/tonlib/tonlib/LastBlockStorage.cpp @@ -18,6 +18,8 @@ */ #include "LastBlockStorage.h" +#include "tonlib/utils.h" + #include "td/utils/as.h" #include "td/utils/filesystem.h" #include "td/utils/port/path.h" @@ -25,22 +27,18 @@ namespace tonlib { -td::Status LastBlockStorage::set_directory(std::string directory) { - TRY_RESULT(path, td::realpath(directory)); - TRY_RESULT(stat, td::stat(path)); - if (!stat.is_dir_) { - return td::Status::Error("not a directory"); - } - directory_ = std::move(path); - return td::Status::OK(); +void LastBlockStorage::set_key_value(std::shared_ptr kv) { + kv_ = std::move(kv); } -std::string LastBlockStorage::get_file_name(td::Slice name) { - return directory_ + TD_DIR_SLASH + td::buffer_to_hex(name) + ".blkstate"; +namespace { +std::string get_file_name(td::Slice name) { + return td::buffer_to_hex(name) + ".blkstate"; } +} // namespace td::Result LastBlockStorage::get_state(td::Slice name) { - TRY_RESULT(data, td::read_file(get_file_name(name))); + TRY_RESULT(data, kv_->get(get_file_name(name))); if (data.size() < 8) { return td::Status::Error("too short"); } @@ -53,10 +51,11 @@ td::Result LastBlockStorage::get_state(td::Slice name) { } void LastBlockStorage::save_state(td::Slice name, LastBlockState state) { + VLOG(last_block) << "Save to cache: " << state; auto x = td::serialize(state); std::string y(x.size() + 8, 0); td::MutableSlice(y).substr(8).copy_from(x); td::as(td::MutableSlice(y).data()) = td::crc64(x); - td::atomic_write_file(get_file_name(name), y); + kv_->set(get_file_name(name), y); } } // namespace tonlib diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/LastBlockStorage.h b/submodules/ton/tonlib-src/tonlib/tonlib/LastBlockStorage.h index d8cbd3fcd1..df5dd12c9e 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/LastBlockStorage.h +++ b/submodules/ton/tonlib-src/tonlib/tonlib/LastBlockStorage.h @@ -20,15 +20,16 @@ #include "tonlib/LastBlock.h" +#include "tonlib/KeyValue.h" + namespace tonlib { class LastBlockStorage { public: - td::Status set_directory(std::string directory); + void set_key_value(std::shared_ptr kv); td::Result get_state(td::Slice name); void save_state(td::Slice name, LastBlockState state); private: - std::string directory_; - std::string get_file_name(td::Slice name); + std::shared_ptr kv_; }; } // namespace tonlib diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/Logging.cpp b/submodules/ton/tonlib-src/tonlib/tonlib/Logging.cpp index 043fe0190d..31dc275c00 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/Logging.cpp +++ b/submodules/ton/tonlib-src/tonlib/tonlib/Logging.cpp @@ -17,6 +17,7 @@ Copyright 2017-2019 Telegram Systems LLP */ #include "Logging.h" +#include "utils.h" #include "auto/tl/tonlib_api.h" @@ -36,11 +37,9 @@ static td::FileLog file_log; static td::TsLog ts_log(&file_log); static td::NullLog null_log; -td::int32 VERBOSITY_NAME(abc) = VERBOSITY_NAME(DEBUG); -td::int32 VERBOSITY_NAME(bcd) = VERBOSITY_NAME(DEBUG); #define ADD_TAG(tag) \ { #tag, &VERBOSITY_NAME(tag) } -static const std::map log_tags{ADD_TAG(abc), ADD_TAG(bcd)}; +static const std::map log_tags{ADD_TAG(tonlib_query), ADD_TAG(last_block)}; #undef ADD_TAG td::Status Logging::set_current_stream(tonlib_api::object_ptr stream) { diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/TestGiver.cpp b/submodules/ton/tonlib-src/tonlib/tonlib/TestGiver.cpp index 50c68571ce..b906193d9e 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/TestGiver.cpp +++ b/submodules/ton/tonlib-src/tonlib/tonlib/TestGiver.cpp @@ -22,19 +22,18 @@ #include "td/utils/base64.h" namespace tonlib { -const block::StdAddress& TestGiver::address() { +const block::StdAddress& TestGiver::address() noexcept { static block::StdAddress res = block::StdAddress::parse("kf_8uRo6OBbQ97jCx2EIuKm8Wmt6Vb15-KsQHFLbKSMiYIny").move_as_ok(); return res; } -vm::CellHash TestGiver::get_init_code_hash() { +vm::CellHash TestGiver::get_init_code_hash() noexcept { return vm::CellHash::from_slice(td::base64_decode("wDkZp0yR4xo+9+BnuAPfGVjBzK6FPzqdv2DwRq3z3KE=").move_as_ok()); } td::Ref TestGiver::make_a_gift_message(td::uint32 seqno, td::uint64 gramms, td::Slice message, - const block::StdAddress& dest_address) { - CHECK(message.size() <= 124); + const block::StdAddress& dest_address) noexcept { td::BigInt256 dest_addr; dest_addr.import_bits(dest_address.addr.as_bitslice()); vm::CellBuilder cb; @@ -45,7 +44,9 @@ td::Ref TestGiver::make_a_gift_message(td::uint32 seqno, td::uint64 gr .store_int256(dest_addr, 256); block::tlb::t_Grams.store_integer_value(cb, td::BigInt256(gramms)); - auto message_inner = cb.store_zeroes(9 + 64 + 32 + 1 + 1).store_bytes("\0\0\0\0", 4).store_bytes(message).finalize(); + cb.store_zeroes(9 + 64 + 32 + 1 + 1).store_bytes("\0\0\0\0", 4); + vm::CellString::store(cb, message, 35 * 8).ensure(); + auto message_inner = cb.finalize(); return vm::CellBuilder().store_long(seqno, 32).store_long(1, 8).store_ref(message_inner).finalize(); } } // namespace tonlib diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/TestGiver.h b/submodules/ton/tonlib-src/tonlib/tonlib/TestGiver.h index 6859be8ff0..f8b62599fe 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/TestGiver.h +++ b/submodules/ton/tonlib-src/tonlib/tonlib/TestGiver.h @@ -18,12 +18,14 @@ */ #pragma once #include "block/block.h" +#include "CellString.h" namespace tonlib { class TestGiver { public: - static const block::StdAddress& address(); - static vm::CellHash get_init_code_hash(); + static constexpr unsigned max_message_size = vm::CellString::max_bytes; + static const block::StdAddress& address() noexcept; + static vm::CellHash get_init_code_hash() noexcept; static td::Ref make_a_gift_message(td::uint32 seqno, td::uint64 gramms, td::Slice message, - const block::StdAddress& dest_address); + const block::StdAddress& dest_address) noexcept; }; } // namespace tonlib diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/TestWallet.cpp b/submodules/ton/tonlib-src/tonlib/tonlib/TestWallet.cpp index 022eaca9db..7c3b6f952f 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/TestWallet.cpp +++ b/submodules/ton/tonlib-src/tonlib/tonlib/TestWallet.cpp @@ -24,13 +24,13 @@ #include "td/utils/base64.h" namespace tonlib { -td::Ref TestWallet::get_init_state(const td::Ed25519::PublicKey& public_key) { +td::Ref TestWallet::get_init_state(const td::Ed25519::PublicKey& public_key) noexcept { auto code = get_init_code(); auto data = get_init_data(public_key); return GenericAccount::get_init_state(std::move(code), std::move(data)); } -td::Ref TestWallet::get_init_message(const td::Ed25519::PrivateKey& private_key) { +td::Ref TestWallet::get_init_message(const td::Ed25519::PrivateKey& private_key) noexcept { std::string seq_no(4, 0); auto signature = private_key.sign(vm::CellBuilder().store_bytes(seq_no).finalize()->get_hash().as_slice()).move_as_ok(); @@ -39,8 +39,7 @@ td::Ref TestWallet::get_init_message(const td::Ed25519::PrivateKey& pr td::Ref TestWallet::make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 seqno, td::int64 gramms, td::Slice message, - const block::StdAddress& dest_address) { - CHECK(message.size() <= 124); + const block::StdAddress& dest_address) noexcept { td::BigInt256 dest_addr; dest_addr.import_bits(dest_address.addr.as_bitslice()); vm::CellBuilder cb; @@ -49,16 +48,22 @@ td::Ref TestWallet::make_a_gift_message(const td::Ed25519::PrivateKey& .append_cellslice(binary_bitstring_to_cellslice("b{000100}").move_as_ok()) .store_long(dest_address.workchain, 8) .store_int256(dest_addr, 256); - block::tlb::t_Grams.store_integer_value(cb, td::BigInt256(gramms)); - auto message_inner = cb.store_zeroes(9 + 64 + 32 + 1 + 1).store_bytes("\0\0\0\0", 4).store_bytes(message).finalize(); td::int8 send_mode = 3; + if (gramms == -1) { + gramms = 0; + send_mode += 128; + } + block::tlb::t_Grams.store_integer_value(cb, td::BigInt256(gramms)); + cb.store_zeroes(9 + 64 + 32 + 1 + 1).store_bytes("\0\0\0\0", 4); + vm::CellString::store(cb, message, 35 * 8).ensure(); + auto message_inner = cb.finalize(); auto message_outer = vm::CellBuilder().store_long(seqno, 32).store_long(send_mode, 8).store_ref(message_inner).finalize(); auto signature = private_key.sign(message_outer->get_hash().as_slice()).move_as_ok(); return vm::CellBuilder().store_bytes(signature).append_cellslice(vm::load_cell_slice(message_outer)).finalize(); } -td::Ref TestWallet::get_init_code() { +td::Ref TestWallet::get_init_code() noexcept { static auto res = [] { auto serialized_code = td::base64_decode( "te6ccgEEAQEAAAAAUwAAov8AIN0gggFMl7qXMO1E0NcLH+Ck8mCBAgDXGCDXCx/tRNDTH9P/" @@ -69,11 +74,11 @@ td::Ref TestWallet::get_init_code() { return res; } -vm::CellHash TestWallet::get_init_code_hash() { +vm::CellHash TestWallet::get_init_code_hash() noexcept { return get_init_code()->get_hash(); } -td::Ref TestWallet::get_init_data(const td::Ed25519::PublicKey& public_key) { +td::Ref TestWallet::get_init_data(const td::Ed25519::PublicKey& public_key) noexcept { return vm::CellBuilder().store_long(0, 32).store_bytes(public_key.as_octet_string()).finalize(); } } // namespace tonlib diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/TestWallet.h b/submodules/ton/tonlib-src/tonlib/tonlib/TestWallet.h index 921e3b3afe..ef726b552d 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/TestWallet.h +++ b/submodules/ton/tonlib-src/tonlib/tonlib/TestWallet.h @@ -21,18 +21,20 @@ #include "vm/cells.h" #include "Ed25519.h" #include "block/block.h" +#include "CellString.h" namespace tonlib { class TestWallet { public: - static td::Ref get_init_state(const td::Ed25519::PublicKey& public_key); - static td::Ref get_init_message(const td::Ed25519::PrivateKey& private_key); + static constexpr unsigned max_message_size = vm::CellString::max_bytes; + static td::Ref get_init_state(const td::Ed25519::PublicKey& public_key) noexcept; + static td::Ref get_init_message(const td::Ed25519::PrivateKey& private_key) noexcept; static td::Ref make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 seqno, td::int64 gramms, td::Slice message, - const block::StdAddress& dest_address); + const block::StdAddress& dest_address) noexcept; - static td::Ref get_init_code(); - static vm::CellHash get_init_code_hash(); - static td::Ref get_init_data(const td::Ed25519::PublicKey& public_key); + static td::Ref get_init_code() noexcept; + static vm::CellHash get_init_code_hash() noexcept; + static td::Ref get_init_data(const td::Ed25519::PublicKey& public_key) noexcept; }; } // namespace tonlib diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/TonlibClient.cpp b/submodules/ton/tonlib-src/tonlib/tonlib/TonlibClient.cpp index d0a9cba7d9..fb046d26df 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/TonlibClient.cpp +++ b/submodules/ton/tonlib-src/tonlib/tonlib/TonlibClient.cpp @@ -29,6 +29,8 @@ #include "tonlib/utils.h" #include "tonlib/keys/Mnemonic.h" +#include "tonlib/TonlibError.h" + #include "auto/tl/tonlib_api.hpp" #include "block/block-auto.h" #include "block/check-proof.h" @@ -45,17 +47,6 @@ namespace tonlib { -template -auto try_f(F&& f) noexcept -> decltype(f()) { - try { - return f(); - } catch (vm::VmError error) { - return td::Status::Error(PSLICE() << "Got a vm exception: " << error.get_msg()); - } -} - -#define TRY_VM(f) try_f([&] { return f; }) - tonlib_api::object_ptr status_to_tonlib_api(const td::Status& status) { return tonlib_api::make_object(status.code(), status.message().str()); } @@ -73,6 +64,7 @@ struct RawAccountState { td::int64 balance = -1; td::Ref code; td::Ref data; + std::string frozen_hash; block::AccountState::Info info; }; @@ -96,8 +88,12 @@ td::Result to_balance(td::Ref balance_ref) { class GetTransactionHistory : public td::actor::Actor { public: GetTransactionHistory(ExtClientRef ext_client_ref, block::StdAddress address, ton::LogicalTime lt, ton::Bits256 hash, - td::Promise promise) - : address_(std::move(address)), lt_(std::move(lt)), hash_(std::move(hash)), promise_(std::move(promise)) { + td::actor::ActorShared<> parent, td::Promise promise) + : address_(std::move(address)) + , lt_(std::move(lt)) + , hash_(std::move(hash)) + , parent_(std::move(parent)) + , promise_(std::move(promise)) { client_.set_client(ext_client_ref); } @@ -107,6 +103,7 @@ class GetTransactionHistory : public td::actor::Actor { ton::Bits256 hash_; ExtClient client_; td::int32 count_{10}; + td::actor::ActorShared<> parent_; td::Promise promise_; void check(td::Status status) { @@ -117,7 +114,31 @@ class GetTransactionHistory : public td::actor::Actor { } } - td::Status do_with_transactions(std::vector blkids, td::BufferSlice transactions) { + void with_transactions( + td::Result> r_transactions) { + check(do_with_transactions(std::move(r_transactions))); + stop(); + } + + td::Status do_with_transactions( + td::Result> r_transactions) { + TRY_RESULT(transactions, std::move(r_transactions)); + TRY_RESULT_PREFIX(info, TRY_VM(do_with_transactions(std::move(transactions))), TonlibError::ValidateTransactions()); + promise_.set_value(std::move(info)); + return td::Status::OK(); + } + + td::Result do_with_transactions( + ton::lite_api::object_ptr transactions) { + std::vector blkids; + for (auto& id : transactions->ids_) { + blkids.push_back(ton::create_block_id(std::move(id))); + } + return do_with_transactions(std::move(blkids), std::move(transactions->transactions_)); + } + + td::Result do_with_transactions(std::vector blkids, + td::BufferSlice transactions) { LOG(INFO) << "got up to " << count_ << " transactions for " << address_ << " from last transaction " << lt_ << ":" << hash_.to_hex(); block::TransactionList list; @@ -130,24 +151,7 @@ class GetTransactionHistory : public td::actor::Actor { LOG(WARNING) << "obtained " << info.transactions.size() << " transaction, but only " << count_ << " have been requested"; } - promise_.set_value(std::move(info)); - return td::Status::OK(); - } - - td::Status do_with_transactions( - td::Result> r_transactions) { - TRY_RESULT(transactions, std::move(r_transactions)); - std::vector blkids; - for (auto& id : transactions->ids_) { - blkids.push_back(ton::create_block_id(std::move(id))); - } - return do_with_transactions(std::move(blkids), std::move(transactions->transactions_)); - } - - void with_transactions( - td::Result> r_transactions) { - check(TRY_VM(do_with_transactions(std::move(r_transactions)))); - stop(); + return info; } void start_up() override { @@ -166,25 +170,35 @@ class GetTransactionHistory : public td::actor::Actor { class GetRawAccountState : public td::actor::Actor { public: - GetRawAccountState(ExtClientRef ext_client_ref, block::StdAddress address, td::Promise&& promise) - : address_(std::move(address)), promise_(std::move(promise)) { + GetRawAccountState(ExtClientRef ext_client_ref, block::StdAddress address, td::actor::ActorShared<> parent, + td::Promise&& promise) + : address_(std::move(address)), promise_(std::move(promise)), parent_(std::move(parent)) { client_.set_client(ext_client_ref); } private: block::StdAddress address_; td::Promise promise_; + td::actor::ActorShared<> parent_; ExtClient client_; LastBlockState last_block_; void with_account_state(td::Result> r_account_state) { - promise_.set_result(TRY_VM(do_with_account_state(std::move(r_account_state)))); + check(do_with_account_state(std::move(r_account_state))); + } + + td::Status do_with_account_state( + td::Result> r_raw_account_state) { + TRY_RESULT(raw_account_state, std::move(r_raw_account_state)); + TRY_RESULT_PREFIX(state, TRY_VM(do_with_account_state(std::move(raw_account_state))), + TonlibError::ValidateAccountState()); + promise_.set_value(std::move(state)); stop(); + return td::Status::OK(); } td::Result do_with_account_state( - td::Result> r_account_state) { - TRY_RESULT(raw_account_state, std::move(r_account_state)); + ton::tl_object_ptr raw_account_state) { auto account_state = create_account_state(std::move(raw_account_state)); TRY_RESULT(info, account_state.validate(last_block_.last_block_id, address_)); auto serialized_state = account_state.state.clone(); @@ -192,10 +206,12 @@ class GetRawAccountState : public td::actor::Actor { res.info = std::move(info); LOG_IF(ERROR, res.info.gen_utime > last_block_.utime) << res.info.gen_utime << " " << last_block_.utime; auto cell = res.info.root; + std::ostringstream outp; + block::gen::t_Account.print_ref(outp, cell); + LOG(ERROR) << outp.str(); if (cell.is_null()) { return res; } - //block::gen::t_Account.print_ref(std::cerr, cell); block::gen::Account::Record_account account; if (!tlb::unpack_cell(cell, account)) { return td::Status::Error("Failed to unpack Account"); @@ -210,7 +226,14 @@ class GetRawAccountState : public td::actor::Actor { if (state_tag < 0) { return td::Status::Error("Failed to parse AccountState tag"); } - // TODO: handle frozen account + if (state_tag == block::gen::AccountState::account_frozen) { + block::gen::AccountState::Record_account_frozen state; + if (!tlb::csr_unpack(storage.state, state)) { + return td::Status::Error("Failed to parse AccountState"); + } + res.frozen_hash = state.state_hash.as_slice().str(); + return res; + } if (state_tag != block::gen::AccountState::account_active) { return res; } @@ -228,19 +251,23 @@ class GetRawAccountState : public td::actor::Actor { return res; } - void start_up() override { - client_.with_last_block([self = this](td::Result r_last_block) { - if (r_last_block.is_error()) { - return self->check(r_last_block.move_as_error()); - } - self->last_block_ = r_last_block.move_as_ok(); + void with_last_block(td::Result r_last_block) { + check(do_with_last_block(std::move(r_last_block))); + } - self->client_.send_query( - ton::lite_api::liteServer_getAccountState(ton::create_tl_lite_block_id(self->last_block_.last_block_id), - ton::create_tl_object( - self->address_.workchain, self->address_.addr)), - [self](auto r_state) { self->with_account_state(std::move(r_state)); }); - }); + td::Status do_with_last_block(td::Result r_last_block) { + TRY_RESULT_ASSIGN(last_block_, std::move(r_last_block)); + client_.send_query( + ton::lite_api::liteServer_getAccountState( + ton::create_tl_lite_block_id(last_block_.last_block_id), + ton::create_tl_object(address_.workchain, address_.addr)), + [self = this](auto r_state) { self->with_account_state(std::move(r_state)); }); + return td::Status::OK(); + } + + void start_up() override { + client_.with_last_block( + [self = this](td::Result r_last_block) { self->with_last_block(std::move(r_last_block)); }); } void check(td::Status status) { @@ -354,18 +381,19 @@ void TonlibClient::init_last_block() { raw_last_block_ = td::actor::create_actor("LastBlock", get_client_ref(), std::move(state), config_, td::make_unique(td::actor::actor_shared(this), config_generation_)); - client_.set_client(get_client_ref()); } void TonlibClient::on_result(td::uint64 id, tonlib_api::object_ptr response) { + VLOG(tonlib_query) << "Tonlib answer query " << td::tag("id", id) << " " << to_string(response); if (response->get_id() == tonlib_api::error::ID) { callback_->on_error(id, tonlib_api::move_object_as(response)); return; } callback_->on_result(id, std::move(response)); } + void TonlibClient::request(td::uint64 id, tonlib_api::object_ptr function) { - LOG(ERROR) << to_string(function); + VLOG(tonlib_query) << "Tonlib got query " << td::tag("id", id) << " " << to_string(function); if (function == nullptr) { LOG(ERROR) << "Receive empty static request"; return on_result(id, tonlib_api::make_object(400, "Request is empty")); @@ -408,6 +436,7 @@ void TonlibClient::close() { } tonlib_api::object_ptr TonlibClient::static_request( tonlib_api::object_ptr function) { + VLOG(tonlib_query) << "Tonlib got static query " << to_string(function); if (function == nullptr) { LOG(ERROR) << "Receive empty static request"; return tonlib_api::make_object(400, "Request is empty"); @@ -415,6 +444,7 @@ tonlib_api::object_ptr TonlibClient::static_request( tonlib_api::object_ptr response; downcast_call(*function, [&response](auto& request) { response = TonlibClient::do_static_request(request); }); + VLOG(tonlib_query) << " answer static query " << to_string(function); return response; } @@ -459,24 +489,35 @@ tonlib_api::object_ptr TonlibClient::do_static_request(const runner.run_all(); return tonlib_api::make_object(); } + +td::Result get_public_key(td::Slice public_key) { + TRY_RESULT_PREFIX(address, block::PublicKey::parse(public_key), TonlibError::InvalidPublicKey()); + return address; +} + td::Result get_account_address(const tonlib_api::raw_initialAccountState& raw_state) { - TRY_RESULT(code, vm::std_boc_deserialize(raw_state.code_)); - TRY_RESULT(data, vm::std_boc_deserialize(raw_state.data_)); + TRY_RESULT_PREFIX(code, vm::std_boc_deserialize(raw_state.code_), TonlibError::InvalidBagOfCells("raw_state.code")); + TRY_RESULT_PREFIX(data, vm::std_boc_deserialize(raw_state.data_), TonlibError::InvalidBagOfCells("raw_state.data")); return GenericAccount::get_address(0 /*zerochain*/, GenericAccount::get_init_state(std::move(code), std::move(data))); } td::Result get_account_address(const tonlib_api::testWallet_initialAccountState& test_wallet_state) { - TRY_RESULT(key_bytes, block::PublicKey::parse(test_wallet_state.public_key_)); + TRY_RESULT(key_bytes, get_public_key(test_wallet_state.public_key_)); auto key = td::Ed25519::PublicKey(td::SecureString(key_bytes.key)); return GenericAccount::get_address(0 /*zerochain*/, TestWallet::get_init_state(key)); } td::Result get_account_address(const tonlib_api::wallet_initialAccountState& test_wallet_state) { - TRY_RESULT(key_bytes, block::PublicKey::parse(test_wallet_state.public_key_)); + TRY_RESULT(key_bytes, get_public_key(test_wallet_state.public_key_)); auto key = td::Ed25519::PublicKey(td::SecureString(key_bytes.key)); return GenericAccount::get_address(0 /*zerochain*/, Wallet::get_init_state(key)); } +td::Result get_account_address(td::Slice account_address) { + TRY_RESULT_PREFIX(address, block::StdAddress::parse(account_address), TonlibError::InvalidAccountAddress()); + return address; +} + tonlib_api::object_ptr TonlibClient::do_static_request( const tonlib_api::raw_getAccountAddress& request) { auto r_account_address = get_account_address(*request.initital_account_state_); @@ -485,6 +526,7 @@ tonlib_api::object_ptr TonlibClient::do_static_request( } return tonlib_api::make_object(r_account_address.ok().rserialize(true)); } + tonlib_api::object_ptr TonlibClient::do_static_request( const tonlib_api::testWallet_getAccountAddress& request) { auto r_account_address = get_account_address(*request.initital_account_state_); @@ -493,6 +535,7 @@ tonlib_api::object_ptr TonlibClient::do_static_request( } return tonlib_api::make_object(r_account_address.ok().rserialize(true)); } + tonlib_api::object_ptr TonlibClient::do_static_request( const tonlib_api::wallet_getAccountAddress& request) { auto r_account_address = get_account_address(*request.initital_account_state_); @@ -501,6 +544,7 @@ tonlib_api::object_ptr TonlibClient::do_static_request( } return tonlib_api::make_object(r_account_address.ok().rserialize(true)); } + tonlib_api::object_ptr TonlibClient::do_static_request( const tonlib_api::testGiver_getAccountAddress& request) { return tonlib_api::make_object(TestGiver::address().rserialize(true)); @@ -508,7 +552,7 @@ tonlib_api::object_ptr TonlibClient::do_static_request( tonlib_api::object_ptr TonlibClient::do_static_request( const tonlib_api::unpackAccountAddress& request) { - auto r_account_address = block::StdAddress::parse(request.account_address_); + auto r_account_address = get_account_address(request.account_address_); if (r_account_address.is_error()) { return status_to_tonlib_api(r_account_address.move_as_error()); } @@ -521,10 +565,10 @@ tonlib_api::object_ptr TonlibClient::do_static_request( tonlib_api::object_ptr TonlibClient::do_static_request( const tonlib_api::packAccountAddress& request) { if (!request.account_address_) { - return status_to_tonlib_api(td::Status::Error(400, "Field account_address must not be empty")); + return status_to_tonlib_api(TonlibError::EmptyField("account_address")); } if (request.account_address_->addr_.size() != 32) { - return status_to_tonlib_api(td::Status::Error(400, "Field account_address.addr must not be exactly 32 bytes")); + return status_to_tonlib_api(TonlibError::InvalidField("account_address.addr", "must be 32 bytes long")); } block::StdAddress addr; addr.workchain = request.account_address_->workchain_id_; @@ -545,10 +589,23 @@ td::Status TonlibClient::do_request(const tonlib_api::init& request, return td::Status::Error(400, "Tonlib is already inited"); } if (!request.options_) { - return td::Status::Error(400, "Field options must not be empty"); + return TonlibError::EmptyField("options"); } - TRY_STATUS(key_storage_.set_directory(request.options_->keystore_directory_)); - TRY_STATUS(last_block_storage_.set_directory(request.options_->keystore_directory_)); + if (!request.options_->keystore_type_) { + return TonlibError::EmptyField("options.keystore_type"); + } + + td::Result> r_kv; + downcast_call( + *request.options_->keystore_type_, + td::overloaded( + [&](tonlib_api::keyStoreTypeDirectory& directory) { r_kv = KeyValue::create_dir(directory.directory_); }, + [&](tonlib_api::keyStoreTypeInMemory& inmemory) { r_kv = KeyValue::create_inmemory(); })); + TRY_RESULT(kv, std::move(r_kv)); + kv_ = std::shared_ptr(kv.release()); + + key_storage_.set_key_value(kv_); + last_block_storage_.set_key_value(kv_); if (request.options_->config_) { TRY_STATUS(set_config(std::move(request.options_->config_))); } @@ -558,15 +615,14 @@ td::Status TonlibClient::do_request(const tonlib_api::init& request, } td::Status TonlibClient::set_config(object_ptr config) { - if (!config) { - return td::Status::Error(400, "config is empty"); - } + CHECK(config); if (config->config_.empty()) { - return td::Status::Error(400, "config is empty"); + return TonlibError::InvalidConfig("config is empty"); } - TRY_RESULT(new_config, Config::parse(std::move(config->config_))); + TRY_RESULT_PREFIX(new_config, Config::parse(std::move(config->config_)), + TonlibError::InvalidConfig("can't parse config")); if (new_config.lite_clients.empty() && !config->use_callbacks_for_network_) { - return td::Status::Error("No lite clients in config"); + return TonlibError::InvalidConfig("no lite clients"); } config_ = std::move(new_config); config_generation_++; @@ -579,6 +635,7 @@ td::Status TonlibClient::set_config(object_ptr config) { ignore_cache_ = config->ignore_cache_; init_ext_client(); init_last_block(); + client_.set_client(get_client_ref()); return td::Status::OK(); } @@ -592,6 +649,9 @@ td::Status TonlibClient::do_request(const tonlib_api::close& request, td::Status TonlibClient::do_request(tonlib_api::options_setConfig& request, td::Promise>&& promise) { + if (!request.config_) { + return TonlibError::EmptyField("config"); + } TRY_STATUS(set_config(std::move(request.config_))); promise.set_value(tonlib_api::make_object()); return td::Status::OK(); @@ -664,6 +724,9 @@ td::Result> to_raw_message_or_th TRY_RESULT(balance, to_balance(msg_info.value)); TRY_RESULT(src, to_std_address(msg_info.src)); TRY_RESULT(dest, to_std_address(msg_info.dest)); + TRY_RESULT(fwd_fee, to_balance(msg_info.fwd_fee)); + TRY_RESULT(ihr_fee, to_balance(msg_info.ihr_fee)); + auto created_lt = static_cast(msg_info.created_lt); td::Ref body; if (message.body->prefetch_long(1) == 0) { body = std::move(message.body); @@ -671,17 +734,18 @@ td::Result> to_raw_message_or_th } else { body = vm::load_cell_slice_ref(message.body->prefetch_ref()); } + auto body_hash = vm::CellBuilder().append_cellslice(*body).finalize()->get_hash().as_slice().str(); std::string body_message; - if (body->size() % 8 == 0) { - body_message = std::string(body->size() / 8, 0); - body->prefetch_bytes(td::MutableSlice(body_message).ubegin(), body->size() / 8); - if (body_message.size() >= 4 && body_message[0] == 0 && body_message[1] == 0 && body_message[2] == 0 && - body_message[3] == 0) { - body_message = body_message.substr(4); + if (body->size() >= 32 && body->prefetch_long(32) == 0) { + body.write().fetch_long(32); + auto r_body_message = vm::CellString::load(body.write()); + if (r_body_message.is_ok()) { + body_message = r_body_message.move_as_ok(); } } - return tonlib_api::make_object(std::move(src), std::move(dest), balance, + return tonlib_api::make_object(std::move(src), std::move(dest), balance, fwd_fee, + ihr_fee, created_lt, std::move(body_hash), std::move(body_message)); } case block::gen::CommonMsgInfo::ext_in_msg_info: { @@ -690,7 +754,16 @@ td::Result> to_raw_message_or_th return td::Status::Error("Failed to unpack CommonMsgInfo::ext_in_msg_info"); } TRY_RESULT(dest, to_std_address(msg_info.dest)); - return tonlib_api::make_object("", std::move(dest), 0, ""); + td::Ref body; + if (message.body->prefetch_long(1) == 0) { + body = std::move(message.body); + body.write().advance(1); + } else { + body = vm::load_cell_slice_ref(message.body->prefetch_ref()); + } + auto body_hash = vm::CellBuilder().append_cellslice(*body).finalize()->get_hash().as_slice().str(); + return tonlib_api::make_object("", std::move(dest), 0, 0, 0, 0, std::move(body_hash), + ""); } case block::gen::CommonMsgInfo::ext_out_msg_info: { block::gen::CommonMsgInfo::Record_ext_out_msg_info msg_info; @@ -698,7 +771,7 @@ td::Result> to_raw_message_or_th return td::Status::Error("Failed to unpack CommonMsgInfo::ext_out_msg_info"); } TRY_RESULT(src, to_std_address(msg_info.src)); - return tonlib_api::make_object(std::move(src), "", 0, ""); + return tonlib_api::make_object(std::move(src), "", 0, 0, 0, 0, "", ""); } } @@ -716,6 +789,7 @@ td::Result> to_raw_transacti tonlib_api::object_ptr in_msg; std::vector> out_msgs; td::int64 fees = 0; + td::int64 storage_fee = 0; if (info.transaction.not_null()) { TRY_RESULT(copy_data, vm::std_boc_serialize(info.transaction)); data = copy_data.as_slice().str(); @@ -724,8 +798,7 @@ td::Result> to_raw_transacti return td::Status::Error("Failed to unpack Transaction"); } - TRY_RESULT(copy_fees, to_balance(trans.total_fees)); - fees = copy_fees; + TRY_RESULT_ASSIGN(fees, to_balance(trans.total_fees)); std::ostringstream outp; block::gen::t_Transaction.print_ref(outp, info.transaction); @@ -745,15 +818,22 @@ td::Result> to_raw_transacti vm::Dictionary dict{trans.r1.out_msgs, 15}; for (int x = 0; x < trans.outmsg_cnt && x < 100; x++) { TRY_RESULT(out_msg, to_raw_message(dict.lookup_ref(td::BitArray<15>{x}))); + fees += out_msg->fwd_fee_; + fees += out_msg->ihr_fee_; out_msgs.push_back(std::move(out_msg)); } } + td::RefInt256 storage_fees; + if (!block::tlb::t_TransactionDescr.get_storage_fees(trans.description, storage_fees)) { + return td::Status::Error("Failed to fetch storage fee from transaction"); + } + storage_fee = storage_fees->to_long(); } return tonlib_api::make_object( info.now, data, tonlib_api::make_object(info.prev_trans_lt, info.prev_trans_hash.as_slice().str()), - fees, std::move(in_msg), std::move(out_msgs)); + fees, storage_fee, fees - storage_fee, std::move(in_msg), std::move(out_msgs)); } td::Result> to_raw_transaction(block::Transaction::Info&& info) { @@ -779,8 +859,11 @@ td::Result> to_raw_transact td::Result> to_testWallet_accountState( RawAccountState&& raw_state) { - if (raw_state.data.is_null()) { - return td::Status::Error(400, "Not a TestWallet"); + if (raw_state.code.is_null()) { + return TonlibError::AccountNotInited(); + } + if (raw_state.code->prefetch_ref()->get_hash() != TestWallet::get_init_code_hash()) { + return TonlibError::AccountTypeUnexpected("TestWallet"); } auto ref = raw_state.data->prefetch_ref(); auto cs = vm::load_cell_slice(std::move(ref)); @@ -794,8 +877,11 @@ td::Result> to_testW td::Result> to_wallet_accountState( RawAccountState&& raw_state) { - if (raw_state.data.is_null()) { - return td::Status::Error(400, "Not a Wallet"); + if (raw_state.code.is_null()) { + return TonlibError::AccountNotInited(); + } + if (raw_state.code->prefetch_ref()->get_hash() != Wallet::get_init_code_hash()) { + return TonlibError::AccountTypeUnexpected("Wallet"); } auto ref = raw_state.data->prefetch_ref(); auto cs = vm::load_cell_slice(std::move(ref)); @@ -809,8 +895,11 @@ td::Result> to_wallet_ac td::Result> to_testGiver_accountState( RawAccountState&& raw_state) { - if (raw_state.data.is_null()) { - return td::Status::Error(400, "Not a TestGiver"); + if (raw_state.code.is_null()) { + return TonlibError::AccountNotInited(); + } + if (raw_state.code->prefetch_ref()->get_hash() != TestGiver::get_init_code_hash()) { + return TonlibError::AccountTypeUnexpected("TestGiver"); } auto ref = raw_state.data->prefetch_ref(); auto cs = vm::load_cell_slice(std::move(ref)); @@ -853,21 +942,18 @@ td::Status TonlibClient::do_request(const tonlib_api::raw_sendMessage& request, td::Promise>&& promise) { td::Ref init_state; if (!request.initial_account_state_.empty()) { - TRY_RESULT(new_init_state, vm::std_boc_deserialize(request.initial_account_state_)); + TRY_RESULT_PREFIX(new_init_state, vm::std_boc_deserialize(request.initial_account_state_), + TonlibError::InvalidBagOfCells("initial_account_state")); init_state = std::move(new_init_state); } - TRY_RESULT(data, vm::std_boc_deserialize(request.data_)); - TRY_RESULT(account_address, block::StdAddress::parse(request.destination_->account_address_)); + TRY_RESULT_PREFIX(data, vm::std_boc_deserialize(request.data_), TonlibError::InvalidBagOfCells("data")); + TRY_RESULT(account_address, get_account_address(request.destination_->account_address_)); auto message = GenericAccount::create_ext_message(account_address, std::move(init_state), std::move(data)); client_.send_query(ton::lite_api::liteServer_sendMessage(vm::std_boc_serialize(message).move_as_ok()), [promise = std::move(promise)](auto r_info) mutable { - if (r_info.is_error()) { - promise.set_error(r_info.move_as_error()); - } else { - auto info = r_info.move_as_ok(); - LOG(ERROR) << "info: " << to_string(info); - promise.set_value(tonlib_api::make_object()); - } + TRY_RESULT_PROMISE(promise, info, std::move(r_info)); + LOG(ERROR) << "info: " << to_string(info); + promise.set_value(tonlib_api::make_object()); }); return td::Status::OK(); } @@ -875,30 +961,28 @@ td::Status TonlibClient::do_request(const tonlib_api::raw_sendMessage& request, td::Status TonlibClient::do_request(tonlib_api::raw_getAccountState& request, td::Promise>&& promise) { if (!request.account_address_) { - return td::Status::Error(400, "Field account_address must not be empty"); + return TonlibError::EmptyField("account_address"); } - TRY_RESULT(account_address, block::StdAddress::parse(request.account_address_->account_address_)); - td::actor::create_actor( - "GetAccountState", client_.get_client(), std::move(account_address), + TRY_RESULT(account_address, get_account_address(request.account_address_->account_address_)); + auto actor_id = actor_id_++; + actors_[actor_id] = td::actor::create_actor( + "GetAccountState", client_.get_client(), std::move(account_address), actor_shared(this, actor_id), [promise = std::move(promise)](td::Result r_state) mutable { - if (r_state.is_error()) { - return promise.set_error(r_state.move_as_error()); - } - promise.set_result(to_raw_accountState(r_state.move_as_ok())); - }) - .release(); + TRY_RESULT_PROMISE(promise, state, std::move(r_state)); + promise.set_result(to_raw_accountState(std::move(state))); + }); return td::Status::OK(); } td::Status TonlibClient::do_request(tonlib_api::raw_getTransactions& request, td::Promise>&& promise) { if (!request.account_address_) { - return td::Status::Error(400, "Field account_address must not be empty"); + return TonlibError::EmptyField("account_address"); } if (!request.from_transaction_id_) { - return td::Status::Error(400, "Field from_transaction_id must not be empty"); + return TonlibError::EmptyField("from_transaction_id"); } - TRY_RESULT(account_address, block::StdAddress::parse(request.account_address_->account_address_)); + TRY_RESULT(account_address, get_account_address(request.account_address_->account_address_)); auto lt = request.from_transaction_id_->lt_; auto hash_str = request.from_transaction_id_->hash_; if (hash_str.size() != 32) { @@ -907,24 +991,22 @@ td::Status TonlibClient::do_request(tonlib_api::raw_getTransactions& request, td::Bits256 hash; hash.as_slice().copy_from(hash_str); - td::actor::create_actor( - "GetTransactionHistory", client_.get_client(), account_address, lt, hash, + auto actor_id = actor_id_++; + actors_[actor_id] = td::actor::create_actor( + "GetTransactionHistory", client_.get_client(), account_address, lt, hash, actor_shared(this, actor_id), [promise = std::move(promise)](td::Result r_info) mutable { - if (r_info.is_error()) { - return promise.set_error(r_info.move_as_error()); - } - promise.set_result(to_raw_transactions(r_info.move_as_ok())); - }) - .release(); + TRY_RESULT_PROMISE(promise, info, std::move(r_info)); + promise.set_result(to_raw_transactions(std::move(info))); + }); return td::Status::OK(); } td::Result from_tonlib(tonlib_api::inputKey& input_key) { if (!input_key.key_) { - return td::Status::Error(400, "Field key must not be empty"); + return TonlibError::EmptyField("key"); } - TRY_RESULT(key_bytes, block::PublicKey::parse(input_key.key_->public_key_)); + TRY_RESULT(key_bytes, get_public_key(input_key.key_->public_key_)); return KeyStorage::InputKey{{td::SecureString(key_bytes.key), std::move(input_key.key_->secret_)}, std::move(input_key.local_password_)}; } @@ -950,15 +1032,15 @@ td::Status TonlibClient::do_request(const tonlib_api::testWallet_init& request, td::Status TonlibClient::do_request(const tonlib_api::testWallet_sendGrams& request, td::Promise>&& promise) { if (!request.destination_) { - return td::Status::Error(400, "Field destination must not be empty"); + return TonlibError::EmptyField("destination"); } if (!request.private_key_) { - return td::Status::Error(400, "Field private_key must not be empty"); + return TonlibError::EmptyField("private_key"); } - if (request.message_.size() > 70) { - return td::Status::Error(400, "Message is too long"); + if (request.message_.size() > TestWallet::max_message_size) { + return TonlibError::MessageTooLong(); } - TRY_RESULT(account_address, block::StdAddress::parse(request.destination_->account_address_)); + TRY_RESULT(account_address, get_account_address(request.destination_->account_address_)); account_address.bounceable = false; TRY_RESULT(input_key, from_tonlib(*request.private_key_)); auto address = GenericAccount::get_address( @@ -967,43 +1049,37 @@ td::Status TonlibClient::do_request(const tonlib_api::testWallet_sendGrams& requ auto private_key = td::Ed25519::PrivateKey(std::move(private_key_str.private_key)); std::string init_state; if (request.seqno_ == 0) { - TRY_RESULT(public_key, private_key.get_public_key()); + TRY_RESULT_PREFIX(public_key, private_key.get_public_key(), TonlibError::Internal()); init_state = vm::std_boc_serialize(TestWallet::get_init_state(public_key)).move_as_ok().as_slice().str(); } + auto message = + TestWallet::make_a_gift_message(private_key, request.seqno_, request.amount_, request.message_, account_address); + auto message_hash = message->get_hash().as_slice().str(); td::Promise> new_promise = - [promise = std::move(promise)](td::Result> res) mutable { - if (res.is_error()) { - promise.set_error(res.move_as_error()); - } else { - promise.set_value(tonlib_api::make_object(0)); - } + [promise = std::move(promise), + message_hash = std::move(message_hash)](td::Result> res) mutable { + TRY_RESULT_PROMISE(promise, ok, std::move(res)); + promise.set_value(tonlib_api::make_object(0, std::move(message_hash))); }; - return do_request( - tonlib_api::raw_sendMessage( - tonlib_api::make_object(address.rserialize(true)), std::move(init_state), - vm::std_boc_serialize(TestWallet::make_a_gift_message(private_key, request.seqno_, request.amount_, - request.message_, account_address)) - .move_as_ok() - .as_slice() - .str()), - std::move(new_promise)); + return do_request(tonlib_api::raw_sendMessage( + tonlib_api::make_object(address.rserialize(true)), + std::move(init_state), vm::std_boc_serialize(std::move(message)).move_as_ok().as_slice().str()), + std::move(new_promise)); } td::Status TonlibClient::do_request(tonlib_api::testWallet_getAccountState& request, td::Promise>&& promise) { if (!request.account_address_) { - return td::Status::Error(400, "Field account_address must not be empty"); + return TonlibError::EmptyField("account_address"); } - TRY_RESULT(account_address, block::StdAddress::parse(request.account_address_->account_address_)); - td::actor::create_actor( - "GetAccountState", client_.get_client(), std::move(account_address), + TRY_RESULT(account_address, get_account_address(request.account_address_->account_address_)); + auto actor_id = actor_id_++; + actors_[actor_id] = td::actor::create_actor( + "GetAccountState", client_.get_client(), std::move(account_address), actor_shared(this, actor_id), [promise = std::move(promise)](td::Result r_state) mutable { - if (r_state.is_error()) { - return promise.set_error(r_state.move_as_error()); - } - promise.set_result(to_testWallet_accountState(r_state.move_as_ok())); - }) - .release(); + TRY_RESULT_PROMISE(promise, state, std::move(r_state)); + promise.set_result(to_testWallet_accountState(std::move(state))); + }); return td::Status::OK(); } @@ -1011,7 +1087,7 @@ td::Status TonlibClient::do_request(tonlib_api::testWallet_getAccountState& requ td::Status TonlibClient::do_request(const tonlib_api::wallet_init& request, td::Promise>&& promise) { if (!request.private_key_) { - return td::Status::Error(400, "Field private_key must not be empty"); + return TonlibError::EmptyField("private_key"); } TRY_RESULT(input_key, from_tonlib(*request.private_key_)); auto init_state = Wallet::get_init_state(td::Ed25519::PublicKey(input_key.key.public_key.copy())); @@ -1028,16 +1104,17 @@ td::Status TonlibClient::do_request(const tonlib_api::wallet_init& request, td::Status TonlibClient::do_request(const tonlib_api::wallet_sendGrams& request, td::Promise>&& promise) { if (!request.destination_) { - return td::Status::Error(400, "Field destination must not be empty"); + return TonlibError::EmptyField("destination"); } if (!request.private_key_) { - return td::Status::Error(400, "Field private_key must not be empty"); + return TonlibError::EmptyField("private_key"); } - if (request.message_.size() > 70) { - return td::Status::Error(400, "Message is too long"); + if (request.message_.size() > Wallet::max_message_size) { + return TonlibError::MessageTooLong(); } - TRY_RESULT(valid_until, td::narrow_cast_safe(request.valid_until_)); - TRY_RESULT(account_address, block::StdAddress::parse(request.destination_->account_address_)); + TRY_RESULT_PREFIX(valid_until, td::narrow_cast_safe(request.valid_until_), + TonlibError::InvalidField("valid_until", "overflow")); + TRY_RESULT(account_address, get_account_address(request.destination_->account_address_)); account_address.bounceable = false; TRY_RESULT(input_key, from_tonlib(*request.private_key_)); auto address = GenericAccount::get_address( @@ -1046,43 +1123,37 @@ td::Status TonlibClient::do_request(const tonlib_api::wallet_sendGrams& request, auto private_key = td::Ed25519::PrivateKey(std::move(private_key_str.private_key)); std::string init_state; if (request.seqno_ == 0) { - TRY_RESULT(public_key, private_key.get_public_key()); + TRY_RESULT_PREFIX(public_key, private_key.get_public_key(), TonlibError::Internal()); init_state = vm::std_boc_serialize(Wallet::get_init_state(public_key)).move_as_ok().as_slice().str(); } + auto message = Wallet::make_a_gift_message(private_key, request.seqno_, valid_until, request.amount_, + request.message_, account_address); + auto message_hash = message->get_hash().as_slice().str(); td::Promise> new_promise = - [promise = std::move(promise), valid_until](td::Result> res) mutable { - if (res.is_error()) { - promise.set_error(res.move_as_error()); - } else { - promise.set_value(tonlib_api::make_object(valid_until)); - } + [promise = std::move(promise), valid_until, + message_hash = std::move(message_hash)](td::Result> res) mutable { + TRY_RESULT_PROMISE(promise, ok, std::move(res)); + promise.set_value(tonlib_api::make_object(valid_until, std::move(message_hash))); }; - return do_request( - tonlib_api::raw_sendMessage( - tonlib_api::make_object(address.rserialize(true)), std::move(init_state), - vm::std_boc_serialize(Wallet::make_a_gift_message(private_key, request.seqno_, valid_until, request.amount_, - request.message_, account_address)) - .move_as_ok() - .as_slice() - .str()), - std::move(new_promise)); + return do_request(tonlib_api::raw_sendMessage( + tonlib_api::make_object(address.rserialize(true)), + std::move(init_state), vm::std_boc_serialize(std::move(message)).move_as_ok().as_slice().str()), + std::move(new_promise)); } td::Status TonlibClient::do_request(tonlib_api::wallet_getAccountState& request, td::Promise>&& promise) { if (!request.account_address_) { - return td::Status::Error(400, "Field account_address must not be empty"); + return TonlibError::EmptyField("account_address"); } - TRY_RESULT(account_address, block::StdAddress::parse(request.account_address_->account_address_)); - td::actor::create_actor( - "GetAccountState", client_.get_client(), std::move(account_address), + TRY_RESULT(account_address, get_account_address(request.account_address_->account_address_)); + auto actor_id = actor_id_++; + actors_[actor_id] = td::actor::create_actor( + "GetAccountState", client_.get_client(), std::move(account_address), actor_shared(this, actor_id), [promise = std::move(promise)](td::Result r_state) mutable { - if (r_state.is_error()) { - return promise.set_error(r_state.move_as_error()); - } - promise.set_result(to_wallet_accountState(r_state.move_as_ok())); - }) - .release(); + TRY_RESULT_PROMISE(promise, state, std::move(r_state)); + promise.set_result(to_wallet_accountState(std::move(state))); + }); return td::Status::OK(); } @@ -1090,60 +1161,52 @@ td::Status TonlibClient::do_request(tonlib_api::wallet_getAccountState& request, td::Status TonlibClient::do_request(const tonlib_api::testGiver_sendGrams& request, td::Promise>&& promise) { if (!request.destination_) { - return td::Status::Error(400, "Field destination must not be empty"); + return TonlibError::EmptyField("destination"); } - if (request.message_.size() > 70) { - return td::Status::Error(400, "Message is too long"); + if (request.message_.size() > TestGiver::max_message_size) { + return TonlibError::MessageTooLong(); } - TRY_RESULT(account_address, block::StdAddress::parse(request.destination_->account_address_)); + TRY_RESULT(account_address, get_account_address(request.destination_->account_address_)); account_address.bounceable = false; + auto message = TestGiver::make_a_gift_message(request.seqno_, request.amount_, request.message_, account_address); + auto message_hash = message->get_hash().as_slice().str(); td::Promise> new_promise = - [promise = std::move(promise)](td::Result> res) mutable { - if (res.is_error()) { - promise.set_error(res.move_as_error()); - } else { - promise.set_value(tonlib_api::make_object(0)); - } + [promise = std::move(promise), + message_hash = std::move(message_hash)](td::Result> res) mutable { + TRY_RESULT_PROMISE(promise, ok, std::move(res)); + promise.set_value(tonlib_api::make_object(0, std::move(message_hash))); }; return do_request(tonlib_api::raw_sendMessage( tonlib_api::make_object(TestGiver::address().rserialize(true)), "", - vm::std_boc_serialize(TestGiver::make_a_gift_message(request.seqno_, request.amount_, - request.message_, account_address)) - .move_as_ok() - .as_slice() - .str()), + vm::std_boc_serialize(std::move(message)).move_as_ok().as_slice().str()), std::move(new_promise)); } td::Status TonlibClient::do_request(const tonlib_api::testGiver_getAccountState& request, td::Promise>&& promise) { - td::actor::create_actor( - "GetAccountState", client_.get_client(), TestGiver::address(), + auto actor_id = actor_id_++; + actors_[actor_id] = td::actor::create_actor( + "GetAccountState", client_.get_client(), TestGiver::address(), actor_shared(this, actor_id), [promise = std::move(promise)](td::Result r_state) mutable { - if (r_state.is_error()) { - return promise.set_error(r_state.move_as_error()); - } - promise.set_result(to_testGiver_accountState(r_state.move_as_ok())); - }) - .release(); + TRY_RESULT_PROMISE(promise, state, std::move(r_state)); + promise.set_result(to_testGiver_accountState(std::move(state))); + }); return td::Status::OK(); } td::Status TonlibClient::do_request(const tonlib_api::generic_getAccountState& request, td::Promise>&& promise) { if (!request.account_address_) { - return td::Status::Error(400, "Field account_address must not be empty"); + return TonlibError::EmptyField("account_address"); } - TRY_RESULT(account_address, block::StdAddress::parse(request.account_address_->account_address_)); - td::actor::create_actor( - "GetAccountState", client_.get_client(), std::move(account_address), + TRY_RESULT(account_address, get_account_address(request.account_address_->account_address_)); + auto actor_id = actor_id_++; + actors_[actor_id] = td::actor::create_actor( + "GetAccountState", client_.get_client(), std::move(account_address), actor_shared(this, actor_id), [promise = std::move(promise)](td::Result r_state) mutable { - if (r_state.is_error()) { - return promise.set_error(r_state.move_as_error()); - } - promise.set_result(to_generic_accountState(r_state.move_as_ok())); - }) - .release(); + TRY_RESULT_PROMISE(promise, state, std::move(r_state)); + promise.set_result(to_generic_accountState(std::move(state))); + }); return td::Status::OK(); } @@ -1185,7 +1248,6 @@ class GenericSendGrams : public TonlibQueryActor { void check(td::Status status) { if (status.is_error()) { - LOG(ERROR) << status; promise_.set_error(std::move(status)); return stop(); } @@ -1196,17 +1258,16 @@ class GenericSendGrams : public TonlibQueryActor { } td::Status do_start_up() { - alarm_timestamp() = td::Timestamp::in(15); if (!send_grams_.destination_) { - return td::Status::Error(400, "Field destination must not be empty"); + return TonlibError::EmptyField("destination"); } - TRY_RESULT(destination_address, block::StdAddress::parse(send_grams_.destination_->account_address_)); + TRY_RESULT(destination_address, get_account_address(send_grams_.destination_->account_address_)); is_destination_bounce_ = destination_address.bounceable; if (!send_grams_.source_) { - return td::Status::Error(400, "Field source must not be empty"); + return TonlibError::EmptyField("destination"); } - TRY_RESULT(source_address, block::StdAddress::parse(send_grams_.source_->account_address_)); + TRY_RESULT(source_address, get_account_address(send_grams_.source_->account_address_)); source_address_ = std::move(source_address); send_query(tonlib_api::generic_getAccountState( @@ -1245,19 +1306,19 @@ class GenericSendGrams : public TonlibQueryActor { source_state_ = std::move(state); if (source_state_->get_id() == tonlib_api::generic_accountStateUninited::ID && send_grams_.private_key_ && send_grams_.private_key_->key_) { - TRY_RESULT(key_bytes, block::PublicKey::parse(send_grams_.private_key_->key_->public_key_)); + TRY_RESULT(key_bytes, get_public_key(send_grams_.private_key_->key_->public_key_)); auto key = td::Ed25519::PublicKey(td::SecureString(key_bytes.key)); if (GenericAccount::get_address(0 /*zerochain*/, TestWallet::get_init_state(key)).addr == source_address_.addr) { auto state = ton::move_tl_object_as(source_state_); source_state_ = tonlib_api::make_object( - tonlib_api::make_object(-1, 0, nullptr, + tonlib_api::make_object(state->account_state_->balance_, 0, nullptr, state->account_state_->sync_utime_)); } else if (GenericAccount::get_address(0 /*zerochain*/, Wallet::get_init_state(key)).addr == source_address_.addr) { auto state = ton::move_tl_object_as(source_state_); source_state_ = tonlib_api::make_object( - tonlib_api::make_object(-1, 0, nullptr, + tonlib_api::make_object(state->account_state_->balance_, 0, nullptr, state->account_state_->sync_utime_)); } } @@ -1273,54 +1334,68 @@ class GenericSendGrams : public TonlibQueryActor { destination_state_ = std::move(state); if (destination_state_->get_id() == tonlib_api::generic_accountStateUninited::ID && is_destination_bounce_ && !send_grams_.allow_send_to_uninited_) { - return td::Status::Error(400, "DANGEROUS_TRANSACTION: Transfer to uninited wallet"); + return TonlibError::DangerousTransaction("Transfer to uninited wallet"); } return do_loop(); } - void alarm() override { - check(td::Status::Error("Timeout")); - } td::Status do_loop() { if (!source_state_ || !destination_state_) { return td::Status::OK(); } - downcast_call(*source_state_, - td::overloaded( - [&](tonlib_api::generic_accountStateTestGiver& test_giver_state) { - send_query(tonlib_api::testGiver_sendGrams( - std::move(send_grams_.destination_), test_giver_state.account_state_->seqno_, - send_grams_.amount_, std::move(send_grams_.message_)), - std::move(promise_)); - stop(); - }, - [&](tonlib_api::generic_accountStateTestWallet& test_wallet_state) { - send_query(tonlib_api::testWallet_sendGrams( - std::move(send_grams_.private_key_), std::move(send_grams_.destination_), - test_wallet_state.account_state_->seqno_, send_grams_.amount_, - std::move(send_grams_.message_)), - std::move(promise_)); - stop(); - }, - [&](tonlib_api::generic_accountStateWallet& test_wallet_state) { - send_query(tonlib_api::wallet_sendGrams( - std::move(send_grams_.private_key_), std::move(send_grams_.destination_), - test_wallet_state.account_state_->seqno_, - send_grams_.timeout_ == 0 - ? 60 + test_wallet_state.account_state_->sync_utime_ - : send_grams_.timeout_ + test_wallet_state.account_state_->sync_utime_, - send_grams_.amount_, std::move(send_grams_.message_)), - std::move(promise_)); - stop(); - }, - [&](tonlib_api::generic_accountStateUninited&) { - promise_.set_error(td::Status::Error(400, "Account is not inited")); - stop(); - }, - [&](tonlib_api::generic_accountStateRaw&) { - promise_.set_error(td::Status::Error(400, "Unknown account type")); - stop(); - })); + downcast_call( + *source_state_, + td::overloaded( + [&](tonlib_api::generic_accountStateTestGiver& test_giver_state) { + auto amount = send_grams_.amount_; + send_query(tonlib_api::testGiver_sendGrams(std::move(send_grams_.destination_), + test_giver_state.account_state_->seqno_, amount, + std::move(send_grams_.message_)), + std::move(promise_)); + stop(); + }, + [&](tonlib_api::generic_accountStateTestWallet& test_wallet_state) { + auto amount = send_grams_.amount_; + auto balance = test_wallet_state.account_state_->balance_; + if (false && amount == balance) { + amount = -1; + } else if (amount >= balance) { + promise_.set_error(TonlibError::NotEnoughFunds()); + return stop(); + } + send_query(tonlib_api::testWallet_sendGrams( + std::move(send_grams_.private_key_), std::move(send_grams_.destination_), + test_wallet_state.account_state_->seqno_, amount, std::move(send_grams_.message_)), + std::move(promise_)); + stop(); + }, + [&](tonlib_api::generic_accountStateWallet& wallet_state) { + auto amount = send_grams_.amount_; + auto balance = wallet_state.account_state_->balance_; + if (false && amount == balance) { + amount = -1; + } else if (amount >= balance) { + promise_.set_error(TonlibError::NotEnoughFunds()); + return stop(); + } + send_query( + tonlib_api::wallet_sendGrams(std::move(send_grams_.private_key_), std::move(send_grams_.destination_), + wallet_state.account_state_->seqno_, + send_grams_.timeout_ == 0 + ? 60 + wallet_state.account_state_->sync_utime_ + : send_grams_.timeout_ + wallet_state.account_state_->sync_utime_, + amount, std::move(send_grams_.message_)), + std::move(promise_)); + stop(); + }, + [&](tonlib_api::generic_accountStateUninited&) { + promise_.set_error(TonlibError::AccountNotInited()); + stop(); + }, + [&](tonlib_api::generic_accountStateRaw&) { + promise_.set_error(TonlibError::AccountTypeUnknown()); + stop(); + })); return td::Status::OK(); } }; @@ -1328,7 +1403,7 @@ class GenericSendGrams : public TonlibQueryActor { td::Status TonlibClient::do_request(tonlib_api::generic_sendGrams& request, td::Promise>&& promise) { if (request.timeout_ < 0 || request.timeout_ > 300) { - return td::Status::Error(400, "Invalid timeout: must be between 0 and 300"); + return TonlibError::InvalidField("timeout", "must be between 0 and 300"); } auto id = actor_id_++; actors_[id] = td::actor::create_actor("GenericSendGrams", actor_shared(this, id), @@ -1336,11 +1411,19 @@ td::Status TonlibClient::do_request(tonlib_api::generic_sendGrams& request, return td::Status::OK(); } +td::Result public_key_from_bytes(td::Slice bytes) { + TRY_RESULT_PREFIX(key_bytes, block::PublicKey::from_bytes(bytes), TonlibError::Internal()); + return key_bytes; +} + td::Status TonlibClient::do_request(const tonlib_api::createNewKey& request, td::Promise>&& promise) { - TRY_RESULT(key, key_storage_.create_new_key(std::move(request.local_password_), std::move(request.mnemonic_password_), - std::move(request.random_extra_seed_))); - TRY_RESULT(key_bytes, block::PublicKey::from_bytes(key.public_key.as_slice())); + TRY_RESULT_PREFIX( + key, + key_storage_.create_new_key(std::move(request.local_password_), std::move(request.mnemonic_password_), + std::move(request.random_extra_seed_)), + TonlibError::Internal()); + TRY_RESULT(key_bytes, public_key_from_bytes(key.public_key.as_slice())); promise.set_value(tonlib_api::make_object(key_bytes.serialize(true), std::move(key.secret))); return td::Status::OK(); } @@ -1348,7 +1431,7 @@ td::Status TonlibClient::do_request(const tonlib_api::createNewKey& request, td::Status TonlibClient::do_request(const tonlib_api::exportKey& request, td::Promise>&& promise) { if (!request.input_key_) { - return td::Status::Error(400, "Field input_key must not be empty"); + return TonlibError::EmptyField("input_key"); } TRY_RESULT(input_key, from_tonlib(*request.input_key_)); TRY_RESULT(exported_key, key_storage_.export_key(std::move(input_key))); @@ -1359,13 +1442,20 @@ td::Status TonlibClient::do_request(const tonlib_api::exportKey& request, td::Status TonlibClient::do_request(const tonlib_api::deleteKey& request, td::Promise>&& promise) { if (!request.key_) { - return td::Status::Error(400, "Field key must not be empty"); + return TonlibError::EmptyField("key"); } - TRY_RESULT(key_bytes, block::PublicKey::parse(request.key_->public_key_)); + TRY_RESULT(key_bytes, get_public_key(request.key_->public_key_)); KeyStorage::Key key; key.public_key = td::SecureString(key_bytes.key); key.secret = std::move(request.key_->secret_); - TRY_STATUS(key_storage_.delete_key(key)); + TRY_STATUS_PREFIX(key_storage_.delete_key(key), TonlibError::KeyUnknown()); + promise.set_value(tonlib_api::make_object()); + return td::Status::OK(); +} + +td::Status TonlibClient::do_request(const tonlib_api::deleteAllKeys& request, + td::Promise>&& promise) { + TRY_STATUS_PREFIX(key_storage_.delete_all_keys(), TonlibError::Internal()); promise.set_value(tonlib_api::make_object()); return td::Status::OK(); } @@ -1373,11 +1463,11 @@ td::Status TonlibClient::do_request(const tonlib_api::deleteKey& request, td::Status TonlibClient::do_request(const tonlib_api::importKey& request, td::Promise>&& promise) { if (!request.exported_key_) { - return td::Status::Error(400, "Field exported_key must not be empty"); + return TonlibError::EmptyField("exported_key"); } TRY_RESULT(key, key_storage_.import_key(std::move(request.local_password_), std::move(request.mnemonic_password_), KeyStorage::ExportedKey{std::move(request.exported_key_->word_list_)})); - TRY_RESULT(key_bytes, block::PublicKey::from_bytes(key.public_key.as_slice())); + TRY_RESULT(key_bytes, public_key_from_bytes(key.public_key.as_slice())); promise.set_value(tonlib_api::make_object(key_bytes.serialize(true), std::move(key.secret))); return td::Status::OK(); } @@ -1385,13 +1475,13 @@ td::Status TonlibClient::do_request(const tonlib_api::importKey& request, td::Status TonlibClient::do_request(const tonlib_api::exportPemKey& request, td::Promise>&& promise) { if (!request.input_key_) { - return td::Status::Error(400, "Field input_key must not be empty"); + return TonlibError::EmptyField("input_key"); } if (!request.input_key_->key_) { - return td::Status::Error(400, "Field key must not be empty"); + return TonlibError::EmptyField("key"); } - TRY_RESULT(key_bytes, block::PublicKey::parse(request.input_key_->key_->public_key_)); + TRY_RESULT(key_bytes, get_public_key(request.input_key_->key_->public_key_)); KeyStorage::InputKey input_key{{td::SecureString(key_bytes.key), std::move(request.input_key_->key_->secret_)}, std::move(request.input_key_->local_password_)}; TRY_RESULT(exported_pem_key, key_storage_.export_pem_key(std::move(input_key), std::move(request.key_password_))); @@ -1402,11 +1492,11 @@ td::Status TonlibClient::do_request(const tonlib_api::exportPemKey& request, td::Status TonlibClient::do_request(const tonlib_api::importPemKey& request, td::Promise>&& promise) { if (!request.exported_key_) { - return td::Status::Error(400, "Field exported_key must not be empty"); + return TonlibError::EmptyField("exported_key"); } TRY_RESULT(key, key_storage_.import_pem_key(std::move(request.local_password_), std::move(request.key_password_), KeyStorage::ExportedPemKey{std::move(request.exported_key_->pem_)})); - TRY_RESULT(key_bytes, block::PublicKey::from_bytes(key.public_key.as_slice())); + TRY_RESULT(key_bytes, public_key_from_bytes(key.public_key.as_slice())); promise.set_value(tonlib_api::make_object(key_bytes.serialize(true), std::move(key.secret))); return td::Status::OK(); } @@ -1414,7 +1504,7 @@ td::Status TonlibClient::do_request(const tonlib_api::importPemKey& request, td::Status TonlibClient::do_request(const tonlib_api::exportEncryptedKey& request, td::Promise>&& promise) { if (!request.input_key_) { - return td::Status::Error(400, "Field input_key must not be empty"); + return TonlibError::EmptyField("input_key"); } TRY_RESULT(input_key, from_tonlib(*request.input_key_)); TRY_RESULT(exported_key, key_storage_.export_encrypted_key(std::move(input_key), request.key_password_)); @@ -1425,12 +1515,12 @@ td::Status TonlibClient::do_request(const tonlib_api::exportEncryptedKey& reques td::Status TonlibClient::do_request(const tonlib_api::importEncryptedKey& request, td::Promise>&& promise) { if (!request.exported_encrypted_key_) { - return td::Status::Error(400, "Field exported_encrypted_key must not be empty"); + return TonlibError::EmptyField("exported_encrypted_key"); } TRY_RESULT(key, key_storage_.import_encrypted_key( std::move(request.local_password_), std::move(request.key_password_), KeyStorage::ExportedEncryptedKey{std::move(request.exported_encrypted_key_->data_)})); - TRY_RESULT(key_bytes, block::PublicKey::from_bytes(key.public_key.as_slice())); + TRY_RESULT(key_bytes, public_key_from_bytes(key.public_key.as_slice())); promise.set_value(tonlib_api::make_object(key_bytes.serialize(true), std::move(key.secret))); return td::Status::OK(); } @@ -1438,10 +1528,10 @@ td::Status TonlibClient::do_request(const tonlib_api::importEncryptedKey& reques td::Status TonlibClient::do_request(const tonlib_api::changeLocalPassword& request, td::Promise>&& promise) { if (!request.input_key_) { - return td::Status::Error(400, "Field input_key must not be empty"); + return TonlibError::EmptyField("input_key"); } if (!request.input_key_->key_) { - return td::Status::Error(400, "Field key must not be empty"); + return TonlibError::EmptyField("key"); } TRY_RESULT(input_key, from_tonlib(*request.input_key_)); TRY_RESULT(key, key_storage_.change_local_password(std::move(input_key), std::move(request.new_local_password_))); @@ -1465,7 +1555,8 @@ td::Status TonlibClient::do_request(const tonlib_api::onLiteServerQueryResult& r td::Status TonlibClient::do_request(const tonlib_api::onLiteServerQueryError& request, td::Promise>&& promise) { send_closure(ext_client_outbound_, &ExtClientOutbound::on_query_result, request.id_, - td::Status::Error(request.error_->code_, request.error_->message_), + td::Status::Error(request.error_->code_, request.error_->message_) + .move_as_error_prefix(TonlibError::LiteServerNetwork()), [promise = std::move(promise)](td::Result res) mutable { if (res.is_ok()) { promise.set_value(tonlib_api::make_object()); diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/TonlibClient.h b/submodules/ton/tonlib-src/tonlib/tonlib/TonlibClient.h index 9e7ecdafea..649df52d74 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/TonlibClient.h +++ b/submodules/ton/tonlib-src/tonlib/tonlib/TonlibClient.h @@ -24,6 +24,7 @@ #include "tonlib/ExtClient.h" #include "tonlib/ExtClientOutbound.h" #include "tonlib/KeyStorage.h" +#include "tonlib/KeyValue.h" #include "tonlib/LastBlockStorage.h" #include "td/actor/actor.h" @@ -46,20 +47,22 @@ class TonlibClient : public td::actor::Actor { private: enum class State { Uninited, Running, Closed } state_ = State::Uninited; td::unique_ptr callback_; + + // Config Config config_; td::uint32 config_generation_{0}; std::string blockchain_name_; bool ignore_cache_{false}; - bool use_callbacks_for_network_{false}; - td::actor::ActorId ext_client_outbound_; // KeyStorage + std::shared_ptr kv_; KeyStorage key_storage_; LastBlockStorage last_block_storage_; // network td::actor::ActorOwn raw_client_; + td::actor::ActorId ext_client_outbound_; td::actor::ActorOwn raw_last_block_; ExtClient client_; @@ -156,6 +159,7 @@ class TonlibClient : public td::actor::Actor { td::Status do_request(const tonlib_api::exportKey& request, td::Promise>&& promise); td::Status do_request(const tonlib_api::deleteKey& request, td::Promise>&& promise); + td::Status do_request(const tonlib_api::deleteAllKeys& request, td::Promise>&& promise); td::Status do_request(const tonlib_api::importKey& request, td::Promise>&& promise); td::Status do_request(const tonlib_api::exportPemKey& request, diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/TonlibError.h b/submodules/ton/tonlib-src/tonlib/tonlib/TonlibError.h new file mode 100644 index 0000000000..e0b4d0b189 --- /dev/null +++ b/submodules/ton/tonlib-src/tonlib/tonlib/TonlibError.h @@ -0,0 +1,157 @@ +/* + This file is part of TON Blockchain Library. + + TON Blockchain Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + TON Blockchain Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with TON Blockchain Library. If not, see . + + Copyright 2017-2019 Telegram Systems LLP +*/ + +#pragma once + +#include "td/utils/Status.h" +#include "common/errorcode.h" +// NEED_MNEMONIC_PASSWORD +// KEY_UNKNOWN +// KEY_DECRYPT +// INVALID_MNEMONIC +// INVALID_BAG_OF_CELLS +// INVALID_PUBLIC_KEY +// INVALID_ACCOUNT_ADDRESS +// INVALID_CONFIG +// INVALID_PEM_KEY +// MESSAGE_TOO_LONG +// EMPTY_FIELD +// INVALID_FIELD +// DANGEROUS_TRANSACTION +// ACCOUNT_NOT_INITED +// ACCOUNT_TYPE_UNKNOWN +// ACCOUNT_TYPE_UNEXPECTED +// VALIDATE_ACCOUNT_STATE +// VALIDATE_TRANSACTION +// VALIDATE_ZERO_STATE +// VALIDATE_BLOCK_PROOF +// NO_LITE_SERVERS +// LITE_SERVER_NETWORK +// CANCELLED +// NOT_ENOUGH_FUNDS +// LITE_SERVER +// INTERNAL + +namespace tonlib { +struct TonlibError { + static td::Status NeedMnemonicPassword() { + return td::Status::Error(400, "NEED_MNEMONIC_PASSWORD"); + } + static td::Status InvalidMnemonic() { + return td::Status::Error(400, "INVALID_MNEMONIC: Invalid mnemonic words or password (invalid checksum)"); + } + static td::Status InvalidBagOfCells(td::Slice comment) { + return td::Status::Error(400, PSLICE() << "INVALID_BAG_OF_CELLS: " << comment); + } + static td::Status InvalidPublicKey() { + return td::Status::Error(400, "INVALID_PUBLIC_KEY"); + } + static td::Status InvalidAccountAddress() { + return td::Status::Error(400, "INVALID_ACCOUNT_ADDRESS"); + } + static td::Status InvalidConfig(td::Slice reason) { + return td::Status::Error(400, PSLICE() << "INVALID_CONFIG: " << reason); + } + static td::Status InvalidPemKey() { + return td::Status::Error(400, "INVALID_PEM_KEY"); + } + static td::Status MessageTooLong() { + return td::Status::Error(400, "MESSAGE_TOO_LONG"); + } + static td::Status EmptyField(td::Slice field_name) { + return td::Status::Error(400, PSLICE() << "EMPTY_FIELD: Field " << field_name << " must not be emtpy"); + } + static td::Status InvalidField(td::Slice field_name, td::Slice reason) { + return td::Status::Error(400, PSLICE() << "INVALID_FIELD: Field " << field_name << " has invalid value " << reason); + } + static td::Status DangerousTransaction(td::Slice reason) { + return td::Status::Error(400, PSLICE() << "DANGEROUS_TRANSACTION: " << reason); + } + static td::Status AccountNotInited() { + return td::Status::Error(400, "ACCOUNT_NOT_INITED"); + } + static td::Status AccountTypeUnknown() { + return td::Status::Error(400, "ACCOUNT_TYPE_UNKNOWN"); + } + static td::Status AccountTypeUnexpected(td::Slice expected) { + return td::Status::Error(400, PSLICE() << "ACCOUNT_TYPE_UNEXPECTED: not a " << expected); + } + static td::Status Internal() { + return td::Status::Error(500, "INTERNAL"); + } + static td::Status Internal(td::Slice message) { + return td::Status::Error(500, PSLICE() << "INTERNAL: " << message); + } + static td::Status KeyUnknown() { + return td::Status::Error(500, "KEY_UNKNOWN"); + } + static td::Status KeyDecrypt() { + return td::Status::Error(500, "KEY_DECRYPT"); + } + static td::Status ValidateAccountState() { + return td::Status::Error(500, "VALIDATE_ACCOUNT_STATE"); + } + static td::Status ValidateTransactions() { + return td::Status::Error(500, "VALIDATE_TRANSACTION"); + } + static td::Status ValidateZeroState(td::Slice message) { + return td::Status::Error(500, PSLICE() << "VALIDATE_ZERO_STATE: " << message); + } + static td::Status ValidateBlockProof() { + return td::Status::Error(500, "VALIDATE_BLOCK_PROOF"); + } + static td::Status NoLiteServers() { + return td::Status::Error(500, "NO_LITE_SERVERS"); + } + static td::Status LiteServerNetwork() { + return td::Status::Error(500, "LITE_SERVER_NETWORK"); + } + static td::Status Cancelled() { + return td::Status::Error(500, "CANCELLED"); + } + static td::Status NotEnoughFunds() { + return td::Status::Error(500, "NOT_ENOUGH_FUNDS"); + } + + static td::Status LiteServer(td::int32 code, td::Slice message) { + auto f = [&](td::Slice code_description) { return LiteServer(code, code_description, message); }; + switch (ton::ErrorCode(code)) { + case ton::ErrorCode::cancelled: + return f("CANCELLED"); + case ton::ErrorCode::failure: + return f("FAILURE"); + case ton::ErrorCode::error: + return f("ERROR"); + case ton::ErrorCode::warning: + return f("WARNING"); + case ton::ErrorCode::protoviolation: + return f("PROTOVIOLATION"); + case ton::ErrorCode::timeout: + return f("TIMEOUT"); + case ton::ErrorCode::notready: + return f("NOTREADY"); + } + return f("UNKNOWN"); + } + + static td::Status LiteServer(td::int32 code, td::Slice code_description, td::Slice message) { + return td::Status::Error(500, PSLICE() << "LITE_SERVER_" << code_description << ": " << message); + } +}; +} // namespace tonlib diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/Wallet.cpp b/submodules/ton/tonlib-src/tonlib/tonlib/Wallet.cpp index 7546e8fd22..e35acfd3bc 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/Wallet.cpp +++ b/submodules/ton/tonlib-src/tonlib/tonlib/Wallet.cpp @@ -17,6 +17,7 @@ Copyright 2017-2019 Telegram Systems LLP */ #include "tonlib/Wallet.h" +#include "tonlib/CellString.h" #include "tonlib/GenericAccount.h" #include "tonlib/utils.h" @@ -26,13 +27,13 @@ #include namespace tonlib { -td::Ref Wallet::get_init_state(const td::Ed25519::PublicKey& public_key) { +td::Ref Wallet::get_init_state(const td::Ed25519::PublicKey& public_key) noexcept { auto code = get_init_code(); auto data = get_init_data(public_key); return GenericAccount::get_init_state(std::move(code), std::move(data)); } -td::Ref Wallet::get_init_message(const td::Ed25519::PrivateKey& private_key) { +td::Ref Wallet::get_init_message(const td::Ed25519::PrivateKey& private_key) noexcept { td::uint32 seqno = 0; td::uint32 valid_until = std::numeric_limits::max(); auto signature = @@ -44,8 +45,7 @@ td::Ref Wallet::get_init_message(const td::Ed25519::PrivateKey& privat td::Ref Wallet::make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 seqno, td::uint32 valid_until, td::int64 gramms, td::Slice message, - const block::StdAddress& dest_address) { - CHECK(message.size() <= 124); + const block::StdAddress& dest_address) noexcept { td::BigInt256 dest_addr; dest_addr.import_bits(dest_address.addr.as_bitslice()); vm::CellBuilder cb; @@ -54,9 +54,15 @@ td::Ref Wallet::make_a_gift_message(const td::Ed25519::PrivateKey& pri .append_cellslice(binary_bitstring_to_cellslice("b{000100}").move_as_ok()) .store_long(dest_address.workchain, 8) .store_int256(dest_addr, 256); - block::tlb::t_Grams.store_integer_value(cb, td::BigInt256(gramms)); - auto message_inner = cb.store_zeroes(9 + 64 + 32 + 1 + 1).store_bytes("\0\0\0\0", 4).store_bytes(message).finalize(); td::int8 send_mode = 3; + if (gramms == -1) { + gramms = 0; + send_mode += 128; + } + block::tlb::t_Grams.store_integer_value(cb, td::BigInt256(gramms)); + cb.store_zeroes(9 + 64 + 32 + 1 + 1).store_bytes("\0\0\0\0", 4); + vm::CellString::store(cb, message, 35 * 8).ensure(); + auto message_inner = cb.finalize(); auto message_outer = vm::CellBuilder() .store_long(seqno, 32) .store_long(valid_until, 32) @@ -68,7 +74,7 @@ td::Ref Wallet::make_a_gift_message(const td::Ed25519::PrivateKey& pri return vm::CellBuilder().store_bytes(signature).append_cellslice(vm::load_cell_slice(message_outer)).finalize(); } -td::Ref Wallet::get_init_code() { +td::Ref Wallet::get_init_code() noexcept { static auto res = [] { auto serialized_code = td::base64_decode( "te6ccgEEAQEAAAAAVwAAqv8AIN0gggFMl7qXMO1E0NcLH+Ck8mCDCNcYINMf0x8B+CO78mPtRNDTH9P/" @@ -79,11 +85,11 @@ td::Ref Wallet::get_init_code() { return res; } -vm::CellHash Wallet::get_init_code_hash() { +vm::CellHash Wallet::get_init_code_hash() noexcept { return get_init_code()->get_hash(); } -td::Ref Wallet::get_init_data(const td::Ed25519::PublicKey& public_key) { +td::Ref Wallet::get_init_data(const td::Ed25519::PublicKey& public_key) noexcept { return vm::CellBuilder().store_long(0, 32).store_bytes(public_key.as_octet_string()).finalize(); } } // namespace tonlib diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/Wallet.h b/submodules/ton/tonlib-src/tonlib/tonlib/Wallet.h index 2f2d8a8de1..dd114cce77 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/Wallet.h +++ b/submodules/ton/tonlib-src/tonlib/tonlib/Wallet.h @@ -21,18 +21,20 @@ #include "vm/cells.h" #include "Ed25519.h" #include "block/block.h" +#include "CellString.h" namespace tonlib { class Wallet { public: - static td::Ref get_init_state(const td::Ed25519::PublicKey& public_key); - static td::Ref get_init_message(const td::Ed25519::PrivateKey& private_key); + static constexpr unsigned max_message_size = vm::CellString::max_bytes; + static td::Ref get_init_state(const td::Ed25519::PublicKey& public_key) noexcept; + static td::Ref get_init_message(const td::Ed25519::PrivateKey& private_key) noexcept; static td::Ref make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 seqno, td::uint32 valid_until, td::int64 gramms, td::Slice message, - const block::StdAddress& dest_address); + const block::StdAddress& dest_address) noexcept; - static td::Ref get_init_code(); - static vm::CellHash get_init_code_hash(); - static td::Ref get_init_data(const td::Ed25519::PublicKey& public_key); + static td::Ref get_init_code() noexcept; + static vm::CellHash get_init_code_hash() noexcept; + static td::Ref get_init_data(const td::Ed25519::PublicKey& public_key) noexcept; }; } // namespace tonlib diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/keys/DecryptedKey.cpp b/submodules/ton/tonlib-src/tonlib/tonlib/keys/DecryptedKey.cpp index 3161d904c7..746ca188c0 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/keys/DecryptedKey.cpp +++ b/submodules/ton/tonlib-src/tonlib/tonlib/keys/DecryptedKey.cpp @@ -67,7 +67,8 @@ EncryptedKey DecryptedKey::encrypt(td::Slice local_password, td::Slice old_secre } td::SecureString encryption_secret(64); - pbkdf2_sha512(as_slice(decrypted_secret), "TON local key", PBKDF_ITERATIONS, encryption_secret.as_mutable_slice()); + pbkdf2_sha512(as_slice(decrypted_secret), "TON local key", EncryptedKey::PBKDF_ITERATIONS, + encryption_secret.as_mutable_slice()); std::vector mnemonic_words_copy; for (auto &w : mnemonic_words) { diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/keys/EncryptedKey.cpp b/submodules/ton/tonlib-src/tonlib/tonlib/keys/EncryptedKey.cpp index 075e89f479..143677914f 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/keys/EncryptedKey.cpp +++ b/submodules/ton/tonlib-src/tonlib/tonlib/keys/EncryptedKey.cpp @@ -25,7 +25,6 @@ namespace tonlib { td::Result EncryptedKey::decrypt(td::Slice local_password, bool check_public_key) { - LOG(ERROR) << "decrypt"; if (secret.size() != 32) { return td::Status::Error("Failed to decrypt key: invalid secret size"); } diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/keys/EncryptedKey.h b/submodules/ton/tonlib-src/tonlib/tonlib/keys/EncryptedKey.h index 5a32c9f89f..56aa661531 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/keys/EncryptedKey.h +++ b/submodules/ton/tonlib-src/tonlib/tonlib/keys/EncryptedKey.h @@ -25,9 +25,9 @@ #include namespace tonlib { -constexpr int PBKDF_ITERATIONS = 100000; struct DecryptedKey; struct EncryptedKey { + static constexpr int PBKDF_ITERATIONS = 100000; td::SecureString encrypted_data; td::Ed25519::PublicKey public_key; td::SecureString secret; diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/keys/SimpleEncryption.cpp b/submodules/ton/tonlib-src/tonlib/tonlib/keys/SimpleEncryption.cpp index 760dda36b9..026a34292e 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/keys/SimpleEncryption.cpp +++ b/submodules/ton/tonlib-src/tonlib/tonlib/keys/SimpleEncryption.cpp @@ -77,7 +77,7 @@ td::Result SimpleEncryption::decrypt_data(td::Slice encrypted_ return td::Status::Error("Failed to decrypt: data is too small"); } if (encrypted_data.size() % 16 != 0) { - return td::Status::Error("Failed to decrypt: data size is not divisible by 32"); + return td::Status::Error("Failed to decrypt: data size is not divisible by 16"); } auto data_hash = encrypted_data.substr(0, 32); encrypted_data = encrypted_data.substr(32); diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/tonlib-cli.cpp b/submodules/ton/tonlib-src/tonlib/tonlib/tonlib-cli.cpp index ce8d5f481f..a783d2aa37 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/tonlib-cli.cpp +++ b/submodules/ton/tonlib-src/tonlib/tonlib/tonlib-cli.cpp @@ -27,6 +27,7 @@ class TonlibCli : public td::actor::Actor { std::string config; std::string name; std::string key_dir{"."}; + bool in_memory{false}; bool use_callbacks_for_network{false}; bool use_simple_wallet{false}; bool ignore_cache{false}; @@ -120,7 +121,14 @@ class TonlibCli : public td::actor::Actor { ? make_object(options_.config, options_.name, options_.use_callbacks_for_network, options_.ignore_cache) : nullptr; - send_query(make_object(make_object(std::move(config), options_.key_dir)), + + tonlib_api::object_ptr ks_type; + if (options_.in_memory) { + ks_type = make_object(); + } else { + ks_type = make_object(options_.key_dir); + } + send_query(make_object(make_object(std::move(config), std::move(ks_type))), [](auto r_ok) { LOG_IF(ERROR, r_ok.is_error()) << r_ok.error(); td::TerminalIO::out() << "Tonlib is inited\n"; @@ -184,6 +192,7 @@ class TonlibCli : public td::actor::Actor { td::TerminalIO::out() << "keys - show all stored keys\n"; td::TerminalIO::out() << "unpackaddress
- validate and parse address\n"; td::TerminalIO::out() << "importkey - import key\n"; + td::TerminalIO::out() << "deletekeys - delete ALL PRIVATE KEYS\n"; td::TerminalIO::out() << "exportkey [] - export key\n"; td::TerminalIO::out() << "setconfig [] [] [] - set lite server config\n"; td::TerminalIO::out() << "getstate - get state of simple wallet with requested key\n"; @@ -205,6 +214,8 @@ class TonlibCli : public td::actor::Actor { try_stop(); } else if (cmd == "keys") { dump_keys(); + } else if (cmd == "deletekeys") { + delete_all_keys(); } else if (cmd == "exportkey") { export_key(parser.read_word()); } else if (cmd == "importkey") { @@ -407,6 +418,27 @@ class TonlibCli : public td::actor::Actor { dump_key(i); } } + void delete_all_keys() { + static td::Slice password = td::Slice("I have written down mnemonic words"); + td::TerminalIO::out() << "You are going to delete ALL PRIVATE KEYS. To confirm enter `" << password << "`\n"; + cont_ = [this](td::Slice entered) { + if (password == entered) { + this->do_delete_all_keys(); + } else { + td::TerminalIO::out() << "Your keys left intact\n"; + } + }; + } + + void do_delete_all_keys() { + send_query(tonlib_api::make_object(), [](auto r_res) { + if (r_res.is_error()) { + td::TerminalIO::out() << "Something went wrong: " << r_res.error() << "\n"; + return; + } + td::TerminalIO::out() << "All your keys have been deleted\n"; + }); + } std::string key_db_path() { return options_.key_dir + TD_DIR_SLASH + "key_db"; @@ -824,6 +856,10 @@ int main(int argc, char* argv[]) { options.key_dir = arg.str(); return td::Status::OK(); }); + p.add_option('M', "in-memory", "store keys only in-memory", [&]() { + options.in_memory = true; + return td::Status::OK(); + }); p.add_option('E', "execute", "execute one command", [&](td::Slice arg) { options.one_shot = true; options.cmd = arg.str(); diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/utils.cpp b/submodules/ton/tonlib-src/tonlib/tonlib/utils.cpp index b577faf3f0..5cef21f56d 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/utils.cpp +++ b/submodules/ton/tonlib-src/tonlib/tonlib/utils.cpp @@ -20,6 +20,10 @@ #include "td/utils/misc.h" #include "vm/cellslice.h" namespace tonlib { +int VERBOSITY_NAME(tonlib_query) = VERBOSITY_NAME(INFO); +int VERBOSITY_NAME(last_block) = VERBOSITY_NAME(INFO); +int VERBOSITY_NAME(lite_server) = VERBOSITY_NAME(INFO); + td::Result> binary_bitstring_to_cellslice(td::Slice literal) { unsigned char buff[128]; if (!begins_with(literal, "b{") || !ends_with(literal, "}")) { diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/utils.h b/submodules/ton/tonlib-src/tonlib/tonlib/utils.h index 924e86d695..840bc10d20 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/utils.h +++ b/submodules/ton/tonlib-src/tonlib/tonlib/utils.h @@ -21,6 +21,21 @@ #include "ton/ton-types.h" #include "block/block.h" #include "block/block-parse.h" + namespace tonlib { +template +auto try_f(F&& f) noexcept -> decltype(f()) { + try { + return f(); + } catch (vm::VmError error) { + return td::Status::Error(PSLICE() << "Got a vm exception: " << error.get_msg()); + } +} + +#define TRY_VM(f) try_f([&] { return f; }) + +extern int VERBOSITY_NAME(tonlib_query); +extern int VERBOSITY_NAME(last_block); +extern int VERBOSITY_NAME(lite_server); td::Result> binary_bitstring_to_cellslice(td::Slice literal); } // namespace tonlib From 9219776bf00c836cc2e876e6acf4964910657fe0 Mon Sep 17 00:00:00 2001 From: Peter <> Date: Thu, 3 Oct 2019 18:53:20 +0400 Subject: [PATCH 06/12] Enable proxy --- submodules/MtProtoKit/TON/TON.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/MtProtoKit/TON/TON.mm b/submodules/MtProtoKit/TON/TON.mm index e76a4b01c1..0936366688 100644 --- a/submodules/MtProtoKit/TON/TON.mm +++ b/submodules/MtProtoKit/TON/TON.mm @@ -325,7 +325,7 @@ typedef enum { make_object( configString.UTF8String, blockchainName.UTF8String, - false, + true, false ), make_object( From 03778764622305645250203ae2dc9f792adcff83 Mon Sep 17 00:00:00 2001 From: Peter <> Date: Thu, 3 Oct 2019 19:12:34 +0400 Subject: [PATCH 07/12] Enable timout --- submodules/MtProtoKit/MTBackupAddressSignals.m | 7 ++----- submodules/TelegramCore/TelegramCore/Wallets.swift | 5 ++++- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/submodules/MtProtoKit/MTBackupAddressSignals.m b/submodules/MtProtoKit/MTBackupAddressSignals.m index e71cafdf18..e61432f0c0 100644 --- a/submodules/MtProtoKit/MTBackupAddressSignals.m +++ b/submodules/MtProtoKit/MTBackupAddressSignals.m @@ -297,12 +297,9 @@ static NSString *makeRandomPadding() { + (MTSignal * _Nonnull)fetchBackupIps:(bool)isTestingEnvironment currentContext:(MTContext * _Nonnull)currentContext additionalSource:(MTSignal * _Nullable)additionalSource phoneNumber:(NSString * _Nullable)phoneNumber { NSMutableArray *signals = [[NSMutableArray alloc] init]; - //[signals addObject:[self fetchBackupIpsResolveGoogle:isTestingEnvironment phoneNumber:phoneNumber currentContext:currentContext addressOverride:currentContext.apiEnvironment.accessHostOverride]]; - //[signals addObject:[self fetchBackupIpsResolveCloudflare:isTestingEnvironment phoneNumber:phoneNumber currentContext:currentContext addressOverride:currentContext.apiEnvironment.accessHostOverride]]; + [signals addObject:[self fetchBackupIpsResolveGoogle:isTestingEnvironment phoneNumber:phoneNumber currentContext:currentContext addressOverride:currentContext.apiEnvironment.accessHostOverride]]; + [signals addObject:[self fetchBackupIpsResolveCloudflare:isTestingEnvironment phoneNumber:phoneNumber currentContext:currentContext addressOverride:currentContext.apiEnvironment.accessHostOverride]]; if (additionalSource != nil) { -/*#if DEBUG - [signals removeAllObjects]; -#endif*/ [signals addObject:[additionalSource mapToSignal:^MTSignal *(MTBackupDatacenterData *datacenterData) { if (![datacenterData isKindOfClass:[MTBackupDatacenterData class]]) { return [MTSignal complete]; diff --git a/submodules/TelegramCore/TelegramCore/Wallets.swift b/submodules/TelegramCore/TelegramCore/Wallets.swift index 163856e8bd..fbbc3ceffd 100644 --- a/submodules/TelegramCore/TelegramCore/Wallets.swift +++ b/submodules/TelegramCore/TelegramCore/Wallets.swift @@ -66,7 +66,10 @@ private final class TonInstanceImpl { } else { let network = self.network instance = TON(keystoreDirectory: self.basePath + "/ton-keystore", config: self.config, blockchainName: self.blockchainName, performExternalRequest: { request in - let _ = (network.request(Api.functions.wallet.sendLiteRequest(body: Buffer(data: request.data)))).start(next: { result in + let _ = ( + network.request(Api.functions.wallet.sendLiteRequest(body: Buffer(data: request.data))) + |> timeout(10.0, queue: .concurrentDefaultQueue(), alternate: .fail(MTRpcError(errorCode: 500, errorDescription: "NETWORK_ERROR"))) + ).start(next: { result in switch result { case let .liteResponse(response): request.onResult(response.makeData(), nil) From 345627b5497cd9b194294916eb22971522e15db9 Mon Sep 17 00:00:00 2001 From: Peter <> Date: Thu, 3 Oct 2019 22:07:46 +0400 Subject: [PATCH 08/12] Fixed visual issues --- submodules/ContextUI/Sources/ContextController.swift | 6 +----- .../Display/Navigation/NavigationContainer.swift | 4 +++- .../Display/Navigation/NavigationModalContainer.swift | 9 ++++++++- .../Navigation/NavigationOverlayContainer.swift | 10 +++++++++- .../Sources/TabBarAccountSwitchController.swift | 2 +- submodules/WalletUI/Sources/WalletSplashScreen.swift | 2 +- 6 files changed, 23 insertions(+), 10 deletions(-) diff --git a/submodules/ContextUI/Sources/ContextController.swift b/submodules/ContextUI/Sources/ContextController.swift index 444aa04be6..3208dee1e5 100644 --- a/submodules/ContextUI/Sources/ContextController.swift +++ b/submodules/ContextUI/Sources/ContextController.swift @@ -1234,11 +1234,7 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi case let .controller(controller): let controllerPoint = self.view.convert(point, to: controller.controller.view) if let result = controller.controller.view.hitTest(controllerPoint, with: event) { - if result is UIScrollView { - return result - } else if result is ListViewBackingView { - return result - } + return result } } } diff --git a/submodules/Display/Display/Navigation/NavigationContainer.swift b/submodules/Display/Display/Navigation/NavigationContainer.swift index 975497b759..adfeb6129c 100644 --- a/submodules/Display/Display/Navigation/NavigationContainer.swift +++ b/submodules/Display/Display/Navigation/NavigationContainer.swift @@ -320,7 +320,9 @@ final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelegate { if let top = self.state.top { var updatedLayout = layout if let topTransition = self.state.transition, top.value.view.disableAutomaticKeyboardHandling.isEmpty { - updatedLayout = updatedLayout.withUpdatedInputHeight(nil) + if !viewTreeContainsFirstResponder(view: top.value.view) { + updatedLayout = updatedLayout.withUpdatedInputHeight(nil) + } } self.applyLayout(layout: updatedLayout, to: top, isMaster: true, transition: transition) updatedStatusBarStyle = top.value.statusBar.statusBarStyle diff --git a/submodules/Display/Display/Navigation/NavigationModalContainer.swift b/submodules/Display/Display/Navigation/NavigationModalContainer.swift index 3cfcab03f7..ab2e1567b4 100644 --- a/submodules/Display/Display/Navigation/NavigationModalContainer.swift +++ b/submodules/Display/Display/Navigation/NavigationModalContainer.swift @@ -18,6 +18,7 @@ final class NavigationModalContainer: ASDisplayNode, UIScrollViewDelegate, UIGes var updateDismissProgress: ((CGFloat, ContainedViewLayoutTransition) -> Void)? var interactivelyDismissed: ((Bool) -> Void)? + private var isUpdatingState = false private var ignoreScrolling = false private var isDismissed = false private var isInteractiveDimissEnabled = true @@ -63,7 +64,9 @@ final class NavigationModalContainer: ASDisplayNode, UIScrollViewDelegate, UIGes } if !strongSelf.isReady { strongSelf.isReady = true - strongSelf.isReadyUpdated?() + if !strongSelf.isUpdatingState { + strongSelf.isReadyUpdated?() + } } } @@ -282,6 +285,8 @@ final class NavigationModalContainer: ASDisplayNode, UIScrollViewDelegate, UIGes return } + self.isUpdatingState = true + self.validLayout = layout transition.updateFrame(node: self.dim, frame: CGRect(origin: CGPoint(), size: layout.size)) @@ -347,6 +352,8 @@ final class NavigationModalContainer: ASDisplayNode, UIScrollViewDelegate, UIGes transition.updateFrameAsPositionAndBounds(node: self.container, frame: containerFrame.offsetBy(dx: 0.0, dy: layout.size.height)) transition.updateTransformScale(node: self.container, scale: containerScale) self.container.update(layout: containerLayout, canBeClosed: true, controllers: controllers, transition: transition) + + self.isUpdatingState = false } func animateIn(transition: ContainedViewLayoutTransition) { diff --git a/submodules/Display/Display/Navigation/NavigationOverlayContainer.swift b/submodules/Display/Display/Navigation/NavigationOverlayContainer.swift index 608a999b24..4689df4688 100644 --- a/submodules/Display/Display/Navigation/NavigationOverlayContainer.swift +++ b/submodules/Display/Display/Navigation/NavigationOverlayContainer.swift @@ -12,6 +12,8 @@ final class NavigationOverlayContainer: ASDisplayNode { private var validLayout: ContainerViewLayout? + private var isUpdatingState: Bool = false + var keyboardViewManager: KeyboardViewManager? { didSet { if self.keyboardViewManager !== oldValue { @@ -44,7 +46,9 @@ final class NavigationOverlayContainer: ASDisplayNode { } if !strongSelf.isReady { strongSelf.isReady = true - strongSelf.isReadyUpdated?() + if !strongSelf.isUpdatingState { + strongSelf.isReadyUpdated?() + } } }) } @@ -58,6 +62,8 @@ final class NavigationOverlayContainer: ASDisplayNode { } func update(layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { + self.isUpdatingState = true + let updateLayout = self.validLayout != layout self.validLayout = layout @@ -66,6 +72,8 @@ final class NavigationOverlayContainer: ASDisplayNode { transition.updateFrame(node: self.controller.displayNode, frame: CGRect(origin: CGPoint(), size: layout.size)) self.controller.containerLayoutUpdated(layout, transition: transition) } + + self.isUpdatingState = false } func transitionIn() { diff --git a/submodules/SettingsUI/Sources/TabBarAccountSwitchController.swift b/submodules/SettingsUI/Sources/TabBarAccountSwitchController.swift index ead8fcfb44..6c3beaa573 100644 --- a/submodules/SettingsUI/Sources/TabBarAccountSwitchController.swift +++ b/submodules/SettingsUI/Sources/TabBarAccountSwitchController.swift @@ -43,7 +43,7 @@ public final class TabBarAccountSwitchController: ViewController { super.init(navigationBarPresentationData: nil) - self.statusBar.statusBarStyle = .Hide + self.statusBar.statusBarStyle = .Ignore self.statusBar.ignoreInCall = true self.lockOrientation = true diff --git a/submodules/WalletUI/Sources/WalletSplashScreen.swift b/submodules/WalletUI/Sources/WalletSplashScreen.swift index a93b8fee3f..7deb6f3b90 100644 --- a/submodules/WalletUI/Sources/WalletSplashScreen.swift +++ b/submodules/WalletUI/Sources/WalletSplashScreen.swift @@ -93,7 +93,7 @@ public final class WalletSplashScreen: ViewController { guard let strongSelf = self else { return } - strongSelf.sendGrams(walletInfo: walletInfo, decryptedSecret: decryptedSecret, address: address, amount: amount, textMessage: textMessage, forceIfDestinationNotInitialized: false, randomId: randomId, serverSalt: serverSalt) + strongSelf.sendGrams(walletInfo: walletInfo, decryptedSecret: decryptedSecret, address: address, amount: amount, textMessage: textMessage, forceIfDestinationNotInitialized: true, randomId: randomId, serverSalt: serverSalt) }, error: { [weak self] error in guard let strongSelf = self else { return From 6868b8aa897cf15220e7b66358c2adf82986f12e Mon Sep 17 00:00:00 2001 From: Peter <> Date: Thu, 3 Oct 2019 22:25:27 +0400 Subject: [PATCH 09/12] Properly filter active sessions --- .../TelegramCore/TelegramCore/ActiveSessionsContext.swift | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/submodules/TelegramCore/TelegramCore/ActiveSessionsContext.swift b/submodules/TelegramCore/TelegramCore/ActiveSessionsContext.swift index 3efaf2cfe0..b71f867c9b 100644 --- a/submodules/TelegramCore/TelegramCore/ActiveSessionsContext.swift +++ b/submodules/TelegramCore/TelegramCore/ActiveSessionsContext.swift @@ -100,13 +100,7 @@ public final class ActiveSessionsContext { return .complete() } - var mergedSessions = strongSelf._state.sessions - for i in (0 ..< mergedSessions.count).reversed() { - if mergedSessions[i].hash != 0 { - mergedSessions.remove(at: i) - break - } - } + let mergedSessions = strongSelf._state.sessions.filter({ $0.hash == 0 }) strongSelf._state = ActiveSessionsContextState(isLoadingMore: strongSelf._state.isLoadingMore, sessions: mergedSessions) return .complete() From a2d96858ded2b7f2f61f482c9bea5767982ee5e7 Mon Sep 17 00:00:00 2001 From: Peter <> Date: Thu, 3 Oct 2019 23:13:50 +0400 Subject: [PATCH 10/12] UI fixes --- submodules/Display/Display/WindowContent.swift | 8 ++++++-- .../Wallet/RefreshIcon.imageset/Contents.json | 2 +- .../RefreshIcon.imageset/ic_walletupdate.pdf | Bin 0 -> 4496 bytes .../Wallet/RefreshIcon.imageset/ô€Š¯ 2.pdf | Bin 171124 -> 0 bytes .../WalletUI/Sources/WalletInfoScreen.swift | 6 +++++- .../WalletUI/Sources/WalletRefreshNode.swift | 4 ++-- 6 files changed, 14 insertions(+), 6 deletions(-) create mode 100644 submodules/TelegramUI/Images.xcassets/Wallet/RefreshIcon.imageset/ic_walletupdate.pdf delete mode 100644 submodules/TelegramUI/Images.xcassets/Wallet/RefreshIcon.imageset/ô€Š¯ 2.pdf diff --git a/submodules/Display/Display/WindowContent.swift b/submodules/Display/Display/WindowContent.swift index 39381f69eb..92985f27db 100644 --- a/submodules/Display/Display/WindowContent.swift +++ b/submodules/Display/Display/WindowContent.swift @@ -493,10 +493,12 @@ public class Window1 { portraitLayoutSize = CGSize(width: portraitLayoutSize.height, height: portraitLayoutSize.width) } if abs(strongSelf.windowLayout.size.height - UIScreen.main.bounds.height) > 41.0 { - screenHeight = UIScreen.main.bounds.height if abs(portraitLayoutSize.height - portraitScreenSize.height) > 41.0 || abs(portraitLayoutSize.width - portraitScreenSize.width) > 41.0 { popoverDelta = 48.0 inPopover = true + screenHeight = strongSelf.windowLayout.size.height + } else { + screenHeight = UIScreen.main.bounds.height } } else if abs(strongSelf.windowLayout.size.height - UIScreen.main.bounds.height) > 39.0 { screenHeight = UIScreen.main.bounds.height @@ -518,7 +520,9 @@ public class Window1 { keyboardHeight = max(0.0, screenHeight - keyboardFrame.minY) if inPopover { if strongSelf.windowLayout.onScreenNavigationHeight != nil { - keyboardHeight = max(0.0, keyboardHeight - popoverDelta / 2.0) + if !keyboardHeight.isZero { + keyboardHeight = max(0.0, keyboardHeight + popoverDelta / 2.0) + } } else { keyboardHeight = max(0.0, keyboardHeight - popoverDelta) } diff --git a/submodules/TelegramUI/Images.xcassets/Wallet/RefreshIcon.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Wallet/RefreshIcon.imageset/Contents.json index f35b36343a..0940c4ae6d 100644 --- a/submodules/TelegramUI/Images.xcassets/Wallet/RefreshIcon.imageset/Contents.json +++ b/submodules/TelegramUI/Images.xcassets/Wallet/RefreshIcon.imageset/Contents.json @@ -2,7 +2,7 @@ "images" : [ { "idiom" : "universal", - "filename" : "ô€Š¯ 2.pdf" + "filename" : "ic_walletupdate.pdf" } ], "info" : { diff --git a/submodules/TelegramUI/Images.xcassets/Wallet/RefreshIcon.imageset/ic_walletupdate.pdf b/submodules/TelegramUI/Images.xcassets/Wallet/RefreshIcon.imageset/ic_walletupdate.pdf new file mode 100644 index 0000000000000000000000000000000000000000..62702732c78409d1aa67893613b84c2b194d7d51 GIT binary patch literal 4496 zcmai&2T&7h*T-oJ1f*OkQj`U$7D%Niy@g&y3DponFB(EO6s266NHc;WO}Z4NN(U(- zNJIn#1&lQ5ph!o);MMPX@B7ZYJ3HCU|2cc+?344K`JIRuscW8xNWwrO?bBbT7xKSm zzHaXX!2vMfY3Blxmj|TuupW+hCjdc_OaLiOXE!_+N4dJ8@mO^%#?u}PC@O-y@Hi~m z9pp!CmaOj~EW;eW=?yBWFj9}^DE#)IrIhP3#8em@IWKGz(IG{j*I6~ zF}6mupHRZNRME~8*n8{MrL)5AlbR9!A%2BRweo4P%S3b1hVe?(jirdib~1G~MprPP zSTna$a%syTRa1Tev*TWN8hiZ7jULweMYI=6I+d{UL9=wsEdOFt&dRDVaUCvr(=;gVwXlJ0atPjvA)iBjm@((sQLeVk z%X`FI(3K%1Bzr}$LswVoJ>3)+@8TF;yf6FxoP=I1=4 zs9$tc#>Q%L#vr$6%WhG!cj4jdAwYo>x6a1%g~9fiB6n5ziKeWsSEC18mTun{;x`N@ zbB4cr1b^QWZS&=uJ=m8m$MHPcanl)zWxoA^At_KOuEVQRpl1K;{&-MzO)&LcWqyAU z*2Dg1e^c%bZE@&@!>bGwakzMR3;oS8m;A3`0VyN2y%0Msz?+L&oOH%f+95_X5n-Y}>PIv=*d;F8UuvO7MhamxIGAqTv>Rsp z!e-RjYOJm?Jr?WAxKe`nI-a)Qg_;QQ-{E_%sG}9TCM&# z-qXHGbApYU#hki@?BGC$+)}4`yVt0Ynp&XMS+TJ!8Dd}m{#>(>sMpXzaDtGGn($F7 zkj9|2e2^&jG)=N;MF$V`fbQjbiUc$Q0_DnL%zi91*y!WV(<7}{ zGT#Pshm?8V)u0wZxu-fMES2ytEun^HoVJ@sCQb#J?kl_q*fm=dT_inJiG7Hga9eyV z)yPG)A#8E~WJObo8C9kGQRQj!W5X4I>dO(T%JBzZPer)dB({HI7GsK8Ty*oI&Ty4H z`∋!}Et&TKHp+v7yC&++6; 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%0AbD+ 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 znES�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
      6)0s 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 diff --git a/submodules/WalletUI/Sources/WalletInfoScreen.swift b/submodules/WalletUI/Sources/WalletInfoScreen.swift index 449a5c0fdd..dbce13d1a5 100644 --- a/submodules/WalletUI/Sources/WalletInfoScreen.swift +++ b/submodules/WalletUI/Sources/WalletInfoScreen.swift @@ -692,6 +692,7 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode { return } let combinedState: CombinedWalletState? + var isUpdated = false switch value { case let .cached(state): if strongSelf.combinedState != nil { @@ -705,6 +706,7 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode { } combinedState = state case let .updated(state): + isUpdated = true strongSelf.loadingIndicator.stopAnimating() strongSelf.loadingIndicator.isHidden = true combinedState = state @@ -729,7 +731,9 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode { strongSelf.transactionsLoaded(isReload: true, transactions: combinedState.topTransactions) - strongSelf.headerNode.isRefreshing = false + if isUpdated { + strongSelf.headerNode.isRefreshing = false + } if strongSelf.isReady, let (layout, navigationHeight) = strongSelf.validLayout { strongSelf.headerNode.update(size: strongSelf.headerNode.bounds.size, navigationHeight: navigationHeight, offset: strongSelf.listOffset ?? 0.0, transition: .animated(duration: 0.2, curve: .easeInOut), isScrolling: false) diff --git a/submodules/WalletUI/Sources/WalletRefreshNode.swift b/submodules/WalletUI/Sources/WalletRefreshNode.swift index 3337601153..333bb3775b 100644 --- a/submodules/WalletUI/Sources/WalletRefreshNode.swift +++ b/submodules/WalletUI/Sources/WalletRefreshNode.swift @@ -83,7 +83,7 @@ final class WalletRefreshNode: ASDisplayNode { self.iconNode = ASImageNode() self.iconNode.displaysAsynchronously = false self.iconNode.displayWithoutProcessing = true - self.iconNode.image = UIImage(bundleImageName: "Wallet/RefreshIcon") + self.iconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Wallet/RefreshIcon"), color: UIColor(white: 0.6, alpha: 1.0)) if let image = self.iconNode.image { self.iconNode.frame = CGRect(origin: CGPoint(), size: image.size) } @@ -199,7 +199,7 @@ final class WalletRefreshNode: ASDisplayNode { let iconSize = self.iconNode.image?.size ?? CGSize(width: 20.0, height: 20.0) let titleSize = self.titleNode.updateLayout(CGSize(width: 200.0, height: 100.0)) - let iconSpacing: CGFloat = 5.0 + let iconSpacing: CGFloat = 1.0 let contentWidth = iconSize.width + titleSize.width + iconSpacing let contentOrigin = floor(-contentWidth / 2.0) From 1cf14df907d40033dbef4cadfdf8f1f473358134 Mon Sep 17 00:00:00 2001 From: Peter <> Date: Thu, 3 Oct 2019 23:56:32 +0400 Subject: [PATCH 11/12] Remove debugging --- submodules/TelegramCore/TelegramCore/Network.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/TelegramCore/TelegramCore/Network.swift b/submodules/TelegramCore/TelegramCore/Network.swift index 0ca9734570..e4626eb5b5 100644 --- a/submodules/TelegramCore/TelegramCore/Network.swift +++ b/submodules/TelegramCore/TelegramCore/Network.swift @@ -503,7 +503,7 @@ func initializedNetwork(arguments: NetworkInitializationArguments, supplementary context.setDiscoverBackupAddressListSignal(MTBackupAddressSignals.fetchBackupIps(testingEnvironment, currentContext: context, additionalSource: wrappedAdditionalSource, phoneNumber: phoneNumber)) #if DEBUG - let _ = MTBackupAddressSignals.fetchBackupIps(testingEnvironment, currentContext: context, additionalSource: wrappedAdditionalSource, phoneNumber: phoneNumber).start(next: nil) + //let _ = MTBackupAddressSignals.fetchBackupIps(testingEnvironment, currentContext: context, additionalSource: wrappedAdditionalSource, phoneNumber: phoneNumber).start(next: nil) #endif let mtProto = MTProto(context: context, datacenterId: datacenterId, usageCalculationInfo: usageCalculationInfo(basePath: basePath, category: nil))! From f21bdec23f5bfff5c8096900f49abc0326a09dd3 Mon Sep 17 00:00:00 2001 From: Peter <> Date: Fri, 4 Oct 2019 01:36:52 +0400 Subject: [PATCH 12/12] UI fixes --- .../Display/ContextMenuController.swift | 2 + .../TGModernGalleryController.m | 2 +- .../TGPhotoEditorController.m | 4 +- .../TelegramCore/TelegramCore/Wallets.swift | 209 ++++++------------ .../Sources/WalletSettingsScreen.swift | 18 +- .../WalletUI/Sources/WalletSplashScreen.swift | 86 +++++-- .../Sources/WalletWordCheckScreen.swift | 58 +++-- 7 files changed, 177 insertions(+), 202 deletions(-) diff --git a/submodules/Display/Display/ContextMenuController.swift b/submodules/Display/Display/ContextMenuController.swift index 20e0b73e49..5e703f0f98 100644 --- a/submodules/Display/Display/ContextMenuController.swift +++ b/submodules/Display/Display/ContextMenuController.swift @@ -38,6 +38,8 @@ public final class ContextMenuController: ViewController, KeyShortcutResponder, self.hasHapticFeedback = hasHapticFeedback super.init(navigationBarPresentationData: nil) + + self.statusBar.statusBarStyle = .Ignore } required public init(coder aDecoder: NSCoder) { diff --git a/submodules/LegacyComponents/LegacyComponents/TGModernGalleryController.m b/submodules/LegacyComponents/LegacyComponents/TGModernGalleryController.m index 652f3fb09b..ec597512c5 100644 --- a/submodules/LegacyComponents/LegacyComponents/TGModernGalleryController.m +++ b/submodules/LegacyComponents/LegacyComponents/TGModernGalleryController.m @@ -535,7 +535,7 @@ { [UIView animateWithDuration:0.2 animations:^ { - [strongSelf->_context setApplicationStatusBarAlpha:1.0f]; + //[strongSelf->_context setApplicationStatusBarAlpha:1.0f]; }]; } diff --git a/submodules/LegacyComponents/LegacyComponents/TGPhotoEditorController.m b/submodules/LegacyComponents/LegacyComponents/TGPhotoEditorController.m index ba3da96b98..ecab32e66d 100644 --- a/submodules/LegacyComponents/LegacyComponents/TGPhotoEditorController.m +++ b/submodules/LegacyComponents/LegacyComponents/TGPhotoEditorController.m @@ -475,12 +475,12 @@ { [UIView animateWithDuration:0.3 animations:^ { - [_context setApplicationStatusBarAlpha:1.0f]; + //[_context setApplicationStatusBarAlpha:1.0f]; }]; } else { - [_context setApplicationStatusBarAlpha:1.0f]; + //[_context setApplicationStatusBarAlpha:1.0f]; } } diff --git a/submodules/TelegramCore/TelegramCore/Wallets.swift b/submodules/TelegramCore/TelegramCore/Wallets.swift index fbbc3ceffd..d5cbeaad88 100644 --- a/submodules/TelegramCore/TelegramCore/Wallets.swift +++ b/submodules/TelegramCore/TelegramCore/Wallets.swift @@ -96,13 +96,13 @@ public final class TonInstance { }) } - fileprivate func exportKey(key: TONKey, serverSalt: Data) -> Signal<[String], NoError> { + fileprivate func exportKey(key: TONKey, localPassword: Data) -> Signal<[String], NoError> { return Signal { subscriber in let disposable = MetaDisposable() self.impl.with { impl in impl.withInstance { ton in - let cancel = ton.export(key, localPassword: serverSalt).start(next: { wordList in + let cancel = ton.export(key, localPassword: localPassword).start(next: { wordList in guard let wordList = wordList as? [String] else { assertionFailure() return @@ -120,18 +120,18 @@ public final class TonInstance { } } - fileprivate func createWallet(keychain: TonKeychain, serverSalt: Data) -> Signal<(WalletInfo, [String]), CreateWalletError> { + fileprivate func createWallet(keychain: TonKeychain, localPassword: Data) -> Signal<(WalletInfo, [String]), CreateWalletError> { return Signal { subscriber in let disposable = MetaDisposable() self.impl.with { impl in impl.withInstance { ton in - let cancel = ton.createKey(withLocalPassword: serverSalt, mnemonicPassword: Data()).start(next: { key in + let cancel = ton.createKey(withLocalPassword: localPassword, mnemonicPassword: Data()).start(next: { key in guard let key = key as? TONKey else { assertionFailure() return } let cancel = keychain.encrypt(key.secret).start(next: { encryptedSecretData in - let _ = self.exportKey(key: key, serverSalt: serverSalt).start(next: { wordList in + let _ = self.exportKey(key: key, localPassword: localPassword).start(next: { wordList in subscriber.putNext((WalletInfo(publicKey: WalletPublicKey(rawValue: key.publicKey), encryptedSecret: encryptedSecretData), wordList)) subscriber.putCompletion() }, error: { error in @@ -154,13 +154,13 @@ public final class TonInstance { } } - fileprivate func importWallet(keychain: TonKeychain, wordList: [String], serverSalt: Data) -> Signal { + fileprivate func importWallet(keychain: TonKeychain, wordList: [String], localPassword: Data) -> Signal { return Signal { subscriber in let disposable = MetaDisposable() self.impl.with { impl in impl.withInstance { ton in - let cancel = ton.importKey(withLocalPassword: serverSalt, mnemonicPassword: Data(), wordList: wordList).start(next: { key in + let cancel = ton.importKey(withLocalPassword: localPassword, mnemonicPassword: Data(), wordList: wordList).start(next: { key in guard let key = key as? TONKey else { subscriber.putError(.generic) return @@ -322,14 +322,14 @@ public final class TonInstance { } } - fileprivate func sendGramsFromWallet(decryptedSecret: Data, serverSalt: Data, walletInfo: WalletInfo, fromAddress: String, toAddress: String, amount: Int64, textMessage: String, forceIfDestinationNotInitialized: Bool, timeout: Int32, randomId: Int64) -> Signal { + fileprivate func sendGramsFromWallet(decryptedSecret: Data, localPassword: Data, walletInfo: WalletInfo, fromAddress: String, toAddress: String, amount: Int64, textMessage: String, forceIfDestinationNotInitialized: Bool, timeout: Int32, randomId: Int64) -> Signal { let key = TONKey(publicKey: walletInfo.publicKey.rawValue, secret: decryptedSecret) return Signal { subscriber in let disposable = MetaDisposable() self.impl.with { impl in impl.withInstance { ton in - let cancel = ton.sendGrams(from: key, localPassword: serverSalt, fromAddress: fromAddress, toAddress: toAddress, amount: amount, textMessage: textMessage, forceIfDestinationNotInitialized: forceIfDestinationNotInitialized, timeout: timeout, randomId: randomId).start(next: { result in + let cancel = ton.sendGrams(from: key, localPassword: localPassword, fromAddress: fromAddress, toAddress: toAddress, amount: amount, textMessage: textMessage, forceIfDestinationNotInitialized: forceIfDestinationNotInitialized, timeout: timeout, randomId: randomId).start(next: { result in guard let result = result as? TONSendGramsResult else { subscriber.putError(.generic) return @@ -366,36 +366,30 @@ public final class TonInstance { } } - fileprivate func walletRestoreWords(walletInfo: WalletInfo, keychain: TonKeychain, serverSalt: Data) -> Signal<[String], WalletRestoreWordsError> { - return keychain.decrypt(walletInfo.encryptedSecret) - |> mapError { error -> WalletRestoreWordsError in - return .secretDecryptionFailed(error) - } - |> mapToSignal { decryptedSecret -> Signal<[String], WalletRestoreWordsError> in - return Signal { subscriber in - let disposable = MetaDisposable() - - self.impl.with { impl in - impl.withInstance { ton in - let cancel = ton.export(TONKey(publicKey: walletInfo.publicKey.rawValue, secret: decryptedSecret), localPassword: serverSalt).start(next: { wordList in - guard let wordList = wordList as? [String] else { - subscriber.putError(.generic) - return - } - subscriber.putNext(wordList) - }, error: { _ in + fileprivate func walletRestoreWords(publicKey: WalletPublicKey, decryptedSecret: Data, localPassword: Data) -> Signal<[String], WalletRestoreWordsError> { + return Signal { subscriber in + let disposable = MetaDisposable() + + self.impl.with { impl in + impl.withInstance { ton in + let cancel = ton.export(TONKey(publicKey: publicKey.rawValue, secret: decryptedSecret), localPassword: localPassword).start(next: { wordList in + guard let wordList = wordList as? [String] else { subscriber.putError(.generic) - }, completed: { - subscriber.putCompletion() - }) - disposable.set(ActionDisposable { - cancel?.dispose() - }) - } + return + } + subscriber.putNext(wordList) + }, error: { _ in + subscriber.putError(.generic) + }, completed: { + subscriber.putCompletion() + }) + disposable.set(ActionDisposable { + cancel?.dispose() + }) } - - return disposable } + + return disposable } } @@ -421,35 +415,6 @@ public final class TonInstance { return disposable } } - - fileprivate func deleteLocalWalletData(walletInfo: WalletInfo, keychain: TonKeychain, serverSalt: Data) -> Signal { - return keychain.decrypt(walletInfo.encryptedSecret) - |> mapError { error -> DeleteLocalWalletDataError in - return .secretDecryptionFailed(error) - } - |> mapToSignal { decryptedSecret -> Signal in - return Signal { subscriber in - let disposable = MetaDisposable() - - self.impl.with { impl in - impl.withInstance { ton in - let cancel = ton.delete(TONKey(publicKey: walletInfo.publicKey.rawValue, secret: decryptedSecret)).start(next: { _ in - assertionFailure() - }, error: { _ in - subscriber.putError(.generic) - }, completed: { - subscriber.putCompletion() - }) - disposable.set(ActionDisposable { - cancel?.dispose() - }) - } - } - - return disposable - } - } - } } public struct WalletPublicKey: Codable, Hashable { @@ -567,24 +532,18 @@ public enum CreateWalletError { case generic } -public func createWallet(postbox: Postbox, network: Network, tonInstance: TonInstance, keychain: TonKeychain) -> Signal<(WalletInfo, [String]), CreateWalletError> { - return getServerWalletSalt(network: network) - |> mapError { _ -> CreateWalletError in - return .generic - } - |> mapToSignal { serverSalt -> Signal<(WalletInfo, [String]), CreateWalletError> in - return tonInstance.createWallet(keychain: keychain, serverSalt: serverSalt) - |> mapToSignal { walletInfo, wordList -> Signal<(WalletInfo, [String]), CreateWalletError> in - return postbox.transaction { transaction -> (WalletInfo, [String]) in - transaction.updatePreferencesEntry(key: PreferencesKeys.walletCollection, { current in - var walletCollection = (current as? WalletCollection) ?? WalletCollection(wallets: []) - walletCollection.wallets = [WalletStateRecord(info: walletInfo, exportCompleted: false, state: nil)] - return walletCollection - }) - return (walletInfo, wordList) - } - |> castError(CreateWalletError.self) +public func createWallet(postbox: Postbox, tonInstance: TonInstance, keychain: TonKeychain, localPassword: Data) -> Signal<(WalletInfo, [String]), CreateWalletError> { + return tonInstance.createWallet(keychain: keychain, localPassword: localPassword) + |> mapToSignal { walletInfo, wordList -> Signal<(WalletInfo, [String]), CreateWalletError> in + return postbox.transaction { transaction -> (WalletInfo, [String]) in + transaction.updatePreferencesEntry(key: PreferencesKeys.walletCollection, { current in + var walletCollection = (current as? WalletCollection) ?? WalletCollection(wallets: []) + walletCollection.wallets = [WalletStateRecord(info: walletInfo, exportCompleted: false, state: nil)] + return walletCollection + }) + return (walletInfo, wordList) } + |> castError(CreateWalletError.self) } } @@ -611,30 +570,24 @@ public enum ImportWalletError { case generic } -public func importWallet(postbox: Postbox, network: Network, tonInstance: TonInstance, keychain: TonKeychain, wordList: [String]) -> Signal { - return getServerWalletSalt(network: network) - |> mapError { _ -> ImportWalletError in - return .generic +public func importWallet(postbox: Postbox, tonInstance: TonInstance, keychain: TonKeychain, wordList: [String], localPassword: Data) -> Signal { + return tonInstance.importWallet(keychain: keychain, wordList: wordList, localPassword: localPassword) + |> `catch` { error -> Signal in + switch error { + case .generic: + return .fail(.generic) + } } - |> mapToSignal { serverSalt in - return tonInstance.importWallet(keychain: keychain, wordList: wordList, serverSalt: serverSalt) - |> `catch` { error -> Signal in - switch error { - case .generic: - return .fail(.generic) - } - } - |> mapToSignal { walletInfo -> Signal in - return postbox.transaction { transaction -> WalletInfo in - transaction.updatePreferencesEntry(key: PreferencesKeys.walletCollection, { current in - var walletCollection = (current as? WalletCollection) ?? WalletCollection(wallets: []) - walletCollection.wallets = [WalletStateRecord(info: walletInfo, exportCompleted: true, state: nil)] - return walletCollection - }) - return walletInfo - } - |> castError(ImportWalletError.self) + |> mapToSignal { walletInfo -> Signal in + return postbox.transaction { transaction -> WalletInfo in + transaction.updatePreferencesEntry(key: PreferencesKeys.walletCollection, { current in + var walletCollection = (current as? WalletCollection) ?? WalletCollection(wallets: []) + walletCollection.wallets = [WalletStateRecord(info: walletInfo, exportCompleted: true, state: nil)] + return walletCollection + }) + return walletInfo } + |> castError(ImportWalletError.self) } } @@ -647,7 +600,7 @@ public func deleteAllLocalWalletsData(postbox: Postbox, network: Network, tonIns |> then( postbox.transaction { transaction -> Void in transaction.updatePreferencesEntry(key: PreferencesKeys.walletCollection, { current in - let walletCollection = (current as? WalletCollection) ?? WalletCollection(wallets: []) + let walletCollection = WalletCollection(wallets: []) return walletCollection }) } @@ -656,50 +609,12 @@ public func deleteAllLocalWalletsData(postbox: Postbox, network: Network, tonIns ) } -public enum DeleteLocalWalletDataError { - case generic - case secretDecryptionFailed(TonKeychainDecryptDataError) -} - -public func deleteLocalWalletData(postbox: Postbox, network: Network, tonInstance: TonInstance, keychain: TonKeychain, walletInfo: WalletInfo) -> Signal { - return getServerWalletSalt(network: network) - |> mapError { _ -> DeleteLocalWalletDataError in - return .generic - } - |> mapToSignal { serverSalt -> Signal in - return tonInstance.deleteLocalWalletData(walletInfo: walletInfo, keychain: keychain, serverSalt: serverSalt) - |> then( - postbox.transaction { transaction -> Void in - transaction.updatePreferencesEntry(key: PreferencesKeys.walletCollection, { current in - var walletCollection = (current as? WalletCollection) ?? WalletCollection(wallets: []) - for i in 0 ..< walletCollection.wallets.count { - if walletCollection.wallets[i].info.publicKey == walletInfo.publicKey { - walletCollection.wallets.remove(at: i) - break - } - } - return walletCollection - }) - } - |> castError(DeleteLocalWalletDataError.self) - |> ignoreValues - ) - } -} - public enum WalletRestoreWordsError { case generic - case secretDecryptionFailed(TonKeychainDecryptDataError) } -public func walletRestoreWords(network: Network, walletInfo: WalletInfo, tonInstance: TonInstance, keychain: TonKeychain) -> Signal<[String], WalletRestoreWordsError> { - return getServerWalletSalt(network: network) - |> mapError { _ -> WalletRestoreWordsError in - return .generic - } - |> mapToSignal { serverSalt in - return tonInstance.walletRestoreWords(walletInfo: walletInfo, keychain: keychain, serverSalt: serverSalt) - } +public func walletRestoreWords(tonInstance: TonInstance, publicKey: WalletPublicKey, decryptedSecret: Data, localPassword: Data) -> Signal<[String], WalletRestoreWordsError> { + return tonInstance.walletRestoreWords(publicKey: publicKey, decryptedSecret: decryptedSecret, localPassword: localPassword) } public struct WalletState: Codable, Equatable { @@ -842,11 +757,11 @@ public enum SendGramsFromWalletError { case network } -public func sendGramsFromWallet(network: Network, tonInstance: TonInstance, walletInfo: WalletInfo, decryptedSecret: Data, serverSalt: Data, toAddress: String, amount: Int64, textMessage: String, forceIfDestinationNotInitialized: Bool, timeout: Int32, randomId: Int64) -> Signal { +public func sendGramsFromWallet(network: Network, tonInstance: TonInstance, walletInfo: WalletInfo, decryptedSecret: Data, localPassword: Data, toAddress: String, amount: Int64, textMessage: String, forceIfDestinationNotInitialized: Bool, timeout: Int32, randomId: Int64) -> Signal { return walletAddress(publicKey: walletInfo.publicKey, tonInstance: tonInstance) |> castError(SendGramsFromWalletError.self) |> mapToSignal { fromAddress in - return tonInstance.sendGramsFromWallet(decryptedSecret: decryptedSecret, serverSalt: serverSalt, walletInfo: walletInfo, fromAddress: fromAddress, toAddress: toAddress, amount: amount, textMessage: textMessage, forceIfDestinationNotInitialized: forceIfDestinationNotInitialized, timeout: timeout, randomId: randomId) + return tonInstance.sendGramsFromWallet(decryptedSecret: decryptedSecret, localPassword: localPassword, walletInfo: walletInfo, fromAddress: fromAddress, toAddress: toAddress, amount: amount, textMessage: textMessage, forceIfDestinationNotInitialized: forceIfDestinationNotInitialized, timeout: timeout, randomId: randomId) } } diff --git a/submodules/WalletUI/Sources/WalletSettingsScreen.swift b/submodules/WalletUI/Sources/WalletSettingsScreen.swift index 8aa0c08c64..c243df64f8 100644 --- a/submodules/WalletUI/Sources/WalletSettingsScreen.swift +++ b/submodules/WalletUI/Sources/WalletSettingsScreen.swift @@ -104,10 +104,20 @@ public func walletSettingsController(context: AccountContext, tonContext: TonCon let presentationData = context.sharedContext.currentPresentationData.with { $0 } let controller = OverlayStatusController(theme: presentationData.theme, strings: presentationData.strings, type: .loading(cancelled: nil)) presentControllerImpl?(controller, nil) - let _ = (walletRestoreWords(network: context.account.network, walletInfo: walletInfo, tonInstance: tonContext.instance, keychain: tonContext.keychain) - |> deliverOnMainQueue).start(next: { [weak controller] wordList in - controller?.dismiss() - pushControllerImpl?(WalletWordDisplayScreen(context: context, tonContext: tonContext, walletInfo: walletInfo, wordList: wordList, mode: .export, walletCreatedPreloadState: nil)) + let _ = (tonContext.keychain.decrypt(walletInfo.encryptedSecret) + |> deliverOnMainQueue).start(next: { [weak controller] decryptedSecret in + let _ = (getServerWalletSalt(network: context.account.network) + |> deliverOnMainQueue).start(next: { serverSalt in + let _ = (walletRestoreWords(tonInstance: tonContext.instance, publicKey: walletInfo.publicKey, decryptedSecret: decryptedSecret, localPassword: serverSalt) + |> deliverOnMainQueue).start(next: { [weak controller] wordList in + controller?.dismiss() + pushControllerImpl?(WalletWordDisplayScreen(context: context, tonContext: tonContext, walletInfo: walletInfo, wordList: wordList, mode: .export, walletCreatedPreloadState: nil)) + }, error: { [weak controller] _ in + controller?.dismiss() + }) + }, error: { [weak controller] _ in + controller?.dismiss() + }) }, error: { [weak controller] _ in controller?.dismiss() }) diff --git a/submodules/WalletUI/Sources/WalletSplashScreen.swift b/submodules/WalletUI/Sources/WalletSplashScreen.swift index 7deb6f3b90..db8340a8ec 100644 --- a/submodules/WalletUI/Sources/WalletSplashScreen.swift +++ b/submodules/WalletUI/Sources/WalletSplashScreen.swift @@ -133,7 +133,7 @@ public final class WalletSplashScreen: ViewController { } private func sendGrams(walletInfo: WalletInfo, decryptedSecret: Data, address: String, amount: Int64, textMessage: String, forceIfDestinationNotInitialized: Bool, randomId: Int64, serverSalt: Data) { - let _ = (sendGramsFromWallet(network: self.context.account.network, tonInstance: self.tonContext.instance, walletInfo: walletInfo, decryptedSecret: decryptedSecret, serverSalt: serverSalt, toAddress: address, amount: amount, textMessage: textMessage, forceIfDestinationNotInitialized: forceIfDestinationNotInitialized, timeout: 0, randomId: randomId) + let _ = (sendGramsFromWallet(network: self.context.account.network, tonInstance: self.tonContext.instance, walletInfo: walletInfo, decryptedSecret: decryptedSecret, localPassword: serverSalt, toAddress: address, amount: amount, textMessage: textMessage, forceIfDestinationNotInitialized: forceIfDestinationNotInitialized, timeout: 0, randomId: randomId) |> deliverOnMainQueue).start(error: { [weak self] error in guard let strongSelf = self else { return @@ -213,15 +213,7 @@ public final class WalletSplashScreen: ViewController { switch strongSelf.mode { case .intro: let controller = OverlayStatusController(theme: strongSelf.presentationData.theme, strings: strongSelf.presentationData.strings, type: .loading(cancelled: nil)) - strongSelf.present(controller, in: .window(.root)) - let _ = (createWallet(postbox: strongSelf.context.account.postbox, network: strongSelf.context.account.network, tonInstance: strongSelf.tonContext.instance, keychain: strongSelf.tonContext.keychain) - |> deliverOnMainQueue).start(next: { walletInfo, wordList in - guard let strongSelf = self else { - return - } - controller.dismiss() - (strongSelf.navigationController as? NavigationController)?.replaceController(strongSelf, with: WalletSplashScreen(context: strongSelf.context, tonContext: strongSelf.tonContext, mode: .created(walletInfo, wordList), walletCreatedPreloadState: nil), animated: true) - }, error: { _ in + let displayError: () -> Void = { guard let strongSelf = self else { return } @@ -230,6 +222,22 @@ public final class WalletSplashScreen: ViewController { TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: { }) ], actionLayout: .vertical), in: .window(.root)) + } + strongSelf.present(controller, in: .window(.root)) + let _ = (getServerWalletSalt(network: strongSelf.context.account.network) + |> deliverOnMainQueue).start(next: { serverSalt in + let _ = (createWallet(postbox: strongSelf.context.account.postbox, tonInstance: strongSelf.tonContext.instance, keychain: strongSelf.tonContext.keychain, localPassword: serverSalt) + |> deliverOnMainQueue).start(next: { walletInfo, wordList in + guard let strongSelf = self else { + return + } + controller.dismiss() + (strongSelf.navigationController as? NavigationController)?.replaceController(strongSelf, with: WalletSplashScreen(context: strongSelf.context, tonContext: strongSelf.tonContext, mode: .created(walletInfo, wordList), walletCreatedPreloadState: nil), animated: true) + }, error: { _ in + displayError() + }) + }, error: { _ in + displayError() }) case let .created(walletInfo, wordList): if let wordList = wordList { @@ -237,20 +245,50 @@ public final class WalletSplashScreen: ViewController { } else { let controller = OverlayStatusController(theme: strongSelf.presentationData.theme, strings: strongSelf.presentationData.strings, type: .loading(cancelled: nil)) strongSelf.present(controller, in: .window(.root)) - let _ = (walletRestoreWords(network: strongSelf.context.account.network, walletInfo: walletInfo, tonInstance: strongSelf.tonContext.instance, keychain: strongSelf.tonContext.keychain) - |> deliverOnMainQueue).start(next: { wordList in - guard let strongSelf = self else { - return - } - strongSelf.mode = .created(walletInfo, wordList) - controller.dismiss() - strongSelf.push(WalletWordDisplayScreen(context: strongSelf.context, tonContext: strongSelf.tonContext, walletInfo: walletInfo, wordList: wordList, mode: .check, walletCreatedPreloadState: strongSelf.walletCreatedPreloadState)) - }, error: { error in - guard let strongSelf = self else { - return - } - controller.dismiss() - if case let .secretDecryptionFailed(.cancelled) = error { + + let context = strongSelf.context + let tonContext = strongSelf.tonContext + let _ = (strongSelf.tonContext.keychain.decrypt(walletInfo.encryptedSecret) + |> deliverOnMainQueue).start(next: { [weak controller] decryptedSecret in + let _ = (getServerWalletSalt(network: context.account.network) + |> deliverOnMainQueue).start(next: { [weak controller] serverSalt in + let _ = (walletRestoreWords(tonInstance: tonContext.instance, publicKey: walletInfo.publicKey, decryptedSecret: decryptedSecret, localPassword: serverSalt) + |> deliverOnMainQueue).start(next: { wordList in + controller?.dismiss() + + guard let strongSelf = self else { + return + } + + strongSelf.mode = .created(walletInfo, wordList) + strongSelf.push(WalletWordDisplayScreen(context: strongSelf.context, tonContext: strongSelf.tonContext, walletInfo: walletInfo, wordList: wordList, mode: .check, walletCreatedPreloadState: strongSelf.walletCreatedPreloadState)) + }, error: { _ in + guard let strongSelf = self else { + return + } + + controller?.dismiss() + + strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: strongSelf.presentationData.theme), title: strongSelf.presentationData.strings.Wallet_Created_ExportErrorTitle, text: strongSelf.presentationData.strings.Wallet_Created_ExportErrorText, actions: [ + TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: { + }) + ], actionLayout: .vertical), in: .window(.root)) + }) + }, error: { [weak controller] _ in + guard let strongSelf = self else { + return + } + + controller?.dismiss() + + strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: strongSelf.presentationData.theme), title: strongSelf.presentationData.strings.Wallet_Created_ExportErrorTitle, text: strongSelf.presentationData.strings.Wallet_Created_ExportErrorText, actions: [ + TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: { + }) + ], actionLayout: .vertical), in: .window(.root)) + }) + }, error: { [weak controller] error in + controller?.dismiss() + if case .cancelled = error { } else { strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: strongSelf.presentationData.theme), title: strongSelf.presentationData.strings.Wallet_Created_ExportErrorTitle, text: strongSelf.presentationData.strings.Wallet_Created_ExportErrorText, actions: [ TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: { diff --git a/submodules/WalletUI/Sources/WalletWordCheckScreen.swift b/submodules/WalletUI/Sources/WalletWordCheckScreen.swift index aa2d08f272..def201ec20 100644 --- a/submodules/WalletUI/Sources/WalletWordCheckScreen.swift +++ b/submodules/WalletUI/Sources/WalletWordCheckScreen.swift @@ -2178,30 +2178,8 @@ public final class WalletWordCheckScreen: ViewController { ], actionLayout: .vertical), in: .window(.root)) return } - let _ = (importWallet(postbox: strongSelf.context.account.postbox, network: strongSelf.context.account.network, tonInstance: strongSelf.tonContext.instance, keychain: strongSelf.tonContext.keychain, wordList: enteredWords) - |> deliverOnMainQueue).start(next: { walletInfo in - guard let strongSelf = self else { - return - } - if let navigationController = strongSelf.navigationController as? NavigationController { - var controllers = navigationController.viewControllers - controllers = controllers.filter { controller in - if controller is WalletSplashScreen { - return false - } - if controller is WalletWordDisplayScreen { - return false - } - if controller is WalletWordCheckScreen { - return false - } - return true - } - controllers.append(WalletSplashScreen(context: strongSelf.context, tonContext: strongSelf.tonContext, mode: .success(walletInfo), walletCreatedPreloadState: strongSelf.walletCreatedPreloadState)) - strongSelf.view.endEditing(true) - navigationController.setViewControllers(controllers, animated: true) - } - }, error: { error in + + let displayError: () -> Void = { guard let strongSelf = self else { return } @@ -2210,6 +2188,38 @@ public final class WalletWordCheckScreen: ViewController { TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: { }) ], actionLayout: .vertical), in: .window(.root)) + } + + let _ = (getServerWalletSalt(network: strongSelf.context.account.network) + |> deliverOnMainQueue).start(next: { serverSalt in + let _ = (importWallet(postbox: strongSelf.context.account.postbox, tonInstance: strongSelf.tonContext.instance, keychain: strongSelf.tonContext.keychain, wordList: enteredWords, localPassword: serverSalt) + |> deliverOnMainQueue).start(next: { walletInfo in + guard let strongSelf = self else { + return + } + if let navigationController = strongSelf.navigationController as? NavigationController { + var controllers = navigationController.viewControllers + controllers = controllers.filter { controller in + if controller is WalletSplashScreen { + return false + } + if controller is WalletWordDisplayScreen { + return false + } + if controller is WalletWordCheckScreen { + return false + } + return true + } + controllers.append(WalletSplashScreen(context: strongSelf.context, tonContext: strongSelf.tonContext, mode: .success(walletInfo), walletCreatedPreloadState: strongSelf.walletCreatedPreloadState)) + strongSelf.view.endEditing(true) + navigationController.setViewControllers(controllers, animated: true) + } + }, error: { error in + displayError() + }) + }, error: { _ in + displayError() }) } }, secondaryAction: { [weak self] in